My dynamical form in Vue does not work

Asked

Viewed 269 times

0

I am making a form, in which it is necessary that I allow to add more fields. I have already managed to do this in other fields of this same form. However, everything I’ve tried for one last field goes wrong.

The div I want to add dynamically:

        <div class="field opcao" v-for="(op, x) in body.fields.options" :key="x">
            <label class="label">Opção de resposta para o campo anterior</label>
            <input type="text" class="input" placeholder="Ex.: Couro" v-model="body.fields[index].options[x]">
        </div>
        <button type="button" class="button btn-secondary" @click="addOption(index)">Adicionar opção de resposta para o campo</button>

THE JS:

addOption(){
            this.body.fields[index].options.push('');
        }

and my JSON is like this:inserir a descrição da imagem aqui

My entire form is like this and for the other fields is working normally.

   <form class="central">
                    <div class="field subcategoria cartao" v-for="(t, index) in body.type" :key="index" >
                        <label class="label">Nome da Subcategoria {{index}} *</label>
                        <input type="text" class="input" placeholder="Ex.:Casaco" required v-model="body.type[index]">
                        <small>Os campos da subcategoria ajudarão a definir melhor as características do objeto, para que suas chances de ser encontrado sejam maiores.</small>
                        <div class="field central">
                            <form class="central central">
                                <div class="campo central">
                                    <div class="field">
                                        <label class="label">Nome do campo *</label>
                                        <input type="text" class="input" placeholder="Ex.: Material" required v-model="body.fields[index].name">
                                    </div>
                                    <div class="field opcao" v-for="(op, x) in body.fields.options" :key="x">
                                        <label class="label">Opção de resposta para o campo anterior</label>
                                        <input type="text" class="input" placeholder="Ex.: Couro" v-model="body.fields[index].options[x]">
                                    </div>
                                    <button type="button" class="button btn-secondary" @click="addOption(index)">Adicionar opção de resposta para o campo</button>                  
                                </div>
                                <button type="button" class="button btn-secondary">Adicionar campo</button>
                            </form>
                        </div>          
                    </div>
                    <button type="button" class="button btn-secondary" @click="addNewSubcategorie()">Adicionar subcategoria</button>
                    <button type="button" @click="imprimir()">console</button>                      
                </form>
  • I just discovered by the console, that it is adding the positions to the options array. But the field does not appear on the screen

1 answer

1


The detection of changes in Objects and Arrays in Vue.js is limited to the creation moment of the component instance. Vue.js cannot recognize the addition or removal of new properties in objects, since Javascript does not have a tool or API that allows the customization of these behaviors (see the Vue.js documentation for limitations of Objects and limitations of Arrays).

Since Javascript does not allow monitoring attribute additions/removals to objects natively, the output is to use Vue.js to do additions/removals, so the framework itself will take care of maintaining the reactivity of the object for you.

To request Vue to change this object while maintaining reactivity, you must use the functions Vue.set() to add a new property and Vue.delete() to remove. This way Vue will be aware of the changes you made to the object.

Example:

new Vue({
    el: '#app',
    data: () => ({
        // Objeto exemplo
        propriedades: {
            prop_1: "Propriedade 1",
            prop_2: "Propriedade 2"
        },
        // Um contador simples só para criar as novas propriedades
        qtd_props: 2,
    }),
    methods: {
        add_prop_errado() {
            // Incrementa o contador
            this.qtd_props += 1
            // Prepara os dados (para o código a seguir ficar mais claro)
            let prop = "prop_" + this.qtd_props
            let valor = "Propriedade " + this.qtd_props
            
            // Operação que o Vue não consegue reconhecer
            this.propriedades[prop] = valor
        },
        add_prop_certo() {
            // Incrementa o contador
            this.qtd_props += 1
            // Prepara os dados (para o código a seguir ficar mais claro)
            let prop = "prop_" + this.qtd_props
            let valor = "Propriedade " + this.qtd_props
            
            // Encarrega o Vue de atribuir a nova propriedade
            Vue.set(this.propriedades, prop, valor)
        }
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
    <button @click="add_prop_errado">Adicionar (errado)</button>
    <button @click="add_prop_certo">Adicionar (certo)</button>
    <ol>
        <li v-for="(valor, prop) in this.propriedades" :key="prop">
            <strong>{{ prop }}</strong>: {{ valor }}
        </li>
    </ol>
</div>


It is worth remembering that the same can be used for Arrays. Example:

let array = [1, 2, 0, 4, 5]

// Maneira INCORRETA
array[2] = 3

// Maneira CORRETA
Vue.set(array, 2, 3)
// ou
this.$set(array, 2, 3)

Completion

Now it’s up to you to analyze your code to find out where you are created or by removing a property in a way that Vue doesn’t recognize.

An option would also be to replace the entire object, so you are modifying an attribute that is already reactive. But it’s not a performance option, you’d need to analyze the performance impact on your project.

Example:

new Vue({
    el: '#app',
    data: () => ({
        propriedades: {
            prop_1: "Propriedade 1",
            prop_2: "Propriedade 2"
        },
        qtd_props: 2,
    }),
    methods: {
        add_prop() {
            this.qtd_props += 1
            let prop = "prop_" + this.qtd_props
            let valor = "Propriedade " + this.qtd_props
            // Cria um cópia de `propriedades`
            let novo_propriedades = {...this.propriedades}
            // Modifica a cópia
            novo_propriedades[prop] = valor
            
            // Substitui o objeto reativo inteiro pela cópia modificada
            this.propriedades = novo_propriedades
        },
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
    <button @click="add_prop">Adicionar</button>
    <ol>
        <li v-for="(valor, prop) in this.propriedades" :key="prop">
            <strong>{{ prop }}</strong>: {{ valor }}
        </li>
    </ol>
</div>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.