angular: angular 9 / Ivy => async 'as' leads to error
🐞 bug report
Affected Package
https://github.com/mpalourdio/ng2
Is this a regression?
Yes, the previous version in which this bug was not present is angular8@latest.
Description
<div id="app" *ngIf="(applicationsList$ | async) as applicationsList">
<app-search-filter [(applicationsList)]="applicationsList"></app-search-filter>
</div>
yarn start
Error : Property 'applicationsList' does not exist on type 'ChildComponent'. Did you mean 'applicationsList$'?
Disabling Ivy leads to
ERROR in Cannot assign value "$event" to template variable "applicationsList". Template variables are read-only.
🔬 Minimal Reproduction
- clone https://github.com/mpalourdio/ng2
- run
ng update @angular/cli @angular/core --next
- yarn start
🔥 Exception or Error
Property 'applicationsList' does not exist on type 'ChildComponent'. Did you mean 'applicationsList$'?
Disabling Ivy leads to
ERROR in Cannot assign value "$event" to template variable "applicationsList". Template variables are read-only.
🌍 Your Environment
Angular Version:
Angular CLI: 9.0.0-rc.6
Node: 12.13.0
OS: linux x64
Angular: 9.0.0-rc.6
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.0-rc.6
@angular-devkit/build-angular 0.900.0-rc.6
@angular-devkit/build-optimizer 0.900.0-rc.6
@angular-devkit/build-webpack 0.900.0-rc.6
@angular-devkit/core 9.0.0-rc.6
@angular-devkit/schematics 9.0.0-rc.6
@ngtools/webpack 9.0.0-rc.6
@schematics/angular 9.0.0-rc.6
@schematics/update 0.900.0-rc.6
rxjs 6.5.3
typescript 3.6.4
webpack 4.41.2
EDIT (by gkalpak)
Adding the conclusions from https://github.com/angular/angular/issues/34405#issuecomment-566134215 (after the discussion below) here for visibility:
The issue is that this breaking change is not (clearly) documented, so let’s keep this open to track that 😃
Action items:
- Figure out what the breaking change is exactly (incl. how template variables created via
as
are different from other template variables).- Document that.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 21 (10 by maintainers)
hello in my case my mistake was because I had this like this:
What I did to solve was to change the value as follows:
hola en mi caso mi error era por que tenia esto asi :
lo que hice para solventar fue cambiar el value a la siguiente manera:
The error in Ivy was incorrect, this has been resolved in #34339 (which just missed the rc.6 release).
Other than that: what @gkalpak said 😃
Looks like it was made intentionally according to Ivy Compatibility Guide
The issue is that this breaking change is not (clearly) documented, so let’s keep this open to track that 😃
Action items:
as
are different from other template variables).That’s really clear for me! Thanks a lot for these great explanation, and for taking time to investigate. So far, again, that’s really a quick and dirty project and I wanted to give feedback on the migration path.
Feel free to close this issue, as it’s really not an issue ('cause I am the issue :p).
Thanks again!
I created this StackBlitz project and it does indeed work with v8 💥 Maybe the variables created via
as
were treated differently than other template-only variables in v8.So, this sounds like a breaking change that needs to be documented. @JoostK, do you know what’s the case for template variables created via
as
in v8 vs v9?@mpalourdio: This seems like a big anti-pattern (and I hope it is not as common as you say 😅).
The main issue I see is that the
[(...)]
binding indicates a two-way-binding relation. Typically, the expectation is that the value is passed into the child-component (the[...]
part of the binding) and the child component reacts to this.So, my expectation when I first looked at the component (and the reason I immediately thought “this can’t be right” 😁) was that
applicationList
goes into the child-component (due to the[...]
part of the binding), then gets filtered inside the child-component and emitted back, the filtered list gets assigned to the templateapplicationList
variables (via the(...)
part of the binding), then the filteredapplicationList
gets back into the child-component (via the[...]
part of the binding), where it gets filtered again and emitted back, etc.The only reason the component works in this case is that it uses the
[...]
binding to initialize its internal state and does not react to changes in the input value. This is, of course, an implementation detail of the child-component and the consumer (parent component) shouldn’t have to know about it. Hence, from the consumer’s perspective, using[(...)]
looks very unintuitive.In addition, you open yourself up to all sorts of subtle bugs, such as:
applicationList$
emits another array, thesearch-filter
component will still be using the original list, giving incorrect results.Of course, you can work around them, but the point is that the parent-component behavior may change due to the implementation of a child-component and detailed knowledge of the child-component’s implementation is needed in order to make the parent-component/template work as intended.
It is not clear what you are trying to achieve (i.e. what the expected/ideal behavior would be) with
[(applicationsList)]="applicationsList"
.Just to be clear, the error is not related to
async ... as
(as mentioned in the title), but to the following bit of code:This is syntactic sugar for a two-way binding. It is equivalent to:
It’s this second part (
(applicationsListChange)="applicationsList = $event"
) that seems to be causing the error. It is not clear what you are trying to achieve by setting the templateapplicationList
variable to the filtered result of itself. Maybe the example you gave is contrived and does not reflect the actual usecase. Could you, please, clarify the usecase?(Finally, as mentioned in the guide, the compiler would previouly ignore the assignments, so this change will not break something that used to work before. It will only turn silent failing at runtime to hard failing at compile time.)
@mpalourdio I am amazed this ever worked!