Sumit Ridhal
Sumit Ridhal

Reputation: 1419

Binding length of one object from $data to another object

VueJS Version

2.1.10

Reproduction link

http://codepen.io/sumitridhal/full/ybVGZa/

What is expected?

While creating custom select input and binding the last value to items object in data.

<select class="form-control xsmall" v-
model="options.limit.value">
  <option v-for="option in options.availableOptions" v-bind:value="option.value">
    {{ option.name }}
  </option>
</select>

the object in options array

{
          id: "4",
          name: "All",
          value: null
}

should bound to length of items.

var app = new Vue({
  // app initial state
  data: {
    title: "VueJS 2.1x CURD Application",
    items: v_items,
    
    options: {
      availableOptions: [
        {
          id: "1",
          name: "5",
          value: 5
        },
        {
          id: "2",
          name: "10",
          value: 10
        },
        {
          id: "3",
          name: "15",
          value: 15
        },
        {
          id: "4",
          name: "All",
          value: null
        }
      ],
      limit: {
        id: "1",
        name: "5",
        value: 5
      } //This sets the default value of the select in the ui
    }
  }
})

#What is actually happening?

Uncaught TypeError: Cannot read property 'length' of undefined

the value for { id: "4", name: "All", value: null } should always bind with items length

Upvotes: 0

Views: 862

Answers (2)

Sumit Ridhal
Sumit Ridhal

Reputation: 1419

Thanks @roy-j. Need to set options.limit.value binding also. Check http://codepen.io/sumitridhal/full/ybVGZa/

computed: {
    availableOptionsPlus: function() {
      this.options.limit.value = this.items.length;
      return this.options.availableOptions.concat({
        id: this.options.availableOptions.length + 1, // counting itself
        name: "All",
        value: this.items.length
      });
    }
  }

Also the watcher for items to set limit.value

 // watch items change 
  watch: {
    items: {
      handler: function(items) {
        this.options.limit.value = items.length;
      },
      deep: true
    }
  }

Upvotes: 0

Roy J
Roy J

Reputation: 43899

UPDATE: This looks like an exception to the general rule I gave in my original answer (still below). To avoid regenerating the options list every time, you can add a watch that just updates the value of the last item:

  watch: {
    items: {
      handler: function(items) {
        this.options.limit.value = items.length;
      },
      deep: true
    },
    items: function() {
      this.options.availableOptions[this.options.availableOptions.length - 1].value = this.items.length;
    }
  }

Original answer:

As a general rule, anything that gets its value from somewhere else should be a computed. Have a data array of the normal items, then use a computed that returns those plus the length item. Something like:

computed: {
  availableOptionsPlus() {
    return this.availableOptions.concat({
      id: this.availableOptions.length + 1, // counting itself
      name: "All",
      value: this.items.length
    })
  }
}

Upvotes: 2

Related Questions