Guys so I'm trying to develop this rule component which can be spawned by my main component as many times as he wants but the problem is that when I delete an index from the list that tracks the number of rules, the vuejs layout doesn't update accordingly. What I mean by this is that if I check the array it self it deleted the correct item but when I look at the vue page (HTML) it either doesn't delete anything or only deletes the last item, and this may be caused by the v-for
not updating on list change but I don't know how to solve this.
NewTask.vue (Parent)
<template>
<div class="mt-4">
<div class="container">
<div class="if-condition container-fluid d-flex flex-row ps-0">
<span class="text-center me-2 condition rounded">IF</span>
<select class="form-select form-select-sm me-2 if-select" v-model="if_condition">
<option value="ALL">ALL</option>
<option value="ANY">ANY</option>
<option value="NONE">NONE</option>
</select>
<span>of these filters match</span>
</div>
<div class="mt-2 ps-3 pt-3 pb-3 border">
<new-rule v-for="(item, index) in rules"
:key="JSON.stringify(index)" v-on:remove-rule="removeRule(index)"
:data="item" :index="index" v-on:data-changed="dataChanged"
class="mb-2"/>
<div class="mt-2 add-rule-div">
<button class="btn add-rule-btn" v-on:click="addRule"> </button>
</div>
</div>
</div>
</div>
</template>
<script>
import Rule from '@/components/rule'
export default {
name: "NewTask",
components: {
'new-rule': Rule
},
data: function () {
return {
if_condition: 'ALL',
rules: []
}
},
methods: {
dataChanged(data) {
const rules = this.rules;
const index = data.index;
delete data['index'];
rules.splice(index, 1, data)
this.rules = rules;
},
removeRule(index) {
const rules = this.rules;
rules.splice(index, 1)
this.rules = rules
},
addRule() {
const new_rule = {
type_input_text: null,
type_input_show: null,
rule_input_text: null,
rule_input_show: null,
}
this.rules.push(new_rule)
console.log(this.rules)
}
}
}
</script>
rule.vue (Child)
<template>
<div class="if-condition d-flex flex-row">
<select class="form-select form-select-sm me-2"
v-on:change="checkTypeSelect" v-model="type_select">
<option value="HTML">HTML</option>
<option value="XPATH">XPATH</option>
<option value="ID">ID</option>
<option value="CLASS">CLASS</option>
</select>
<input v-if="type_input_show" type="text" class="form-control me-2" v-model="type_input_text" v-on:change="dataChanged">
<select class="form-select form-select-sm me-2"
v-on:change="checkRuleSelect" v-model="rule_select">
<option value="CONTAINS">CONTAINS</option>
<option value="EXISTS">EXISTS</option>
</select>
<input v-if="rule_input_show" type="text" class="form-control me-2" v-model="rule_input_text" v-on:change="dataChanged">
<button class="btn remove-rule-btn pb-0 pt-0 ps-2 pe-2" v-on:click="this.$emit('remove-rule')">-</button>
</div>
</template>
<script>
export default {
name: "rule",
props: {
data: {
type: Object,
required: true
},
index: {
type: Number,
required: true
}
},
data: function () {
return {
type_select: 'HTML',
type_input_text: '',
rule_select: 'CONTAINS',
rule_input_text: '',
//
type_input_show: false,
rule_input_show: true,
}
},
beforeMount() {
if (this.data.type_select) {
this.type_select = this.data.type_select
this.checkTypeSelect()
}
if (this.data.type_input_text) {
this.type_input_text = this.data.type_input_text
}
if (this.data.rule_select) {
this.rule_select = this.data.rule_select
this.checkRuleSelect()
}
if (this.data.rule_input_text) {
this.rule_input_text = this.data.rule_input_text
}
},
methods: {
dataChanged() {
const new_data = {
index: this.index,
type_select: this.type_select,
type_input_text: this.type_input_text,
rule_select: this.rule_select,
rule_input_text: this.rule_input_text
}
this.$emit('data-changed', new_data)
},
checkTypeSelect() {
const type_select = this.type_select;
this.type_input_show = type_select !== 'HTML';
this.dataChanged()
},
checkRuleSelect() {
const rule_select = this.rule_select;
this.rule_input_show = rule_select !== 'EXISTS';
this.dataChanged()
}
}
}
</script>
Some images to demonstrate the issue:
For further investigation feel free to visit the repo: https://github.com/DEADSEC-SECURITY/Easy-Scraper
THIS IS NOT PUBLICITY, I TRULY NEED HELP
CodePudding user response:
You are using the index as a key. VueJS updates the DOM based on the change in key. So you have two options:
- Use some distinct data from each entry or combination as a key.
- Provide no key because as per Vuejs docs you need not provide a key anymore.
CodePudding user response:
Currently, your rules
value in NewTask.vue
is under data
. If you move it into computed
, it will become reactive and the list should update properly.