Shelly
Shelly

Reputation: 440

VUE Js child is not updating when parent updates

I am using VUE JS and I want to have group of checkboxes as below. When someone clicked on main checkbox all the checkboxes under that check box should be selected. Please find the attached image for your reference

enter image description here

To accomplish this scenario I am using 2 main components. When someone clicked on a component I am adding that component to selectedStreams array. Selected stream array structure is similar to below structure

  checked: {
        g1: ['val1'],
        g2: []
    }

When I click on heading checkbox I am triggering function

clickAll and try to change the selectedStreams[keyv].

But this action doesn't trigger the child component and automatically checked the checkbox.

Can I know the reason why when I changed the parent v-model value it is not visible in child UI.

Parent Component

 <template>
    <div>
        <b-form-group>
            <StreamCheckBox
                    v-for="(opts, keyv) in loggedInUsernamesf"
                    :key="keyv"
                    :name="opts"
                    :main="keyv"
                    v-model="selectedStreams[keyv]"
                    @clickAll="clickAll($event, keyv)"
            ></StreamCheckBox>
        </b-form-group>
    </div>
</template>
<script>import StreamCheckBox from "./StreamCheckBox";
export default {
        name: "GroupCheckBox",
        components: {StreamCheckBox},
        data(){
          return {
            selectedStreams:{}
          }
        },
        computed: {
            loggedInUsernamesf() {
                var username_arr = JSON.parse(this.$sessionStorage.access_info_arr);
                var usernames = {};
                if (!username_arr) return;
                for (let i = 0; i < username_arr.length; i++) {
                    usernames[username_arr[i].key] = [];
                    var payload = {};
                    payload["main"] = username_arr[i].val.name;
                    payload["type"] = username_arr[i].val.type;
                    if (username_arr[i].val.permissions) {
                        for (let j = 0; j < username_arr[i].val.permissions.length; j++) {
                            payload["value"] = username_arr[i].key + username_arr[i].val.permissions[j].streamId;
                            payload["text"] = username_arr[i].val.permissions[j].streamId;
                        }
                    }
                    usernames[username_arr[i].key].push(payload);
                }
                return usernames;
            },
        },

        methods: {
            
            clickAll(e, keyv) {
                if (e && e.includes(keyv)) {
                    this.selectedStreams[keyv] = this.loggedInUsernamesf[keyv].map(
                        opt => {
                            return opt.value
                        }
                    );
                }
                console.log(this.selectedStreams[keyv]);
            }
        }
    }
</script>

<style scoped>

</style>

Child Component

    <template>
    <div style="text-align: left;">
        <b-form-checkbox-group style="padding-left: 0;"
                               id="flavors"
                               class="ml-4"
                               stacked
                               v-model="role"
                               :main="main"
        >
            <b-form-checkbox
                    class="font-weight-bold main"
                    :main="main"
                    :value="main"
                    @input="checkAll(main)"
            >{{ name[0].main }}</b-form-checkbox>
                <b-form-checkbox
                        v-for="opt in displayStreams"
                        :key="opt.value"
                        :value="opt.value"
                >{{ opt.text }}</b-form-checkbox>
            </b-form-checkbox-group>
    </div>
</template>

<script>
    export default {
        name:"StreamCheckBox",
        props: {
            value: {
                type: Array,
            },
            name: {
                type: Array,
            },
            main:{
                type:String
            }

        },
        computed:{
            role: {
                get: function(){
                    return this.value;
                },
                set: function(val) {
                    this.$emit('input', val);
                }
            },
            displayStreams: function () {
                return this.name.filter(i => i.value)
            },
        },
        methods:{
            checkAll(val)
            {
                this.$emit('clickAll', val);
            }
        }
    }
</script>

Upvotes: 3

Views: 1994

Answers (1)

Jakub A Suplicki
Jakub A Suplicki

Reputation: 4801

First of all, I am not sure what is the purpose of having props in your parent component. I think you could just remove props from your parent and leave in the child component only.

Second of all, the reason for not triggering the changes could be that you are dealing with arrays, for that you could set a deep watcher in your child component:

export default {
  props: {
    value: {
      type: Array,
      required: true,
    },
  },
  watch: {
    value: {
      deep: true,
      //handle the change
      handler() {
        console.log('array updated');
      }
    }
  }
}

You can find more info here and here.

Upvotes: 3

Related Questions