VueJS forms and object props



In working with VueJS recently, a reoccurring gremlin has been Vue’s concept of props, using an object as a prop, and using objects with v-model. The application I’m putting together is basically a CRUD (create read update destroy) ticketing system. It uses several HTML forms to update records.

Taking advantage of Vue’s component system, these forms are completely encapsulated which makes them easy to drop in where-ever they’re needed. They take a database record, as a JSON object, make some changes and then emit a new object when saved. Whatever component is the parent of the form is responsible for providing the initial record as a prop and handling saving the new record.

<save-ticket-form
  :ticket="ticket"
  :submitting="false"
  v-on:save="onSaveTicket"
  v-on:cancel="resetTicket">
</save-ticket-form>

There’s a few important concepts here that expose the prickly nature of using props to pass in the initial database record. The first is that props are read-only. In fact some of Vue’s contributors will suggest that you only use primitives like numbers, strings, and booleans in props, and not objects, since objects are passed by reference. If you try to directly manipulate a primitive prop, Vue’s developer tools will yell at you.

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.

But it can’t tell if you change properties on an object prop. That is unless you’re using Vuex, in which case Vuex will then yell at you for manipulating its data directly. The end result is the same - you don’t want to directly mutate props.

There are several ways to respect read-only props when using objects. This gets into another issue however, data reactivity. Depending on how you handle the prop, if you’re using v-model on the resulting object’s properties, you might have issues with data reactivity. Vue expects to know about all of an object’s properties whenever the component exposing that object is rendered. If not you’ll run into instances where v-model behaves in unpredictable ways, watchers won’t fire, and Vue might give you warnings about null values if you’re trying to use deeply nested properties (Object.company.id)