0

Picture of interlinkage between forms and fields.

I have searched this forum for an answer, as I suspect this has been asked before, but I haven't managed to find an answer.

I just picked up using Vue and Laravel, where I am building a form. Right now I am building a test to learn how to do it before I add complexity. The right form consists of 1 select-box and 3 text fields. My requirements for the form are:

  1. One button to duplicate the entire form.
  2. One button in each form (also ones that are duplicated), which adds the 3 input-text fields in the form, by duplication the fields in the div called "registration_grid". One form may require the text-fields to be duplicated 10 times, others only 1 or 2...

I realize the code is a bit messy in its context, but it is put together by various pieces I found in tutorials along the way.

    var app = new Vue({
    el: '.container', 
    data: {
        workouts: [ 
            {
            workout_unit: '', 
            workout_weight: '',
            workout_comment: ''
            }
        ]
        },

    methods: {
        addNewEmployeeForm () {
            this.workouts.push({
                workout_unit: '', 
                workout_weight: '',
                workout_comment: ''
            })
        },
        deleteEmployeeForm (index) {
            this.workouts.splice(index, 1)
            }
        }
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div class="container">
  <button class="btn btn-primary" type="button" name="button" @click="addNewEmployeeForm">Add form fields</button>
  <div class="card" v-for="(workout, index) in workouts">
    <div class="card-body">
      <i class="far fa-trash-alt float-right" @click="deleteEmployeeForm(index)"></i>
      <h4 class="card-title">Test form - @{{index}}</h4>
      <div class="employee-form">
        <select class="form-select form-select-sm" aria-label=".form-select-sm example">
          <option selected>Open this select menu</option>
          <option value="1">One</option>
          <option value="2">Two</option>
          <option value="3">Three</option>
        </select>
        <div class="registration_grid">
          <input type="text" class="form-control" name="unit" placeholder="unit" v-model="workout.workout_unit">
          <input type="text" class="form-control" name="weight" placeholder="weight" v-model="workout.workout_weight">
          <input type="text" class="form-control" name="comment" placeholder="comment" v-model="workout.workout_comment">
        </div>
      </div>
    </div>
  </div>

Can this be done by Vue, and if so how?

2
  • So you need a separate form for each item in the workouts array, is that right? When you duplicate the text fields in an individual form, what properties should the new fields correspond to? E.g. should they become workout_unit_1, workout_unit_2 etc. Commented Feb 15, 2021 at 11:49
  • Hi Hannah, Yes I think that would be the way to go. My expectation is that I would somehow end up with a multidimensional array for each form that is created, which I will then manage through PHP. I don't know if that is the case or maybe I will end up with one big multidimensional array covering all the forms in one. I am still to new in Vue to have a clear idea of what is possible. However, if I can end up having a unique names for each input field in each form and the naming convention you are listing, then I can manage that as will through a loop. I have updated question with a drawing Commented Feb 15, 2021 at 13:12

1 Answer 1

0

You need to access the form data with workouts[index].unit for the v-model instead of workout.workout_unit

var app = new Vue({
  el: '.container', 
  data: {
    workouts: [ 
      {
        unit: '', 
        weight: '',
        comment: ''
      }
    ]
  },

  methods: {
    addRow () {
      this.workouts.push({
        unit: '', 
        weight: '',
        comment: ''
      })
    },
    deleteRow (index) {
      this.workouts.splice(index, 1)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>

<div class="container">
  <button class="btn btn-primary" type="button" name="button" @click="addRow">Add form fields</button>
  
  <div class="card" v-for="(workout, index) in workouts">
    <div class="card-body">
      <i class="far fa-trash-alt float-right" @click="deleteRow(index)"></i>
      <h4 class="card-title">Test form - {{index}}</h4>
      <div class="employee-form">
        <select class="form-select form-select-sm" aria-label=".form-select-sm example">
          <option selected>Open this select menu</option>
          <option value="1">One</option>
          <option value="2">Two</option>
          <option value="3">Three</option>
        </select>
        <div class="registration_grid">
          <input type="text" class="form-control" name="unit" placeholder="unit" v-model="workouts[index].unit">
          <input type="text" class="form-control" name="weight" placeholder="weight" v-model="workouts[index].weight">
          <input type="text" class="form-control" name="comment" placeholder="comment" v-model="workouts[index].comment">
        </div>
      </div>
    </div>
  </div>
</div>

Modified example to only duplicate the input fields

var app = new Vue({
  el: '.container', 
  data: {
    workouts: [ 
      {
        unit: '', 
        weight: '',
        comment: ''
      }
    ]
  },

  methods: {
    addRow () {
      this.workouts.push({
        unit: '', 
        weight: '',
        comment: ''
      })
    },
    deleteRow (index) {
      this.workouts.splice(index, 1)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>

<div class="container">
  <button class="btn btn-primary" type="button" name="button" @click="addRow">Add form fields</button>
  
  <div class="card">
    <div class="card-body">
      <h4 class="card-title">Test form</h4>
      <div class="employee-form">
        <select class="form-select form-select-sm" aria-label=".form-select-sm example">
          <option selected>Open this select menu</option>
          <option value="1">One</option>
          <option value="2">Two</option>
          <option value="3">Three</option>
        </select>
        <div class="registration_grid" v-for="(workout, index) in workouts">
          <input type="text" class="form-control" name="unit" placeholder="unit" v-model="workouts[index].unit">
          <input type="text" class="form-control" name="weight" placeholder="weight" v-model="workouts[index].weight">
          <input type="text" class="form-control" name="comment" placeholder="comment" v-model="workouts[index].comment">
          <i class="far fa-trash-alt float-right" @click="deleteRow(index)"></i>
        </div>
      </div>
    </div>
  </div>
</div>

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

3 Comments

Hi, This makes a lot of sense, but where do I add the index in the addRow function? As it stands now, it is a copy of my addEmployeeForm, which means it will duplicate the entire form including a dropdown (left side of the picture on my original question). What I want is to only add 3 input fields in the selected form, but then it must be pointed to the right index (left side of picture in my original question). Also, why is it important that I change the syntax in my v-model?
If you want only these 3 fields to be duplicated you have to modify the v-for loop to only hold the 3 inputs not the card-title and select. But the deleteRow also must be inside the loop, because it deletes rows by the index. Take a look at the modified example. I only renamed the array keys to make it shorter
Hi Julian, Thanks!! I ended combining your input with another question I found (stackoverflow.com/questions/52605867/…)

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.