javascript - aktualizovaná vlastnosť vo Vue.js sa nezmení v detskej komponente


Mám komponent dieťa, ktorý je HTML vstupným prvkom. Vyzerá to takto:

<label-input inputId="formProductId"
             inputType="number"
             inputName="productId"
             :inputEnabled="filters.productId.options"
             :label="translations['product_id']"
             :placeholder="translations['product_id']"
             :data="filters.productId.value"
/>

Súbor LabelInput.vue:

<template>
    <div class="form-element">
        <label :for="inputId" :class="['form-element-title', { 'js-focused': focused }]">{{ label }}</label>
        <input @input="updateValue($event.target.value)" :type="inputType" :id="inputId" :name="inputEnabled ? inputName : false" v-model="inputData" :placeholder="placeholder" @focus="focused = true" @blur="focused = false">
    </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class LabelInput extends Vue {
    @Prop({ default: () => '' }) inputId!: string
    @Prop({ default: () => '' }) inputType!: string
    @Prop({ default: () => '' }) inputName!: string
    @Prop({ default: () => '' }) label!: string
    @Prop({ default: () => '' }) placeholder!: string
    @Prop({ default: () => {} }) data!: []
    @Prop({ default: () => true }) inputEnabled!: string

    private inputData = this.data
    private focused = false

    updateValue (value: string) {
        this.$root.$emit('input', {'inputName' : this.inputName, 'inputValue' : value});
    }
}

Takže model je odoslaný prostredníctvom filters.productId.value ako dáta a potom zmenený na lokálnu premennú inputData.

Teraz, ak zmením vstupnú hodnotu, použijem funkciu updateValue, ktorá vysiela názov vstupu a jeho hodnotu späť do nadradeného komponentu, ktorý aktualizuje pôvodnú hodnotu filters.productId.value. Toto funguje dobre.

Teraz je problém v tom, že mám vo svojej rodičovskej komponente funkciu, ktorá resetuje hodnotu filters.productId.value späť na null. Vyzerá to takto:

clearFilters() {
    for (const [key, value] of Object.entries(this.filters)) {
        this.filters[key].value = null;
    }
}

A teraz sa dáta v mojej detskej komponente LabelInput nemenia, aj keď je filters.productId.value teraz null. Ako môžem aktualizovať detskú komponentu?

Odpoveď č. 1

Ešte som nepracoval s Vue ako s komponentom triedy, ale zdá sa, že problém je v nastavení vlastnosti na atribút v triede.

private inputData = this.data

Vue počúva zmeny vlastností (prop), ale dáta (data) neposlúchajú zmeny odkazov, takže vlastnosť sa zmenila, ale inputData nie, pretože Vue pre ňu nenastavuje poslucháčov.

Pracujúc bez tried, keď chcem robiť niečo podobné ako ty, používam vlastnosti computed. Pozri si dokumentáciu, aby si videl, ako je to implementované.

Používanie vypočítanej vlastnosti.

get inputData() {
  return this.data;
}

Verím, že to bude fungovať tak, ako očakávaš.

Aby sme lepšie vizualizovali to, čo hovoríme v komentároch, tu je, ako by mal kód vyzerať bez v-model.

vstup :

<input :value="inputData" @input="updateValue($event.target.value)" :type="inputType" :id="inputId" :name="inputEnabled ? inputName : false" :placeholder="placeholder" @focus="focused = true" @blur="focused = false">

Getter :

get inputData() {
  // you can change your prop here and return a new value. 
  // A lower or upper case, for example. Just don't change the prop, only use it.
  return this.data;
}

aktualizovaťHodnotu :

updateValue(value) {
  this.$root.$emit('input', {'inputName' : this.inputName, 'inputValue' : value});
    }
}

Tiež nevidím potrebu používať $root, pretože môžete použiť $emit v komponente. Pre ne-klasické komponenty k nemu pristupujete cez this.$emit, myslím, že tu by to malo byť rovnaké.

Ďalšou zmenou, ktorú môžete urobiť, je počúvať udalosť v HTML:

<label-input inputId="formProductId"
             inputType="number"
             inputName="productId"
             :inputEnabled="filters.productId.options"
             :label="translations['product_id']"
             :placeholder="translations['product_id']"
             :data="filters.productId.value"
             @updateValue="doSomething"

/>

Môžete deklarovať metódu s názvom doSomething, ktorá prijíma prijatú hodnotu ako prvý argument, alebo jednoducho nastaviť premennú na hodnotu prijatú udalosťou @updateValue="(value) => {filters.productId.value=value}". Toto bude fungovať rovnako.