JSFiddle - React, Tailwind, and code Playground

by lid0

HTML

<div id="app">
  <p>
    app form state: {{form}}

    <div>
      Hello {{form.first}} {{form.last}}
    </div>
  </p>


  <span class="title">Enter First and last name</span>

  <template v-for="f,k in form">
    <div>
      <div class="field-title">
        {{k}}
      </div>
      <field class="editable" v-model="form[k]" :key=k></field>
    </div>
  </template>


</div>

CSS

.editable {
  border: 5px dashed cadetblue;
  width: 200px;
  max-width: 400px;
  color: red;
  font-size: 28px;
  padding: 4px;
  display: inline-block;
}

.editable:hover {
  background: #cfcfcf
}

.editable input {
  font-size: 28px;
  width: 180px;
}

.title {
  font-size: 25px;

  background: #4abf5c;
  color: white;
  padding: 5px;
  display: inherit;
}

.field-title {
  font-size: 31px;
  display: inline-block;
  border: 5px solid #b9b9b9;
  padding: 5px 20px 5px 20px;
}

JavaScript

// lidlanca 2021

/**
 <field> 
    |_  view   props: val
    |_  edit   props: val

by default a field is rendered in view mode.
when clicked, will switch to edit mode. 

in edit mode a user can edit the value, then save or cancel.
on save, the new value will be emitted

*/


Vue.component('view1', {
  props: ['val'],
  template: `<h1   @click="$emit('click')">{{val}}</h1>`
});

Vue.component('edit1', {
  emits: ["save"],
  props: ['val'],
  template: `<h1>
  <input v-model="value"></input>
  <button @click="$emit('cancel')">cancel</button>
  <button @click="$emit('input',edit)">save</button>
  </h1>`,
  data() {
    return {
      edit: ""
    }
  },
  computed: {
    value: {
      get() {
        this.edit = this.val
        return this.val
      },
      set(v) {
        this.edit = v
      }
    }
  }
});


Vue.component('field', {
  props: ["value"],
  template: `
 
  <component
     v-on:cancel="cancel"
     @input="save"
     @click="toggle()" 
     :val="value"
     v-bind:is="current"></component>

`,
  data() {
    return {
      current: "view1"
    }
  },
  methods: {
    toggle() {
      this.current = this.current == "view1" ? "edit1" : "view1"
    },
    cancel() {
      this.toggle()
    },
    // onSave
    save(a) {
      //this.value = a
      this.toggle();
      this.$emit('input', a) // emit input  to update model value.
    }
  }
});

new Vue({
  el: "#app",
  data: {
    form: {
      first: "cudi",
      last: "fredu"
    }
  }
})