Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aurelia changes model values bound to input fields. #288

Closed
NateRedding opened this issue Jan 5, 2016 · 10 comments
Closed

Aurelia changes model values bound to input fields. #288

NateRedding opened this issue Jan 5, 2016 · 10 comments

Comments

@NateRedding
Copy link

I am seeing some odd behavior where Aurelia seems to change some of my model values from null to ''.

I have a form with input fields bound to properties of a model object. At one point in my code, I need to replace the existing object with a new model object. After doing so, Aurelia adds new getters/setters onto the model object since this new model object doesn't have any yet. If the new model object contains null values for any of the bound properties, the getters now return an empty string '' instead of null.

This seems like an issue to me, but maybe I am just doing something wrong?

I have created a fork of the latest skeleton-navigation project which exemplifies this issue. The only modified files are welcome.html and welcome.js. https://github.com/NateRedding/skeleton-navigation/tree/nulls-changed-to-empty-strings.

Essentially, I am trying to add dirty checking to the form, so I save a clean copy of my model. But, when I go to compare the clean model to the actual model, they aren't the same because the actual model now gives empty strings instead of nulls after the getters are added.

@EisenbergEffect
Copy link
Contributor

@jdanyow Can you look into this? I suspect it has to do with how inputs work.

@jdanyow
Copy link
Contributor

jdanyow commented Jan 5, 2016

@EisenbergEffect / @NateRedding - I did some digging, there's a couple things going on here...

The primary issue is the input element's value property only stores strings. The element converts null/undefined to empty string. The binding is supposed to keep the element and model in sync which is why empty string is eventually assigned to the model.

If you really want to bind null to input.value and preserve the null on the model side, you could use a value converter:

export class NullToEmptyStringValueConverter {
  toView(value) {
    return value === null ? '' : value;
  }
  fromView(value) {
    return value === '' ? null : value;
  }
}
<input type="text" value.bind="firstName | nullToEmptyString">

Using this approach will mean empty string will never be assigned to the model- only null or a non-empty string.

All that said, one could argue, why is my model being updated if the user never makes a change to the input element? It boils down to this line of code which has been around from the beginning. The observer for the input element publishes change events when it's assigned a new value. When the input is assigned null, the input's value becomes empty string, it then publishes a change event with newValue = '' resulting in the model being assigned empty string.

Maybe we should update the logic from this:

setValue(newValue) {
  this.element[this.propertyName] =
    (newValue === undefined || newValue === null) ? '' : newValue;

  this.notify();
}

to something like this:

setValue(newValue) {
  newValue = newValue === undefined || newValue === null ? '' : newValue;
  if (this.element[this.propertyName] !== newValue) {
    this.element[this.propertyName] = newValue;
    this.notify();
  }
}

As an aside, take a look at aurelia/templating-resources#160 for another dirty tracking approach.

@EisenbergEffect
Copy link
Contributor

@jdanyow How do you feel about making the change above?

@NateRedding
Copy link
Author

Thank you @jdanyow for taking a look at this so quickly! You all are awesome!

I had seen the other approach, but in my case, I really need to compare the models since I have subforms that show up in modals for nested objects. So, I need to know if my whole model has changed, or not... not really just if the primary form has changed.

Your value converter approach could work... feels almost as painful as my other approach, though, which was to manually convert nulls to empty strings before I save off my pristine copy.

@jdanyow
Copy link
Contributor

jdanyow commented Jan 5, 2016

@EisenbergEffect I think the change is safe to make and will help reduce the confusion around this particular element property. Will target this release.

@NateRedding understood, this is a tricky one. These kinds of issues come up with elements that coerce values to strings. Food for thought: in a perfect world, with the initial model value being null, what do you expect the model value to be after the user enters some text and then clears the input? If this was the only change they made to the form, would you expect to be in a "dirty" or "pristine" state?

@NateRedding
Copy link
Author

@jdanyow In a perfect world, I would expect the form to be "pristine" again. However, realistically, I am fine with nulls being changed to empty strings after a value has been entered and backed out. I have seen plenty of form dirty checking implementations where once the form is dirty, it stays that way. In my experience, this hasn't really caused many complaints from users as long as they have a way to reset the form back to a pristine state.

@jdanyow
Copy link
Contributor

jdanyow commented Jan 5, 2016

ok excellent- so the fix we're planning should work for you- will post back here when it's in-place.

@NateRedding
Copy link
Author

Thanks again! What's the release schedule looking like for this?

@NateRedding
Copy link
Author

@jdanyow You mentioned above that if the user enters a value in a text field that was originally null, and backs out the change, then the value might be an empty string '' instead of the original null. Now, my assumption was that this would happen if the user uses backspace to clear out the original value. However, I am seeing similar behavior that I wanted to run by you. Here is the scenario:

  1. value is initially null
  2. user types a value into the text input field
  3. user hits the form reset button which restores the entire model with a clean copy where the value is null
  4. the value is subsequently changed to an empty string '' by Aurelia (it would seem)

Does it seem like the change made above may result in this occurrence, or do I have some other issue going on?

@TonyLugg
Copy link

This is a very similar issue to what I reported last month here: aurelia/binding#617

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants