Mobx: Computed is not firing

Created on 5 Feb 2019  Â·  8Comments  Â·  Source: mobxjs/mobx

For given code when onFieldChange is called, the computed property named editedFields is not updating. Any help will be appreciated.

class FormsBaseStore {
    constructor() {
        this.form = {};
    }

    //Filters the form fields that were edited
     @ computed get editedFields() {
        let arrEdited = [];

        const fields = this.form.fields;

        for (var field in fields) {
            (fields[field].isEdited)
             ? arrEdited.push(fields[field])
             : null;
        }

        return arrEdited;
    }

    //Use it to instantiate values to the form
     @ action setFormData(fieldsObj) {

        const {
            id,
            ...fields
        } = fieldsObj;

        let newFieldsObj = {};

        for (var field in fields) {
            const newObjValue = (fields[field].value !== null && fields[field].value !== undefined) ? fields[field].value : "";
            const newObjRule = (fields[field].rule) ? fields[field].rule : null;
            (newObjValue !== undefined && newObjValue !== null && newObjValue !== "")
             ? newFieldsObj[field] = new FormField(field, newObjValue, )
                 : newFieldsObj[field] = new FormField(field, newObjValue);
        }

        this.form = new Form(newFieldsObj, id);

    }

    //this method is called on the onChange event of the form elements
     @ action.bound onFieldChange(field, value) {

        var fieldName = (typeof(field) === "string") ? field : field.target.name;
        const form = this.form;
        const formField = form.fields[fieldName];

        //Setting item value
        (value == undefined || value == null) ? value = "" : null;
        let fieldValue = (value !== undefined && value !== "") ? value : (typeof(field) === "string") ? "" : field.target.value;
        (fieldValue == undefined || fieldValue == null) ? fieldValue = "" : fieldValue;

        formField.value = fieldValue;

        //controlling edition
        this.checkIfEdited(formField);

    }

    checkIfEdited = (field) => {
        let value = field.value;
        let defaultValue = field.defaultValue;

        if (isObservable(field.defaultValue)) {
            defaultValue = toJS(field.defaultValue);
            value = toJS(field.value);
        }

        if (defaultValue !== value && !Array.isArray(defaultValue) && typeof defaultValue !== 'object') {
            field.isEdited = true;
        } else if ((Array.isArray(defaultValue) || typeof defaultValue === 'object') && !isEqual(defaultValue, value)) {
            field.isEdited = true;
        } else if (!field.isValid) {
            field.isEdited = true;
        } else {
            field.isEdited = false;
            field.container = null;
        }
    }

}

class Form {
    constructor(fields, id) {
        this.fields = fields;
        this.meta.id = id;
    }

     @ observable fields = {};
     @ observable meta = {
        id: null
    }
}

class FormField {
     @ observable name;
     @ observable value;
     @ observable isEdited;

    constructor(name = null, value = "", isEdited = false) {

        this.name = name;
        this.value = value;
        this.isEdited = isEdited;
    }

}

All 8 comments

Please create a codesandbox.io example

On Tue, Feb 5, 2019, 2:41 PM gs-trader notifications@github.com wrote:

For given code when onFieldChange is called, the computed property named
editedFields is not updating. Any help will be appreciated.

class FormsBaseStore {
constructor() {
this.form = {};
}

//Filters the form fields that were edited
@ computed get editedFields() {
let arrEdited = [];

  const fields = this.form.fields;

  for (var field in fields) {
      (fields[field].isEdited)
       ? arrEdited.push(fields[field])
       : null;
  }

  return arrEdited;

}

//Use it to instantiate values to the form
@ action setFormData(fieldsObj) {

  const {
      id,
      ...fields
  } = fieldsObj;

  let newFieldsObj = {};

  for (var field in fields) {
      const newObjValue = (fields[field].value !== null && fields[field].value !== undefined) ? fields[field].value : "";
      const newObjRule = (fields[field].rule) ? fields[field].rule : null;
      (newObjValue !== undefined && newObjValue !== null && newObjValue !== "")
       ? newFieldsObj[field] = new FormField(field, newObjValue, )
           : newFieldsObj[field] = new FormField(field, newObjValue);
  }

  this.form = new Form(newFieldsObj, id);

}

//this method is called on the onChange event of the form elements
@ action.bound onFieldChange(field, value) {

  var fieldName = (typeof(field) === "string") ? field : field.target.name;
  const form = this.form;
  const formField = form.fields[fieldName];

  //Setting item value
  (value == undefined || value == null) ? value = "" : null;
  let fieldValue = (value !== undefined && value !== "") ? value : (typeof(field) === "string") ? "" : field.target.value;
  (fieldValue == undefined || fieldValue == null) ? fieldValue = "" : fieldValue;

  formField.value = fieldValue;

  //controlling edition
  this.checkIfEdited(formField);

}

checkIfEdited = (field) => {
let value = field.value;
let defaultValue = field.defaultValue;

  if (isObservable(field.defaultValue)) {
      defaultValue = toJS(field.defaultValue);
      value = toJS(field.value);
  }

  if (defaultValue !== value && !Array.isArray(defaultValue) && typeof defaultValue !== 'object') {
      field.isEdited = true;
  } else if ((Array.isArray(defaultValue) || typeof defaultValue === 'object') && !isEqual(defaultValue, value)) {
      field.isEdited = true;
  } else if (!field.isValid) {
      field.isEdited = true;
  } else {
      field.isEdited = false;
      field.container = null;
  }

}

}

class Form {
constructor(fields, id) {
this.fields = fields;
this.meta.id = id;
}

@ observable fields = {};
@ observable meta = {
id: null
}
}

class FormField {
@ observable name;
@ observable value;
@ observable isEdited;

constructor(name = null, value = "", isEdited = false) {

  this.name = name;
  this.value = value;
  this.isEdited = isEdited;

}

}

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx/issues/1891, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAIrcqbEZqaiOyDEZRjRTFrHyBbtR-iTks5vKeyUgaJpZM4akCEt
.

@gs-trader Base on the code ( and as @mattruby said, codesandbox would be better)

  1. You computed is based on non observable data.
    Your fields param, is Form's class member
    doing this.form = new Form(newFieldsObj, id); in class FormsBaseStore, without making it an observable in this class also, will break observability.
    see the docs section Don't copy observables properties and store them locally

  2. computing other stores on a new store has some limits. you can see https://github.com/mobxjs/mobx/issues/715

@mattruby and @ItamarShDev Thanks for your quick responses. After your suggestion i created example version on codesandbox and it works there as is. So there is something in my code base that causing it.
Also to my surprise when this.forms is updated to @observable form = {}, the code base starts working. So probably there is some anomaly in code thats is responsible for this strange behavior.

@gs-trader Happy to hear that you manages to make it work in the codesandbox.
Hope you'll manage to fix it in your codebase too.

Seems like this issue should be closed.

@gs-trader yes, form must be declared as observable, otherwise mobx cannot track reassignments to that property! And you are reassinging it in setFormData: this.form = new Form(newFieldsObj, id);

A rule of thumb you can use: either all fields should be readonly or @observable. If it is neither, than you have something for which no changes can be tracked. Marking that field as readonly would have resulted in a compile error in typescript in the setFormData method.

@gs-trader if this matter is solved for you, please consider closing the issue

Closing for inactivity

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs or questions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bakedog417 picture bakedog417  Â·  3Comments

cafreeman picture cafreeman  Â·  4Comments

giacomorebonato picture giacomorebonato  Â·  3Comments

etinif picture etinif  Â·  3Comments

kirhim picture kirhim  Â·  3Comments