3

My requirement is to make nested data in my form and each of this data has ability to add more rows or delete them. I have done such thing with JavaScript before but with VueJs it's my first attempt so I kind of need push :)

Logic

one

  1. Parent data has select option which will let user to select what type of input they need and based on that selection it append the input. (RED)
  2. My parent data can be added or removed so i can have several parent and each of them several child at the same time (BLUE)
  3. My child data can be added or removed (GREEN)

Code

Here is my first static html (no script has written for it yet)

Ps: all parts are commented.

<el-form-item label="Variation Name">
    <el-col :span="12">

        // parent
        <el-input placeholder="Please input your variation name" v-model="form.variationParent" class="input-with-select">
            // select type of child's input
            <el-select v-model="form.variationParent" slot="prepend" placeholder="Select">
                <el-option label="Text" value="1"></el-option>
                <el-option label="Text Area" value="2"></el-option>
                <el-option label="Boolean" value="3"></el-option>
            </el-select>
            <el-button slot="append" type="success" icon="el-icon-plus"></el-button> //add parent
            <el-button slot="append" type="danger" icon="el-icon-delete"></el-button> // delete parent
        </el-input>

    </el-col>

    <el-col class="line text-center" :span="3">Variation Value(s)</el-col>
    <el-col :span="9">

        // child's
        <el-input v-model="form.variationChilds" placeholder="Please input your variation value" class="input-with-select">
            <el-button slot="append" type="success" icon="el-icon-plus"></el-button> //add child
            <el-button slot="append" type="danger" icon="el-icon-delete"></el-button> // delete child
        </el-input>

    </el-col>
</el-form-item>

Any kind of idea and sample codes are appreciated.

Update

I have manage to add and remove parent part with this code:

<el-form-item v-for="(index, k) in variationParents" :key="k" label="Variation Name">
    <el-col :span="12">

        <!-- parent -->
        <el-input placeholder="Please input your variation name" v-model="form.variationParent" class="input-with-select">
            <el-select v-model="form.variationParent" slot="prepend" placeholder="Select">
                <el-option label="Text" value="input"></el-option>
                <el-option label="Text Area" value="textarea"></el-option>
                <el-option label="Boolean" value="boolean"></el-option>
            </el-select>
            <el-button slot="append" @click="add(k)" type="success" icon="el-icon-plus"></el-button>
            <el-button slot="append" @click="remove(k)" v-show="k || ( !k == variationParents.lenghth > 1)" type="danger" icon="el-icon-delete"></el-button>
        </el-input>

    </el-col>

    <el-col class="line text-center" :span="3">Variation Value(s)</el-col>
    <el-col :span="9">

        <!-- child's -->
        <el-input v-model="form.variationChilds" placeholder="Please input your variation value" class="input-with-select">
            <el-button slot="append" type="success" icon="el-icon-plus"></el-button>
            <el-button slot="append" type="danger" icon="el-icon-delete"></el-button>
        </el-input>

    </el-col>
</el-form-item>

data() {
    return {
        variationParents: [
            {
                name: '',
                type: ''
            }
        ],
    }
},
methods: {
    add(index){
        this.variationParents.push({name: '', type: ''});
    },
    remove(index){
        this.variationParents.splice(index, 1);
    },
}

and here is the result + issue

three

As you see i have new rows of parents and add / remove buttons working but my inputs are all getting same value, meaning if i set first input to something all of them will get same value.

They need to each one have different value and be send to back-end as array.

4
  • @YomS. regarding to this question all i have is the html part that i included to the question but if you need i can make jsfiddle, yet all the code i have is this :) Commented Jan 20, 2020 at 9:53
  • here you go jsfiddle.net/robertnicjoo/c2d1xzeL/1 Commented Jan 20, 2020 at 9:56
  • Well, this fiddle looks completely different and irrelevant to your template in question. Please post some data or scripts you have tried so far. Commented Jan 20, 2020 at 10:07
  • The reason you're getting shared values is because you are doing v-model on different object (form) instead of what's being looped in the v-for. Commented Jan 20, 2020 at 14:26

1 Answer 1

1

I couldn't actually run your jsfiddle, but looking at your code I think you're pretty close, only, as I said in the comment, you need to bind these input/form elements on the individual variationParents being looped with v-for.

Here's some quick example that shows how to sync those parent values across the components. I couldn't add everything for you though.

Also, as you scale, you might want to consider using Vuex for better management of states.

const variationNames = ['Text', 'Text Area', 'Boolean'];

const VariationBar = Vue.extend({
  template: '#variation-bar',
  props: {
    name: {
      type: String,
      // This simply ensures that the `name` property 
      // be validated against the list, while binding;
      // https://vuejs.org/v2/guide/components-props.html#Prop-Validation
      validator: val => variationNames.includes(val)
    },
    values: {
      type: Array
    }
  },

  data: () => ({
    variationNames
  }),

  computed: {
    // Read more here on how computed setter works:
    // https://vuejs.org/v2/guide/computed.html#Computed-Setter
    inputName: {
      get() {
        return this.name;
      },
      set(val) {
        // When setter gets invoked, emit the new value
        // and notify the parent that it needs to "sync" it.
        // This works hand-in-hand with the `.sync` modifier
        // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
        this.$emit('update:name', val);
      }
    }
  },
  
  methods: {
    addValue() {
      // Add your default item/preset here
      this.values.push({
        text: ''
      })
    },
    removeValue(index) {
      this.values.splice(index, 1);
    }
  }
})

new Vue({
  el: '#app',

  data: vm => ({
    variations: [{
      name: 'Boolean',
      values: [
        { text: 'Core i3' },
        { text: 'Core i5' }
      ]
    }]
  }),

  methods: {
    addVariation() {
      this.variations.push({
        name: 'Text',
        values: [
          { text: 'Core i3' }
        ]
      });
    },
  },

  components: {
    VariationBar
  }
})
.variation {
  display: flex;
  justify-content: space-between;
  margin-bottom: 2rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <variation-bar v-for="item of variations" :key="item.name" :name.sync="item.name" :values="item.values" @variation:add="addVariation">
  </variation-bar>
  
  <pre>{{variations}}</pre>
</div>

<template id="variation-bar">
  <div class="variation">
    <div class="variation__col">
      <label>Variation Name</label>
      <select v-model="inputName">
        <option
          v-for="name of variationNames" :key="name"
          :value="name"
          v-text="name">
        </option>
      </select>

      <div class="variation__btn-group">
        <button @click="$emit('variation:add')">add</button>
        <button @click="$emit('variation:remove')">remove</button>
      </div>
    </div>

    <div class="variation__col">
      <label>Variation values(s)</label>

      <div
        v-for="(val, index) of values" :key="`${val.text}-${index}`"
        class="variation__value">
        <input type="text" v-model.lazy="val.text" />

        <div class="variation__btn-group">
          <button @click="addValue">add</button>
          <button @click="removeValue(index)">remove</button>
        </div>
      </div>
    </div>
  </div>
</template>

Sign up to request clarification or add additional context in comments.

12 Comments

thanks for answer man, would you mind to comment each part so i can understand where to place them or what each one does? for instance right now anywhere i place those const it's breaking some other part. :/
Do you mean the variationNames const in my example? Where and how did you use it? That was actually for prop checking only.
I added some inline comments on the example. I might actually be able to help you with the real code (your app in question) if you could just get the jsfiddle to work, and the issue reproducible. As it stands, I couldn't even run it. Too many missing info on the fiddle. But that's up to you.
thanks, how if i give you my component? would that help you? i just send you full component?
this is my full component here collabedit.com/ywheq and i commented issue part so you can find it easily
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.