3

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>
Shelly
  • 410
  • 7
  • 26
  • You could pass the value down to the children and if that value is true then have them be checked. If you pass it as props down to the child you could also put a watcher on it and run a function causing an update whenever that props value changes – Aaron Angle Jul 06 '20 at 19:41
  • @AaronAngle I am using an array and push into it if any checkbox is selected. – Shelly Jul 06 '20 at 21:04

1 Answers1

2

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.

Jakub A Suplicki
  • 4,586
  • 1
  • 23
  • 31
  • Thank you very much for your answer. I have added watch function to my code and that function triggers when I click on a checkbox. But here my concern is to use ClickAll method inside parent class to push child elements also into selected array. So when some one clicks on parent checkbox all the child checkboxes should be checked. change in the array this.selectedStreams[keyv] is not visible in child. It would be really great if you could help me with this. – Shelly Jul 06 '20 at 21:00
  • `selectedStreams` seems to be a `computed property`. If you wanted the returned array to be visible in the child component, you would return some kind of `data property` and pass it as a `prop` that you could then `watch` in your child component again. That could be one way to see the change of a returned array from `selectedStreams` in your child component or `checkAll` could return such array that you would use a `prop`. – Jakub A Suplicki Jul 06 '20 at 21:18
  • I have changed my code to make selectedStreams as a data property. (return selectedStreams:{}). But for the v-model, I am passing selectedStreams[key] which should return an array. Changes to this selectedStream object is not still visible. I am new to vuejs and I cant figure out the issue with this. – Shelly Jul 07 '20 at 07:19
  • If you wanted me to look into the specific scenario then it would be helpful if you could recreate it in CodeSandbox (https://codesandbox.io/s/vue), for example. – Jakub A Suplicki Jul 07 '20 at 21:06