Skip to content

Nested models and reactivity #12

Description

@riker09

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions