xpepermint / vue-rawmodel

RawModel.js plugin for Vue.js v2. Form validation has never been easier!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Clarification of how to use nested schemas/models

michaelsorich opened this issue · comments

I am having a little difficulty understanding how to properly use nested schemas. In the objectschema example I see that there is a nested schema (the field books has a type of [bookSchema]) in the user schema. I am clear on defining the schema but I am not sure how to use this operationally in vue.

For example if I have a form in the template which enables editing of the details of all books in addition to the user details.

  1. if I wish to have a button for adding additional books how do I code for this.
    e.g. my guess would be to use something like this.user.books.push({ title: 'True Detective' }), but this does not seem to work properly.

  2. I also am having some issue with v-model on the nested models.
    e.g. I am attempting to display fields for all the nested models. In terms of the user/book example it would be something like this for the first book in the array

{{ user.books[0].$title.errors | firstMessage }} I find that the user.books[0].title value of the model is not updated when I change the value in the form field (e.g. if I include {{ user.books[0].title value }} in the template to track this) and hence the rest of the methods/properties (e.g. hasErrors, errors) are not updated either. If I use a simple data object instead of the schema object this issue does not occur. I notice that when I change the value of a form field bound to a field such as user.name it triggers the user.books[0].title value to be updated such that it matches what is in the form field. Any insight into what I am doing wrong would be appreciated.

I'm about to start writing an example for you. I just need some information:

  • How does your form structure look like?
  • Are you using sub-components in your form?

Thanks - this would be much appreciated.

I currently have a single component which focuses on editing the model (including its nested models). The template contains a single form containing simple fields of the parent model (using html input fields with v-model to bind the appropriate field similar to the example in the vue-contextable README.md), as well fields for each nested models in the array holding the nested models. I have been displaying the same set of fields for each instance of the nested model by iterating over nested models in the array using v-for (at the moment I have each nested model displayed as a row of a table). Next to the collection of fields for each nested model I have button to delete the nested model from the array (delete row from the table). I also have button to add an new nested model to the end of the array (i.e. add row to the bottom of the table in the form).

Hum... it seams that Vue is not tracking changes on class instances but it could also be a bug in the plugin. I'll investigate so don't worry, we'll find a solution soon. I also asked for help here so please be patient.

Here is what I came up with:

  1. Since Vue.js doesn't recommend modifying a model structure at runtime, the easiest solution to fix this immediatelly is to set the defaultValue of each nested field to a non-null value as shown in the example below. This will deeply construct model structure before making the model reactive.
export default new Schema({
  fields: {
    ...
    book: {
      type: bookSchema,
      defaultValue: {} // THIS
    },
    books: {
      type: [bookSchema],
      defaultValue: [{}] // THIS
    }
  }
});
  1. I've upgraded this plugin with a new modelData configuration option which pre-populates a model (preferred way).
export default {
  contextable: {
    validate: [
      { 
        ...
        modelData: {},
      }
    ]
  },
  ...
}
  1. Two new reactive methods are also available - $build and $populate.
// using the $build method
export default {
  contextable: {
    ...
  },
  beforeCreate () {
    this.user.book = {title: 'asdasd'}; // sets field's data but removes reactivity
    this.user.books = [{title: 'asdasd'}]; // sets field's data but removes reactivity
    this.user.$build(); // rebuilds model reactivity
  }
}
// using the $populate method
export default {
  contextable: {
    ...
  },
  beforeCreate () {
    this.user.$populate({ // sets model fields and runs $build method
      name: null,
      book: {},
      books: [{}]
    });
  }
}
  1. The new $build method will help you build a form with dynamic fields as well. See the example for details.

Features have been published and a new version of this package is now available for download. Please let me know if this works for you.

Cool :)