adopted-ember-addons / ember-changeset

Ember.js flavored changesets, inspired by Ecto
http://bit.ly/ember-changeset-demo
MIT License
431 stars 141 forks source link

Allow to call execute() even if isValid = false #559

Open RuslanZavacky opened 3 years ago

RuslanZavacky commented 3 years ago

Use case that I am currently working on:

Checkbox to agree with Terms of Use. I add validator on that checkbox, that it should be "checked". If it is not checked - I show an error, that "they, you have to agree with it". So if I have such validator, calling execute() method, won't do anything, as isValid will be false. In cases like that, It should be allowed to update changeset even if the value will result in error.

My values for form fields comes from the changeset object. In cases like input type="text", input gets updates in DOM and then it propagates to changeset. With checkbox, it is a bit different, as it is more DDAU than text one.

Here is a code in question:

  execute() {
    let oldContent;
    if (this.isValid && this.isDirty) {
      let content = this[CONTENT];
      let changes = this[CHANGES];

      // keep old values in case of error and we want to rollback
      oldContent = buildOldValues(content, this.changes, this.getDeep);

      // we want mutation on original object
      // @tracked
      this[CONTENT] = mergeDeep(content, changes, { safeGet, safeSet });
    }

    this[PREVIOUS_CONTENT] = oldContent;

    return this;
  }

@snewcomer do you have any ideas on this case?

The only proposal I can think of now, is to allow to pass a forceUpdate or similar, to ignore isValid check.

Or, maybe I am missing point completely, and changeset.get('name') is actually an incorrect way to get "latest" value of a changeset?

snewcomer commented 3 years ago

@RuslanZavacky Lets see if we can fix or get to the root of the issue.

Assuming the value on the underlying model is isAccepted: boolean - you can add a change to the changeset with changeset.set('isAccepted', ...) and retrieve the "not yet applied to underlying model" value with changeset.get. You can do this all day long. Even with unknown keys on the changeset - changeset.set('randomKey', ...).

execute gives you certainty the any state with errors on the changeset will not be applied to the underlying model. In your case, it seems like you don't want to continue unless the Terms of Use is checked (isAccepted: true).

Is your click action responding with changeset.execute when it should be changeset.set?