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

You attempted to update `_errors` on `changeset:[object Object]` #573

Open john-griffin opened 3 years ago

john-griffin commented 3 years ago

Not sure if this is a bug or a feature request - happy to provide a reproduction if needed, would really appreciate some feedback.

We have been using the following pattern in our components for a while now:

import Component from '@glimmer/component';
import Changeset from 'ember-changeset';
import lookupValidator from 'ember-changeset-validations';
import InfoValidations from '../validations/info';

export default class InfoFormComponent extends Component {
  constructor() {
    super(...arguments);

    this.changeset = new Changeset(
      this.args.model,
      lookupValidator(InfoValidations),
      InfoValidations
    );

    this.changeset.validate();
  }
}

This causes the following deprecation warning in Ember 3.23:

DEPRECATION: You attempted to update `_errors` on `changeset:[object Object]`, but it had already been used previously in the same computation.  Attempting to update a value after using it in a computation can cause logical errors, infinite revalidation bugs, and performance issues, and is not supported.

`_errors` was first used:

- While rendering:
  application
    index
      info-form

I believe this is because internally the changeset is tracking _errors and it is being updated by the validate call.

How do you suggest we restructure things given we would like to immediately validate the changeset when the component is invoked?

Alternatively do you think it's worth considering adding an option to ember-changeset to immediately validate a changeset when initialized?

wozny1989 commented 1 year ago

After upgrade to Ember 4.4 we see the same problem but it completely crash app. Currently we're using workaround with next:

import { next } from '@ember/runloop';
// ...

constructor() {
  super(...arguments);

  this.changeset = new Changeset(
    this.args.model,
    lookupValidator(InfoValidations),
    InfoValidations
  );

  next(this, () => this.changeset.validate());
}

But it not looks pretty... any idea how to solve it?

Alternatively do you think it's worth considering adding an option to ember-changeset to immediately validate a changeset when initialized?

In my opinion it will be a good option!

wozny1989 commented 1 year ago

Ahh read documentation from top to bottom... :)
This is a solution and issue can be closed:

constructor() {
  super(...arguments);

  this.changeset = new Changeset(
    this.args.model,
    lookupValidator(InfoValidations),
    InfoValidations,
    { initValidate: true }
  );
}
snjpost commented 1 month ago

Ahh read documentation from top to bottom... :) This is a solution and issue can be closed:

constructor() {
  super(...arguments);

  this.changeset = new Changeset(
    this.args.model,
    lookupValidator(InfoValidations),
    InfoValidations,
    { initValidate: true }
  );
}

Very helpful solution, thank you. It also worked with the helper for me.

{{changeset model this.validate initValidate=true}}

But where can I find the documentation about initValidate?

wozny1989 commented 1 month ago

But where can I find the documentation about initValidate?

@snjpost Oh, it's really not in this documentation, but it should be. I found it in this docs: https://www.npmjs.com/package/validated-changeset