1

I am learning vue.js. I am trying to build a form dynamically from data. The form is condition based. If I select some field from the select field the specific content related to that option has to show.

Here is the data

If the model of "id: 2" object is "germany", the show from "id: 3" has to become true and the show from 'id:4" and "id: 5" has to become false.

Similarly, If the model of "id: 2" object is "us", the show from the id: 4 has to become true and the show from "id:3" and "id: 5" has to become false.

  data(){
    return{
      fields: [
        {
          id: 1,
          type: "text",
          placeholder: "Name",
          model: "",
          show: true
        },
        {
          id: 2,
          type: "select",
          placeholder: "Select",
          model: "",
          show: true,
          options: [
            {value: "germany", text: "Gemany", id: "germany"},
            {value: "us", text: "United States", id: "us"},
            {value: "uk", text: "United Kingdom", id: "uk"}
          ],
          events: "onChange"
        },
        {
          id: 3,
          type: "paragraph",
          text: "Berlin",
          show: false
        },
        {
          id: 4,
          type: "paragraph",
          text: "New York",
          show: false
        },
        {
          id: 5,
          type: "paragraph",
          text: "London",
          show: false
        }
      ]
    }
  }

Here is template

<template>
  <div>
    <div class="" v-for="field in fields" :key="field.id">
      <input :type="field.type" :placeholder="field.placeholder" v-model="field.model" :id="field.id" v-if="field.type == 'text' && field.show">
      <select v-model="field.model" :id="field.id" v-if="field.type == 'select' && field.show" @change="onChange(field.id)">
        <option v-for="option in field.options" :key="option.id" :value="option.value" :id="option.id">{{option.text}}</option>
      </select>
      <p v-if="field.type == 'paragraph' && field.show" :id="field.id">{{field.text}}</p>
    </div>
    <button @click="submit">Submit</button>
  </div>
</template>

methods

onChange(e){
      console.log(e)
    }

How can I achieve this? Thank you.

5
  • What is stored in fields is not JSON. It it is just a regular object. JSON is a string. Commented Sep 5, 2018 at 10:06
  • In the onChange event you can say: this.fields.filter(field => field.id === 3) .show = this.fields.filter(field => field.id === id).model === 'germany' and follow a similar pattern Commented Sep 5, 2018 at 10:38
  • 1
    You're missing a crucial link: there is no mapping between the cities and countries. How are you going to infer that relationship? Commented Sep 5, 2018 at 11:16
  • How to link between the objects. My knowledge is very basic. Commented Sep 5, 2018 at 12:03
  • @Terry how to map between cities and countries? Help Commented Sep 6, 2018 at 2:36

2 Answers 2

1

v-model on select does the job to find the selected value.

First, you can add an new property (option_id for example) to create a link between your option field id and your paragraph field option_id.
Then add a selectedOptionId data used for v-model to reach the right selected field.

You can now put this selected field out of the v-for loop and remove the show and model properties:

new Vue({
  el: "#app",
  data(){
    return{
      selectedOptionId: '',
      fields: [
        {
          id: 1,
          type: "text",
          placeholder: "Name",
          model: "",
        },
        {
          id: 2,
          type: "select",
          placeholder: "Select",
          options: [
            {value: "germany", text: "Gemany", id: "germany"},
            {value: "us", text: "United States", id: "us"},
            {value: "uk", text: "United Kingdom", id: "uk"}
          ]
        },
        {
          id: 3,
          option_id: "germany",
          type: "paragraph",
          text: "Berlin",
        },
        {
          id: 4,
          option_id: "us",
          type: "paragraph",
          text: "New York",
        },
        {
          id: 5,
          option_id: "uk",
          type: "paragraph",
          text: "London",
        }
      ]
    }
  },
  computed: {
    selectedField(){
      return this.fields.find(field =>  field.option_id == this.selectedOptionId)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
    <div v-for="field in fields" :key="field.id">
      <input :type="field.type" :placeholder="field.placeholder" v-model="field.model" :id="field.id" v-if="field.type == 'text'">
      <select v-model="selectedOptionId" :id="field.id" v-if="field.type == 'select'">
        <option v-for="option in field.options" :key="option.id" :value="option.id" :id="option.id">{{option.text}}</option>
      </select>
    </div>
    <p v-if="selectedField" :id="selectedField.id">{{selectedField.text}}</p>
</div>

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

3 Comments

what if we have multiple selects?
@KiranVilla you can use multiple on select. Just change the v-model type to array and the computed property: fiddle example here
My intention is to build a form using several objects which contains several select types. There may be several selects in the form (for ex. one select for country, other select for state, etc) if I select a specific option from the countries, the result has to show below that select field similarly for state also. Right now in the fiddle example it is showing out side loop. Hope you understand my problem.
0

This could be a solution: in your data you could add a variable idToShowMain, which is an array of id you want to show. You will initialize it with the default visualization:

idToShowMain: [ 1,2 ],

Then in your options you will add a property for each item with the array related to that option. When the value changes you will replace the main array with the one selected.

options: [
    {value: "germany", text: "Gemany", id: "germany", idToShow: [ 1,2,3 ] },
    {value: "us", text: "United States", id: "us", idToShow: [ 1,2,4 ] },
    {value: "uk", text: "United Kingdom", id: "uk", idToShow: [ 1,2 ] }
],

At the end you will change your template in this way:

<div class="" v-for="field in fields" :key="field.id" v-if="idToShowMain.includes(field.id)">

In this way you could remove the show property from each field.

Hope this helps you.

1 Comment

I did the same. But how to listen particular idToShow in onChage() event in the select tag i.e, @change="onChange(....)"

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.