Vue + VUEX + Typescript + Vue Router. component is not destroyed

Vue.js version = 2.3.3

A question for everyone. I have a json that contains a list of data based on json. I am creating form input. Form inputs have a bound model that basically updates the application state transaction.

I have a component that displays a list of checkboxes, On one page I have 1 instance, and on the next I have 3 instances of the component, each with its own checkbox list and a different name.

When navigating from page 1 to page 2, the checkbox_list component from page 1 does not fire the destroyed lifecycle hook (other components fire it).

On page 2 I have 3 other components of type checkbox_list with their name, model and parameters. ( data

initialized as a function). Somehow, in the list of checkboxes of the third type component, the hook created

, neither set nor w / e, is fired . It renders but doesn't render and events and model are there and from vue debugger the model array is empty. The problem is that when I update the checkbox model (by clicking on one of the checkboxes from the list) in the 3rd component instance (the one that does not fire the created lifecycle hook), the model contains everything that I checked on the first page of the checkbox_list component instance ...

Components are mostly rendered in a loop as the data is parsed. Does anyone know why this is happening? Thank.

Please see below for my components code. InputTypes.ts

import Vue from 'vue';
import Component from 'vue-class-component';

import TextInput from './text/TextInput.vue';
import EmailInput from './email/EmailInput.vue';
import RadioGroup from './radio/RadioGroup.vue';
import SelectInput from './select/SelectInput.vue';
import SelectAutocompleteInput from './select/SelectAutocompleteInput.vue';
import PasswordInput from './password/PasswordInput.vue';
import CheckboxGroup from './checkbox/CheckboxGroup.vue';
import AgreementSection from './custom/AgreementSection.vue';
import CvSection from './custom/CVSection.vue';
import SubmitSection from './custom/SubmitSection.vue';


@Component({
  name: 'input-types',
  props: ['field', 'lastPageIndex'],
  components: {
    TextInput,
    EmailInput,
    RadioGroup,
    SelectInput,
    SelectAutocompleteInput,
    PasswordInput,
    AgreementSection,
    CheckboxGroup,
    CvSection,
    SubmitSection
  },
  watch: {
    '$route'($to, $from) {
      let clearFields = this['clearFields'];
      clearFields();
    }
  }
})

export default class InputsTypes extends Vue {
  conditionalFields: object = {fields: []};

  clearFields(): void {
    this.$set(this.conditionalFields, 'fields', []);
  }

  changeHandler(fields): void {
    this.$set(this.conditionalFields, 'fields', fields);
  }

  updateModelValue(data): void {
    console.log(data);
  }
}

      

InputTypes.vue

<!-- InputTypesComponent -->
<template>
  <div>
    <text-input v-if="field.type == 'text'" :field="field"></text-input>

    <email-input v-else-if="field.type == 'email'" :field="field"></email-input>

    <checkbox-group v-else-if="field.type == 'checkbox_list'" :field="field"></checkbox-group>

    <radio-group v-else-if="field.type == 'radio'" :field="field" :onChange="changeHandler"></radio-group>

    <select-input  v-else-if="field.type == 'select'" :field="field" :onChange="changeHandler"></select-input>

    <select-autocomplete-input  v-else-if="field.type == 'select_autocomplete'" :field="field" :onChange="changeHandler"></select-autocomplete-input>

    <password-input v-else-if="field.type == 'password'" :field="field"></password-input>

    <agreement-section v-else-if="field.type == 'agreement'" :field="field"></agreement-section>

    <div v-else-if="field.type == 'complex_inputs'">
      <label>{{field.label}}</label>
      <div v-for="option, key in field.options" :key="key">
        <input-types :field="option" :onChange="changeHandler"></input-types>
      </div>
    </div>
    <cv-section v-else-if="field.type == 'cv_section'" :field="field"></cv-section>
    <submit-section v-else-if="field.type == 'next_page'" :field="field" :lastPageIndex="lastPageIndex"></submit-section>

    <div v-if="conditionalFields.fields" v-for="field, key in conditionalFields.fields" :key="key">
      <input-types :field="field" :onChange="changeHandler"></input-types>
    </div>
  </div>
</template>

<script lang="ts">
  import InputsTypes from './InputsTypes.ts'
  export default InputsTypes
</script>

      

CheckboxGroup.ts

import Vue from 'vue';
import Component from 'vue-class-component';


@Component({
  name: 'checkbox-group',
  props: ['field'],
  watch: {
    selected: (e) => {
      console.log(e);
    }
  },
  created(): void {
    let predefinedSelected: Array<string> = [];
    let data: object = {
      'name': this.$props.field.name,
      'value': predefinedSelected
    };

    let updateState = this['updateState'];
    updateState(data);
  }
})

export default class CheckboxGroup extends Vue {
  updateStore(): void {
    let data: object = {
      'name': this.$props.field.name,
      'value': this['selected']
    };
    this.updateState(data);
  }

  updateState(data): void {
    this.$store.commit('SIMPLE_FIELD_UPDATE', data);
  }

  data(): object {
    let predefinedSelected: Array<string> = this.$props.field.selected || [];
    return {
      selected: []
    }
  }
  created(): void {
    console.log('created');
  }
  mounted(): void {
    console.log('mounted');
  }
  destroyed(): void {
    console.log('destroyed');
  }
}

      

CheckboxGroup.vue

    <template>
  <div class="checkbox-group">
    <div class="row" v-if="field.label">
      <div class="col">
        {{field.label}}
      </div>
    </div>
    <div class="row">
      <div class="form-check col-3" v-for="option, key in field.options" :key="key">
        <label class="form-check-label">
          <input class="form-check-input" v-model="selected" @change="updateStore" type="checkbox" :name="field.name" :value="option.label"/>
          {{option.label}}
        </label>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
  import CheckboxGroup from './CheckboxGroup.ts'
  export default CheckboxGroup
</script>

      

+3


source to share


3 answers


The problem was solved easily. The problem was that I was changing views based on the url and providing different components, but some of them were persistent in the view, so Vue assumed the same components that were needed in the previous view. To solve this I just passed to key

the page component, so in this situation it is treated as a different component and there is no shallow comparison in the page component.



Conclusion . Don't forget that you are playing with guys and girls.

0


source


This is a great place for a mutable component, allowing you to have components that can reshape at runtime based on data.

So you want to add your composite types to your own components, and then instead of the conglomeration component, input-types

you just use

<component :is="field.type" :field="field"></component>

      

wherever you use



<input-types :field="field"></input-types>

      

You will need to make sure your field.type matches your component labels. so there text-input

must be a value for the type parameter text-input

.

If you need help, let me know.

+1


source


This is a pretty big description / set of code to try and read / understand what the real problem is. I might suggest trying to keep the description / situation as simple as possible in the future.

I believe the source of your problem may be related to the interaction of v-for and v-if on the same element. The v-if statement is going to reevaluate this v-for element for each loop. The simplest answer is to run a v-if on the element <template>

just above what you want the v-for to run instead .

https://vuejs.org/v2/guide/list.html#v-for-with-v-if

0


source







All Articles