fix(core): only apply WrappedValue to the binding of the pipe (#15257)

Previously, a pipe that returned a `WrappedValue` would force the change
of the next bound property, independent of the binding in which the pipe
was used.

Now only the binding in which the `WrappedValue` is used will be assumed
as changed.

Fixes #15116

PR Close #15257
This commit is contained in:
Tobias Bosch
2017-03-17 13:45:37 -07:00
committed by Miško Hevery
parent 49829b4a4d
commit 0c43535ccc
5 changed files with 119 additions and 35 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, SimpleChange, SimpleChanges} from '../change_detection/change_detection';
import {ChangeDetectorRef, SimpleChange, SimpleChanges, WrappedValue} from '../change_detection/change_detection';
import {Injector} from '../di';
import {ElementRef} from '../linker/element_ref';
import {TemplateRef} from '../linker/template_ref';
@ -450,7 +450,10 @@ function updateProp(
providerData.instance[propName] = value;
if (def.flags & NodeFlags.OnChanges) {
changes = changes || {};
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
let oldValue = view.oldValues[def.bindingIndex + bindingIdx];
if (oldValue instanceof WrappedValue) {
oldValue = oldValue.wrapped;
}
const binding = def.bindings[bindingIdx];
changes[binding.nonMinifiedName] =
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0);

View File

@ -32,12 +32,15 @@ export function tokenKey(token: any): string {
return key;
}
let unwrapCounter = 0;
export function unwrapValue(value: any): any {
export function unwrapValue(view: ViewData, nodeIdx: number, bindingIdx: number, value: any): any {
if (value instanceof WrappedValue) {
value = value.wrapped;
unwrapCounter++;
let globalBindingIdx = view.def.nodes[nodeIdx].bindingIndex + bindingIdx;
let oldValue = view.oldValues[globalBindingIdx];
if (oldValue instanceof WrappedValue) {
oldValue = oldValue.wrapped;
}
view.oldValues[globalBindingIdx] = new WrappedValue(oldValue);
}
return value;
}
@ -83,9 +86,8 @@ export function resolveRendererType2(type: RendererType2): RendererType2 {
export function checkBinding(
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
const oldValues = view.oldValues;
if (unwrapCounter > 0 || !!(view.state & ViewState.FirstCheck) ||
if ((view.state & ViewState.FirstCheck) ||
!looseIdentical(oldValues[def.bindingIndex + bindingIdx], value)) {
unwrapCounter = 0;
return true;
}
return false;
@ -103,8 +105,7 @@ export function checkAndUpdateBinding(
export function checkBindingNoChanges(
view: ViewData, def: NodeDef, bindingIdx: number, value: any) {
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
if (unwrapCounter || (view.state & ViewState.FirstCheck) || !devModeEqual(oldValue, value)) {
unwrapCounter = 0;
if ((view.state & ViewState.FirstCheck) || !devModeEqual(oldValue, value)) {
throw expressionChangedAfterItHasBeenCheckedError(
Services.createDebugContext(view, def.index), oldValue, value,
(view.state & ViewState.FirstCheck) !== 0);