What are strategies for handling intricate state logic within my Vue.js checkbox component?

I'm facing a few challenges as I dive into learning Vue.js for just one week. Keep in mind that this example is actually nested within a parent component called <question>, but for the sake of simplicity, I've streamlined the code for this post.

  1. Is there a way to have certain items pre-checked when the page loads?

Edit — I cracked number 1. Just needed to use

[ "Chicken", "Turkey", "Beef", "Fish", "Pork" ]

  1. How can I deselect specific items, like unchecking meat options if I choose Vegan?
  2. How do I add Exclude and Include checkboxes next to my options?

https://i.stack.imgur.com/GGOSe.gif

Checkbox

<div id="questionnaire">
  <checkbox v-model="form.meats" id="8a"  option="Chicken"></checkbox>
  <checkbox v-model="form.meats" id="8b" option="Turkey"></checkbox>
  <checkbox v-model="form.meats" id="8c" option="Beef"></checkbox>
  <checkbox v-model="form.meats" id="8d" option="Pork"></checkbox>
  <checkbox v-model="form.meats" id="8e" option="Fish"></checkbox>
  <checkbox v-model="form.meats" id="8f" option="Vegetarian Only"></checkbox>
  <checkbox v-model="form.meats" id="8g" option="Vegan Only"></checkbox>
  {{ form.meats }}
</div>

Vue.component('checkbox')

Vue.component('checkbox', {
  template: `
    <div>
            <input type="checkbox" :id="id" :value="option" v-model="checked" @change="update">
            <label :for="id">
                {{ option }}
                <slot></slot>
            </label>
    </div>
    `,
  data() {
    return {
      checkedProxy: false
    }
  },
  computed: {
    checked: {
      get() {
        return this.value
      },
      set(option) {
        this.checkedProxy = option
      }
    }
  },
  methods: {
    update: function(e) {
      this.$emit('input', this.checkedProxy)
    }
  },
  props: {
    value: null,
    option: null,
    id: {
      type: String,
      required: true
    }
  }
});

new Vue({
  el: "#questionnaire",
  data: {

    form: {

      meats: [],

    }
  }
})

Answer №1

I believe these are the details you're looking for.

<div id="questionnaire">
  <check-group :chks="chks" v-model="form.meats"></check-group>
  {{ form.meats }}
</div>

const elements = {
    '1': {
        tag: 'meats',
        exclusiveGroups: [2]
    },
    '2': {
        tag: 'vegan',
        exclusiveGroups: [1,3]
    },
    '3': {
        tag: 'Vegetarian Only',
        exclusiveGroups: [1,2]
    }
}

const checkboxes = {
    'Chicken': {
        groupIds: [1]
    },
    'Turkey': {
        groupIds: [1]
    },
    'Beef': {
        groupIds: [1]
    },
    'Pork': {
        groupIds: [1]
    },
    'Fish': {
        groupIds: [1]
    },
    'Vegetarian Only': {
        groupIds: [3]
    },
    'Vegan Only': {
        groupIds: [2]
    }
}

Vue.component('checkbox', {
    template: `
    <div>
        <label>
            <input type="checkbox" ref="chk" :value="val" v-model="value" @change="update($event)">
            {{ txt }}
            <slot></slot>
        </label>
        <input type="checkbox" :checked="value.indexOf(val)<0" @change="reverseSelection($event)">
    </div>
    `,
    data () {
        return {
            val: this.optValue || this.optText,
            txt: this.optText || this.optValue
        }
    },
    methods: {
        update (e) {
            this.$emit('input', this.value, e.target.value, e.target.checked)
        },
        reverseSelection () {
            var e = document.createEvent("MouseEvents");
            e.initEvent("click", true, true);
            this.$refs.chk.dispatchEvent(e);
        }
    },
    props: ['value','optValue','optText']
});

Vue.component('check-group',{
    template: `
        <div>
            <checkbox v-for="item in chks" :opt-value="item.value" :opt-text="item.text" @input="update" v-model="value"></checkbox>
        </div>
    `,
    props: {
        value: {
            required: true,
            type: Array
        },
        chks: {
            required: true,
            type: Array
        }
    },
    methods: {
        update (val,curVal,checked) {
            if(checked){
                chks[curVal].groupIds.forEach(id=>{
                    groups[id].exclusiveGroups.forEach(eid=>{
                        for(let i=0;i<val.length;i++){
                            let p = chks[val[i]].groupIds.indexOf(eid)
                            if(p>=0){
                                val.splice(p,1)
                                i--
                            }
                        }
                    })
                })
            }
            this.$emit('input',val)
        },
    }
})

new Vue({
    el: "#questionnaire",
    data: {
        chks: Object.keys(chks).map(key=>({value: key,groupIds: chks[key]})),
        form: {
            meats: ['Chicken']
        }
    }
})

If you want to ensure that vegan and vegetarian options cannot be selected simultaneously, make the following adjustments to the definitions of groups and checkboxes:

const elements = {
    '1': {
        tag: 'meats',
        exclusiveGroups: [2]
    },
    '2': {
        tag: 'vegan',
        exclusiveGroups: [1,3]
    },
    '3': {
        tag: 'Vegetarian Only',
        exclusiveGroups: [1,2]
    }
}

