Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix($parse) - Allow setterFn to bind correctly to promise results #2854

Closed
wants to merge 3 commits into from

Conversation

jimmydivvy
Copy link
Contributor

When binding the result of a promise directly to an ng:model directive,
getterFn successfully extracts the data from the promise by traversing
the '$$v' attribute.

However the setterFn was not successfully traversing to the $$v
attribute, and instead writing model updates directly on the promise
itself.

The subsequent apply/digest phase of Angular was then pulling the
original value from the promise and applying it back into the viewState,
thus simulating a read-only field.

In summary, setterFn was writing to the root of the promise, while
getterFn was reading from the '$$v' component.

Fixed by modifying setterFn to unwrap promises if found and read $$v.

If promises have not been resolved yet, bindings will function as they
previously did (act as a read-only field). This appears to be more of a
side effect than intentional design in the existing codebase, however
I kept this behaviour in this patch to minimize the chance of breaking
existing projects.

Closes #1827

This issue affects the 1.0.x branch as well and would be worth backporting.
(Cleanly cherry-picks against 1.0.7 with all tests passing).

Also see: http://stackoverflow.com/questions/16883239/angularjs-ngmodel-
field-is-readonly-when-bound-to-q-promise/16883387

When binding the result of a promise directly to an ng:model directive,
getterFn successfully extracts the data from the promise by traversing
the '$$v' attribute.

However the setterFn was not successfully traversing to the $$v
attribute, and instead writing model updates directly on the promise
itself.

The subsequent apply/digest phase of Angular was then pulling the
original value from the promise and applying it back into the viewState,
thus simulating a read-only field.

In summary, setterFn was writing to the root of the promise, while
getterFn was reading from the '$$v' component.

Fixed by modifying setterFn to unwrap promises if found and read $$v.

If promises have not been resolved yet, bindings will function as they
previously did (act as a read-only field). This appears to be more of a
side effect than intentional design in the existing codebase, however
I kept this behaviour in this patch to minimize the chance of breaking
existing projects.

Closes angular#1827

Also see: http://stackoverflow.com/questions/16883239/angularjs-ngmodel-
field-is-readonly-when-bound-to-q-promise/16883387
function unwrapPromise(obj){

// If we'v been passed a promise
if( obj.then ){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coding style

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to adjust. Can you elaborate on the issue?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You seem to be using a different style than the rest of this file (if (is('(){}[].,;:?')) vs if( obj.then ){ for example)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ta. I've gone with the style

if(condition) {
// Block
}

which appears to be commonly used throughout that file?

I was missing a null check (which I've just added), and have expanded on my function comments a bit more. Closer to what's expected? (The if() statement is now identical to other promise check within the same file)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm talking about spacing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right. That's obvious now that I see it. Will adjust.

@aluedeke
Copy link

we are experiencing this bug in our app would be nice if it could be merged into the stable branch

@matthewrk
Copy link

+1 as someone relatively new to Angular this took me a day to track down and workaround, surprised more people haven't run into it.

@scamden
Copy link

scamden commented Jul 10, 2013

+1

1 similar comment
@atomical
Copy link

+1

@petebacondarwin
Copy link
Contributor

-1 - personally I don't like the idea of auto-unwrapping promises. It hides what is really going on.

@petebacondarwin
Copy link
Contributor

This is a feature not a fix...

PR Checklist (Minor Feature)

  • Contributor signed CLA now or in the past (if you just signed, leave a comment here with your real name for cross reference)
  • Feature improves existing core functionality
  • API is compatible with existing Angular apis and relevant standards (if applicable)
  • PR doesn't contain a breaking change
  • PR contains unit tests
  • PR contains e2e tests (if suitable)
  • PR contains documentation update
  • PR passes all tests on Travis (sanity)
  • PR passes all tests on ci.angularjs.org (cross-browser compatibility)
  • PR is rebased against recent master
  • PR is squashed into one commit per logical change
  • PR's commit messages are descriptive and allows us to autogenerate release notes (required commit message format)
  • All changes requested in review have been implemented

Sorry, something went wrong.

@petebacondarwin
Copy link
Contributor

@zoomzoom83 - can you sign the CLA?

@jimmydivvy
Copy link
Contributor Author

@petebacondarwin CLA Signed - "James Davies"

@jimmydivvy
Copy link
Contributor Author

This is a feature not a fix...
-1 - personally I don't like the idea of auto-unwrapping promises. It hides what is really going on.

At the moment, AngularJS appears to unwrap promises automatically in all other scenarios - from an end-developers perspective, this comes across as a bug when contrasted with other behaviour. I'm not sure if this particular scenario was intentional or not, but it doesn't appear to be.

I'm aware this has been discussed on the forums and the existing promise unwrapping functionality has been considered for removal - but in the meantime it makes sense to add this in for consistency. Going in the opposite direction would break existing apps.

(My vote would be to keep this functionality - I'm making very heavy use of it, and it dramatically simplifies the code and removes a lot of bug-prone boilerplate. There's minimal confusion as to what's happening).

@jeffbcross
Copy link
Contributor

We're going to discuss this feature as a team. There are three possible outcomes:

  1. We don't want this, because getters may have been a mistake.
  2. Chirayu's implementation is good (throwing an error with premature set on an unresolved promise).
  3. This works without promises, create a temp object used for writes prior to promise resolving, destroy object after resolution and replace with resolved value.

@chirayuk
Copy link
Contributor

Landed as 61906d3

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

Successfully merging this pull request may close these issues.

Bug with asynchronous text field updates
9 participants