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

Issue with change detection mechanism not detecting change for local template variable and unclear documentation #6618

Closed
user414 opened this issue Jan 21, 2016 · 12 comments

Comments

@user414
Copy link

user414 commented Jan 21, 2016

Here is the plunk, http://plnkr.co/edit/moyGtR3UE7JymtSbQIXX?p=info. Basically form previous conversation and the documentation I would expect this

<input #uploadFile type="file" name="uploadFile"/> 
<input type="text" [attr.value]="uploadFile.value" readonly/>      

To work but it doesn't, similarly any other such binding don't work neither. There's no example of such use of local variable in the documentation only event binding with function call, is that the only supported use case at this time?

@ericmartinezr
Copy link
Contributor

@user414
Copy link
Author

user414 commented Jan 21, 2016

@ericmartinezr I don't believe that's the same, in that thread the poster tries to set the value of the input type="file" which I was aware of the issues with that. Whereas, I'm trying to set the value of a plain text field with reading the value of the input file which is allowed.

@ericmartinezr
Copy link
Contributor

@user414 to make my point more clear https://jsfiddle.net/bhy7n941/ , if I understand correctly you can't access the value property of an input type file

@user414
Copy link
Author

user414 commented Jan 21, 2016

@ericmartinezr Because of the iframe in jsfidle you can't even do document.getElementById("text") in the console. However, if I have the same code in a plain html page you can access the value property no problem, just go in the javascript console and type

document.getElementById('file').value

and I get the value. I think my example was not choosen very well the file just come and create confusion this is the same and doesn't work

<div>
      <input #test type="text"/> 
      <input type="text" [value]="test.value" readonly/>             
</div>

From the documentation and binding I would expect the second field to be bound the DOM "value" property of the first field but it is not. I don't think the file here is important.

@user414
Copy link
Author

user414 commented Jan 21, 2016

To go further, to fix the above I would need to do this

<input #uploadFile type="text" (input)="target.value = uploadFile.value">
<input #target type="text"/>  

This works, but I don't think I would need the extra input to make it work according to my understanding of how the binding,interpolation works, which obviously is wrong:-) To make the above work with file (change) works instead, but still don't understand why it's needed in the first place.

@shlomiassaf
Copy link
Contributor

@user414 I believe it behaves exactly as it should, actually there is a binding but the change detection doesn't kick in.

In your 2nd example:

      <input #test type="text"/> 
      <input type="text" [value]="test.value" readonly/>      

The 2nd input box value property is indeed bounded to the expression test.value

The reason you don't see any change is because the change detector is smarrt enough to assume that it shouldn't kick in.

There is nothing registered in the change detector, no emitter is set so nothing gets checked.
A web application changes as a reaction to something, this is a the rule.
It can be a timeout, event, xhr response, RAF etc... so angular finds those events and triggers change detection when they happen.

In the case above there is no listener registered at all! so why should angular check for something...

To understand better, look at this example:

      <input #test type="text"/> 
      <input type="text" [value]="test.value" readonly/>             
      <p>===============</p>
      <input #notRelated type="text" (input)="1+1">

This is the same as the first example I wrote, just added another input at the bottom that is actually bound to nothing but it uses angular to register to an input an basically do nothing.

Now, write 123 in the first input box, nothing happens!
Write ABC in the 3rd input box, and there you have it, the 2nd input box will show 123.

What happened? angular kicked in the change detector which found a change.

@user414
Copy link
Author

user414 commented Jan 21, 2016

@shlomiassaf That was my guess as to what's happening but seems inconsistent to me. Since if the variable is in my javascript and I do any of the below

<img src="{{heroImageUrl}}">
<img [src]="'' + heroImageUrl">

If I then change the value heroImageUrl it will automatically be reflected, whereas in my example it is not. Both are binding exactly the same, from my point of view I can see no indication anywhere that one trigger this "change detector" mechanism and the other doesn't. In my opinion

The reason you don't see any change is because the change detector is smarrt enough to assume that it shouldn't kick in.

Is more a bug then a feature. If that's the way it was intended, I think we need to clarify the documentation. IMHO I would rather they all kick in this "change detector" mechanism, it would be clearer.

@pkozlowski-opensource
Copy link
Member

@user414 I think that your confusion steams from the fact that you assume that this is an existence of a binding that kicks off change detection. In reality it is subscription to an event (DOM, XHR etc.) that triggers change detection. In your example you are having a template where there is no event handler so it is like saying: "there are no user actions that are interesting here so I won't be updating model, so there is no reason to change anything on a page".

The basic idea is: UI is driven by model changes. If there are no model changes no need to update UI. No user actions I'm subscribing too = no model updates => no need to repaint UI.

I'm going to close this one as things work as intended.

@shlomiassaf
Copy link
Contributor

@user414 Change detection is a delicate thing, you need to make sure you don't miss but at the same time don't over hit.

I think @pkozlowski-opensource expressed it the best way, a binding is not a contract for change detection.

The core assumption in Angular and Zone is that everything is driven by events... so setTimeout, dom events, XHR etc all of these will trigger change detection (most of the time).

Since each component is an isolated unit and data flow is known (input, output) Angular knows exactly what to listen to, on a component basis, its quite smart! you just need to show intent.

You believe that every event should trigger change detection, this will result in poor performance and cancel the isolation angular lives in.

@user414
Copy link
Author

user414 commented Jan 21, 2016

@pkozlowski-opensource Thanks that clarifies the whole thing. Something to that effect could be added in the "template binding" section of the tutorial/documentation and I think it would be helpful.

@shlomiassaf It hadn't crossed my mind, but I agree with you about the performance of doing everything. However, I think perhaps this use case could be added in the smart detection. Unless I'm mistaken, I can't see any other behavior that could be expected from that code beside having change detection kicking in. Regardless, with updated documentation with an explanation similar to what @pkozlowski-opensource suggested that should avoid confusion.

@pkozlowski-opensource @shlomiassaf So should I change this into a feature request to add this use case into the detection mechanism and/or another issue to update the documentation?

@user414
Copy link
Author

user414 commented Jan 21, 2016

@shlomiassaf I also like your sentenced

a binding is not a contract for change detection.

I think that could be also added in the template binding section of the tutorial/documentation and that would be helpful. Since binding can indirectly trigger change detection, it can be confusing when reading the documentation that all binding trigger this indirect change detection. In addition, having a little blurb as to what kick in this change detection automatically, or the process by which it is triggered would be helpful. I reiterate what I said earlier, that having two binding with one that create this indirect change detection and another binding that doesn't while from a user point of view looking very similar can be confusing.

@user414 user414 changed the title Local template variable is unavailable when it seems like it should Issue with change detection mechanism not detecting change for local template variable and unclear documentation Jan 22, 2016
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants