Search code examples
vue.jsv-forv-model

Vue,js, Computing a property with v-model?


I have a vue page that loads a bunch of actions from a database. It then creates a table with some data got from the action, using v-for.

Here is my problem: In one of the table rows I need a checkbox that is v-modeled to an attribute, action.weekly. Ideally, it will be a boolean. But there are a bunch of action entries in my database that don't have a weekly attribute. In those cases, I need the checkbox checked, as if it were true. Normally, I would use a computed property here, but you can't pass arguments to computed properties, so I don't know how to tell vue which action to look at at (I can't pass $event, ndx in to a computed property like I am doing below with handleEnableChanged() ).

Here is my code for the table:

<tbody>
            <tr v-for="(action, ndx) in actions" >
              <td class="pointer" @click='openModalCard(action, ndx)'>
                {{action.name}}
              </td>
                <input type="checkbox" v-model="action.weekly??" @change="handleEnableChanged($event, ndx)"/>
              </td>
                <input type="checkbox" v-model="action.enabled" @change="handleEnableChanged($event, ndx)">
              </td>
            </tr>
            </tbody>

In the cases where action does not have a weekly attribute, I want the checkbox checked as if it were true. How can I accomplish this?

If there is a better way to approach this, please let me know. I'm still a novice with vue.js.


Solution

  • I think it would be easiest to use v-if and v-else for this.. With that being said, I have also provided an example of how to handle this without v-if and v-else..

    Using v-if and v-else:

    new Vue({
      el: "#root",
      data: {
        actions: [
            {
              name: "first",
              weekly: true,
              enabled: false
            },
            {
              name: "second",
              enabled: false
            },
            {
              name: "third",
              weekly: true,
              enabled: true
            },
            {
              name: "fourth",
              enabled: true
            }
          ]
      },
      template: `
    <tbody>
      <tr v-for="(action, ndx) in actions" >
        <td class="pointer" @click='console.log(action, ndx)'>{{action.name}}</td>
        <input v-if="'weekly' in action" type="checkbox" v-model="action.weekly" @change="handleEnableChanged($event, ndx)"/>
        <input v-else type="checkbox" checked="true" @change="handleEnableChanged($event, ndx)"/>
        </td>
        <input type="checkbox" v-model="action.enabled" @change="handleEnableChanged($event, ndx)">
        </td>
      </tr>
    </tbody>
      `,
      methods: {
        handleEnableChanged(evt, ndx) {
          console.log(evt, ndx);
        },
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
    <div id="root"></div>

    Without v-if and v-else:

    new Vue({
      el: "#root",
      data: {
        actions: ""
      },
      template: `
    <tbody>
      <tr v-for="(action, ndx) in actions" >
        <td class="pointer" @click='console.log(action, ndx)'>{{action.name}}</td>
        <input type="checkbox" v-model="action.weekly" @change="handleEnableChanged($event, ndx)"/>
        </td>
        <input type="checkbox" v-model="action.enabled" @change="handleEnableChanged($event, ndx)">
        </td>
      </tr>
    </tbody>
      `,
      methods: {
        handleEnableChanged(evt, ndx) {
          console.log(evt, ndx);
        },
        getActions() {
          let originalActions = [
            {
              name: "first",
              weekly: true,
              enabled: false
            },
            {
              name: "second",
              enabled: false
            },
            {
              name: "third",
              weekly: true,
              enabled: true
            },
            {
              name: "fourth",
              enabled: true
            }
          ];
          this.actions = originalActions.map(a => { 
            return {
              name: a.name,
              weekly: 'weekly' in a ? a.weekly : true,
              enabled: a.enabled
            }
          })
        }
      },
      created() {
        this.getActions();
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
    <div id="root"></div>