fix(compiler): generate view restoration for keyed write inside template listener (#42603)
If an implcit receiver is accessed in a listener inside of an `ng-template`, we generate some extra code in order to ensure that we're assigning to the correct object. The problem is that the logic wasn't covering keyed writes which caused it to write to the wrong object and throw an assertion error at runtime. These changes expand the logic to cover keyed writes. Fixes #41267. PR Close #42603
This commit is contained in:
committed by
Dylan Hunn
parent
8793d1a046
commit
f52df99fe3
+52
@@ -584,3 +584,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
|
||||
****************************************************************************************************/
|
||||
export {};
|
||||
|
||||
/****************************************************************************************************
|
||||
* PARTIAL FILE: implicit_receiver_keyed_write_inside_template.js
|
||||
****************************************************************************************************/
|
||||
import { Component, NgModule } from '@angular/core';
|
||||
import * as i0 from "@angular/core";
|
||||
export class MyComponent {
|
||||
constructor() {
|
||||
this.message = '';
|
||||
}
|
||||
}
|
||||
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
||||
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, selector: "my-component", ngImport: i0, template: `
|
||||
<ng-template #template>
|
||||
<button (click)="this['mes' + 'sage'] = 'hello'">Click me</button>
|
||||
</ng-template>
|
||||
`, isInline: true });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{
|
||||
selector: 'my-component',
|
||||
template: `
|
||||
<ng-template #template>
|
||||
<button (click)="this['mes' + 'sage'] = 'hello'">Click me</button>
|
||||
</ng-template>
|
||||
`
|
||||
}]
|
||||
}] });
|
||||
export class MyModule {
|
||||
}
|
||||
MyModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||||
MyModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, declarations: [MyComponent] });
|
||||
MyModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, decorators: [{
|
||||
type: NgModule,
|
||||
args: [{ declarations: [MyComponent] }]
|
||||
}] });
|
||||
|
||||
/****************************************************************************************************
|
||||
* PARTIAL FILE: implicit_receiver_keyed_write_inside_template.d.ts
|
||||
****************************************************************************************************/
|
||||
import * as i0 from "@angular/core";
|
||||
export declare class MyComponent {
|
||||
message: string;
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<MyComponent, never>;
|
||||
static ɵcmp: i0.ɵɵComponentDeclaration<MyComponent, "my-component", never, {}, {}, never, never>;
|
||||
}
|
||||
export declare class MyModule {
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<MyModule, never>;
|
||||
static ɵmod: i0.ɵɵNgModuleDeclaration<MyModule, [typeof MyComponent], never, never>;
|
||||
static ɵinj: i0.ɵɵInjectorDeclaration<MyModule>;
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -264,6 +264,23 @@
|
||||
"failureMessage": "Incorrect event listener"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "should generate the view restoration statements if a keyed write is used in an event listener from within an ng-template",
|
||||
"inputFiles": [
|
||||
"implicit_receiver_keyed_write_inside_template.ts"
|
||||
],
|
||||
"expectations": [
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"expected": "implicit_receiver_keyed_write_inside_template_template.js",
|
||||
"generated": "implicit_receiver_keyed_write_inside_template.js"
|
||||
}
|
||||
],
|
||||
"failureMessage": "Incorrect template"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: `
|
||||
<ng-template #template>
|
||||
<button (click)="this['mes' + 'sage'] = 'hello'">Click me</button>
|
||||
</ng-template>
|
||||
`
|
||||
})
|
||||
export class MyComponent {
|
||||
message = '';
|
||||
}
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
function MyComponent_ng_template_0_Template(rf, $ctx$) {
|
||||
if (rf & 1) {
|
||||
const _r3 = $i0$.ɵɵgetCurrentView();
|
||||
$i0$.ɵɵelementStart(0, "button", 1);
|
||||
$i0$.ɵɵlistener("click", function MyComponent_ng_template_0_Template_button_click_0_listener() {
|
||||
$i0$.ɵɵrestoreView(_r3);
|
||||
const $ctx_2$ = $i0$.ɵɵnextContext();
|
||||
return ($ctx_2$["mes" + "sage"] = "hello");
|
||||
});
|
||||
$i0$.ɵɵtext(1, "Click me");
|
||||
$i0$.ɵɵelementEnd();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user