fix(upgrade): two-way binding and listening for event (#22772)

Changes would not propagate to a value in downgraded component in case you had two-way binding and listening to a value-change, e.g. [(value)]="value" (value-change)="fetch()"

Closes #22734

PR Close #22772
This commit is contained in:
Domas Trijonis
2018-03-16 21:18:11 +01:00
committed by Miško Hevery
parent 5c387a7f3c
commit 2b3de6390f
3 changed files with 131 additions and 32 deletions

View File

@ -168,42 +168,40 @@ export class DowngradeComponentAdapter {
const outputs = this.componentFactory.outputs || [];
for (let j = 0; j < outputs.length; j++) {
const output = new PropertyBinding(outputs[j].propName, outputs[j].templateName);
let expr: string|null = null;
let assignExpr = false;
const bindonAttr = output.bindonAttr.substring(0, output.bindonAttr.length - 6);
const bracketParenAttr =
`[(${output.bracketParenAttr.substring(2, output.bracketParenAttr.length - 8)})]`;
// order below is important - first update bindings then evaluate expressions
if (attrs.hasOwnProperty(bindonAttr)) {
this.subscribeToOutput(output, attrs[bindonAttr], true);
}
if (attrs.hasOwnProperty(bracketParenAttr)) {
this.subscribeToOutput(output, attrs[bracketParenAttr], true);
}
if (attrs.hasOwnProperty(output.onAttr)) {
expr = attrs[output.onAttr];
} else if (attrs.hasOwnProperty(output.parenAttr)) {
expr = attrs[output.parenAttr];
} else if (attrs.hasOwnProperty(bindonAttr)) {
expr = attrs[bindonAttr];
assignExpr = true;
} else if (attrs.hasOwnProperty(bracketParenAttr)) {
expr = attrs[bracketParenAttr];
assignExpr = true;
this.subscribeToOutput(output, attrs[output.onAttr]);
}
if (attrs.hasOwnProperty(output.parenAttr)) {
this.subscribeToOutput(output, attrs[output.parenAttr]);
}
}
}
if (expr != null && assignExpr != null) {
const getter = this.$parse(expr);
const setter = getter.assign;
if (assignExpr && !setter) {
throw new Error(`Expression '${expr}' is not assignable!`);
}
const emitter = this.component[output.prop] as EventEmitter<any>;
if (emitter) {
emitter.subscribe({
next: assignExpr ? (v: any) => setter !(this.scope, v) :
(v: any) => getter(this.scope, {'$event': v})
});
} else {
throw new Error(
`Missing emitter '${output.prop}' on component '${getComponentName(this.componentFactory.componentType)}'!`);
}
}
private subscribeToOutput(output: PropertyBinding, expr: string, isAssignment: boolean = false) {
const getter = this.$parse(expr);
const setter = getter.assign;
if (isAssignment && !setter) {
throw new Error(`Expression '${expr}' is not assignable!`);
}
const emitter = this.component[output.prop] as EventEmitter<any>;
if (emitter) {
emitter.subscribe({
next: isAssignment ? (v: any) => setter !(this.scope, v) :
(v: any) => getter(this.scope, {'$event': v})
});
} else {
throw new Error(
`Missing emitter '${output.prop}' on component '${getComponentName(this.componentFactory.componentType)}'!`);
}
}