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

Nested models and reactivity

riker09 opened this issue · comments

I'm not quite sure if this is an issue with vue-rawmodel or Vue.js. but it seems that the support for nested models is limited or broken. Please see this demo for reference: https://codepan.net/gist/a7fe8b888cf6b5e92c84350e9ed22fbc

Basically I have two reactive models, where one model is a child of the other.

class MyModel extends ReactiveModel {
    name: string;
    locked: boolean;
    settings: Settings;

    public constructor({parent, ...data} = {}) {
        super({parent});

        this.defineField('name', { type: 'String', defaultValue: '' });
        this.defineField('locked', { type: 'Boolean', defaultValue: false });
        this.defineField('settings', { type: Settings, defaultValue: function() { return new Settings(); } });
    }
}

class Settings extends ReactiveModel {
    dummy: boolean;

    public constructor({parent, ...data} = {}) {
        super({parent});

        this.defineField('dummy', { type: 'Boolean', defaultValue: true });
    }
}

I have a custom form component named form-toggle looking like this:

Vue.component('form-toggle', {
  props: {
    value: { type: Boolean },
    onValue: { type: Boolean, default: true },
    offValue: { type: Boolean, default: false }
  },
  template: `<div>
    	<div class="toggle" :class="{on: isOn}">
        <div class="val" :class="{active: !isOn}" @click="turnItOff">off</div>
        <div class="val" :class="{active: isOn}" @click="turnItOn">on</div>
        <div class="marker"></div>
    	</div>
    </div>`,
  computed: {
    isOn: function() { return this.value === this.onValue }
  },
  methods: {
    turnItOn: function() { this.$emit('input', this.onValue); },
    turnItOff: function() { this.$emit('input', this.offValue); }
  }
});

And now we put it all together:

new Vue({
  el: "#app",
  data: {
    hasChanges: false,
    myModel: new MyModel()
  },
  computed: {
    status: function() { return this.hasChanges ? 'changed' : 'vanilla' }
  },
  methods: {
    stateChanged: function() {
      this.hasChanges = this.myModel.isChanged();
    },
    reset: function() {
      this.myModel.$rollback();
      this.hasChanges = this.myModel.isChanged();
    }
  }
});
</script>

For conveniance here's the template:

<div id="app">
  <h2>Model status: {{ status }}</h2>
  <div>
    <label for="name">
      Name:
      <input id="name" v-model="myModel.Name" @input="stateChanged" />
    </label>
  </div>
  <div>
    <p>Locked: {{myModel.locked}}</p>
    <form-toggle v-model="myModel.locked" @input="stateChanged"></form-toggle>
  </div>
  <div>
    <p>settings.dummy: {{myModel.settings.dummy}}</p>
    <form-toggle v-model="myModel.settings.dummy" @input="stateChanged"></form-toggle>
  </div>
  <button @click="reset">Reset</button>
  
  <h2>
    Raw output:
  </h2>
  {{ myModel }}
</div>

When I change the value of a non-nested property I'm unable to change the value of a nested property until I either reset ($rollback) the model or change the values back to their original state.

It feels like I'm missing something very obvious, but I've been trying to figure this one out for quite some time now. Hopefully you can shine some light on this?