const checkboxes = {
    'Chicken': {
        groupIds: [1]
    },
    'Turkey': {
        groupIds: [1]
    },
    'Beef': {
        groupIds: [1]
    },
    'Pork': {
        groupIds: [1]
    },
    'Fish': {
        groupIds: [1]
    },
    'Vegetarian Only': {
        groupIds: [3]
    },
    'Vegan Only': {
        groupIds: [2]
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Begin by initializing a variable within the `mounted` lifecycle hook and then pass it back to

Experimenting with the new composition api. Check out the composable function useProduct.js below: export default function useProduct() { const product = reactive({}); async function getProduct(id) { try{ const response = await { ...

An elegant approach to converting a JavaScript object containing key-value pairs into an array of objects, each with a single key-value pair

Essentially, I have an enum that represents different statuses status = {1: "new", 2: "working" ... } and my goal is to transform it into something like status = [{1: "new"}, {2: "working"} ...] in a way that is cl ...

Having trouble getting the jQuery function to update text properly

I'm curious to understand the behavior happening in this code snippet. It seems like updating the list item by clicking doesn't work as expected using the initial method. But when rearranging the JavaScript code, it displays the correct value wit ...

What are some effective techniques for handling asynchronous operations while utilizing [displayWith] in an autocomplete

In my angular reactive form, I am struggling with an autocomplete functionality. I want to show the name (myObject.name) but use the ID (myObject.id) as the value. However, when the form is populated with existing values, there is a delay in retrieving th ...

Understanding the behavior of the enter key in Angular and Material forms

When creating forms in my MEAN application, I include the following code: <form novalidate [formGroup]="thesisForm" enctype="multipart/form-data" (keydown.enter)="$event.preventDefault()" (keydown.shift.enter)="$ev ...

The presentation of the Google graph with dynamically changing data appears to be displaying inaccurately

I am looking to incorporate a graph displaying sales and purchase data on my webpage. Users should be able to select from categories like Purchase, Sales, or Production. I have separate tables for Purchase (AccPurchase) and Sales (AccSales), with productio ...

Extracting information from a designated website using Python, including pages with search functionality and javascript features

Visit the website where you will find a search input box in html. Input a company name into the search box, select the first suggestion from the drop-down menu (like "Anglo American plc"), navigate to the URL containing information about that specific com ...

Create a toggle effect using attribute selectors in CSS and JavaScript

I am looking to switch the "fill: #000;" from the CSS property "svg [id^='_']". Usually, I would use a method like this, but it seems that I can't do so because "svg [id^='_']" is not an element, correct? pub.toggleClass = functi ...

Avoid displaying "undefined" on HTML page when Firebase database value is empty

I am trying my best to explain my issue, although I struggle with scripts. Please bear with me and help me improve. ˆˆ Below is the script I am working on. The goal is to display all records with a date set for 'today or in the future'. Progr ...

Understanding how to retrieve a particular list item in JQuery without having the index in advance

I have a lengthy list that is broken down into various subheadings. How can I retrieve the second to last element of the list before a specific subheading, provided it is not the final element? Is it possible to do this if I know the ID of the subheading? ...

The error message "TypeError: e.preventDefault is not a function" indicates that

I'm fairly new to JavaScript and jQuery, and I've incorporated two jQuery plugins into my code - jQuery form validator and jQuery form ajaxSubmit. Initially, everything was working fine with normal AJAX submission until I needed to post a file, w ...

How to Stop AJAX Requests Mid-Flight with JQuery's .ajax?

Similar Question: Stopping Ajax Requests in JavaScript with jQuery Below is the straightforward piece of code that I am currently using: $("#friend_search").keyup(function() { if($(this).val().length > 0) { obtainFriendlist($(this).va ...

Insert elements to an XML document in Node.js using libxmljs

I've been working on updating an XML file by adding a new child node using the code below: var libxml = require('libxmljs'); var xml = '<?xml version="1.0" encoding="UTF-8"?>' + '<root>' + ...

The function Server.listeners is not recognized by the system

Currently, I am following a tutorial on websockets to understand how to incorporate Socket.IO into my Angular project. Despite meticulously adhering to the instructions provided, I encountered an error when attempting to run my websockets server project: ...

leaving code block using Express and Node

My code is displayed below: // Implement the following operations on routes ending with "users" router.route('/users') .post(function(req, res, next) { var user = new User(); user.username = req.body.username; user.p ...

What causes the low Performance score of a default NextJS Application with no content?

Just started experimenting with my initial Next.js project. Upon generating a new project using create-next-app, I decided to test its performance with the web application 'Lighthouse'. Surprisingly, although most other metrics scored above 90, ...

Navigating through the DOM using JavaScript or regular expressions

I have a DOM string called innerHTML and I am looking to extract or display the node value using either JavaScript's DOM API or JavaScript RegEx. "<nobr> <label class="datatable-header-sortable-child" onmousedown="javascript:giveFeedback(&ap ...

No data is being returned by the Jquery Ajax function

I am experiencing an issue with a Jquery Ajax call in my code: $('body').on('click', '#btnPopulate', function() { alert(getTree()); }); function getTree() { var url = getUrlPath() + "/StoryboardAdmin/BuildStoryboardViewMode ...

Error in Vue component when setting the background image URL

Here is my code snippet that sets the background image for a component: style() { return { "background-image": `url(${require(`../../../assets/images/${this .last_result}.png`)})` }; }, The expected URL should be ../../../assets/images/ ...

Embracing the Quirks of JSON: A Call for a

Currently, I am in the process of developing a webpage that involves incorporating four distinct JSON entities (objects, arrays). Excuse my lack of appropriate jargon. Upon receiving the JSON data, it is structured as an object with numerous sub-objects, ...