fix(ivy): o2+ should work with multiple template instances (#22075)
Closes #22075
This commit is contained in:
parent
8ec21fc325
commit
5e4af7c550
|
@ -87,6 +87,7 @@ export {
|
|||
objectLiteral6 as o6,
|
||||
objectLiteral7 as o7,
|
||||
objectLiteral8 as o8,
|
||||
objectLiteralV as oV,
|
||||
} from './object_literal';
|
||||
|
||||
|
||||
|
|
|
@ -499,8 +499,7 @@ export function createTView(): TView {
|
|||
contentCheckHooks: null,
|
||||
viewHooks: null,
|
||||
viewCheckHooks: null,
|
||||
destroyHooks: null,
|
||||
objectLiterals: null
|
||||
destroyHooks: null
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1736,6 +1735,12 @@ function valueInData<T>(data: any[], index: number, value?: T): T {
|
|||
return value !;
|
||||
}
|
||||
|
||||
/** Gets the binding at the current bindingIndex */
|
||||
export function peekBinding(): any {
|
||||
ngDevMode && assertNotEqual(currentView.bindingStartIndex, null, 'bindingStartIndex');
|
||||
return data[bindingIndex];
|
||||
}
|
||||
|
||||
export function getCurrentQueries(QueryType: {new (): LQueries}): LQueries {
|
||||
return currentQueries || (currentQueries = new QueryType());
|
||||
}
|
||||
|
@ -1748,10 +1753,6 @@ export function getRenderer(): Renderer3 {
|
|||
return renderer;
|
||||
}
|
||||
|
||||
export function getTView(): TView {
|
||||
return currentView.tView;
|
||||
}
|
||||
|
||||
export function getDirectiveInstance<T>(instanceOrArray: T | [T]): T {
|
||||
// Directives with content queries store an array in data[directiveIndex]
|
||||
// with the instance as the first index
|
||||
|
|
|
@ -259,9 +259,6 @@ export interface TView {
|
|||
* Odd indices: Hook function
|
||||
*/
|
||||
destroyHooks: HookData|null;
|
||||
|
||||
/** Contains copies of object literals that were passed as bindings in this view. */
|
||||
objectLiterals: any[]|null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,268 +6,294 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {assertEqual} from './assert';
|
||||
import {NO_CHANGE, bind, getTView} from './instructions';
|
||||
|
||||
import {NO_CHANGE, bind, peekBinding} from './instructions';
|
||||
|
||||
/**
|
||||
* Updates an expression in an object or array literal if the expression has changed.
|
||||
* Used in objectLiteral instructions.
|
||||
*
|
||||
* @param obj Object to update
|
||||
* @param key Key to set in object
|
||||
* @param exp Expression to set at key
|
||||
* @returns Whether or not there has been a change
|
||||
*/
|
||||
function updateBinding(obj: any, key: string | number, exp: any): boolean {
|
||||
if (bind(exp) !== NO_CHANGE) {
|
||||
obj[key] = exp;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Updates two expressions in an object or array literal if they have changed. */
|
||||
function updateBinding2(
|
||||
obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any): boolean {
|
||||
let different = updateBinding(obj, key1, exp1);
|
||||
return updateBinding(obj, key2, exp2) || different;
|
||||
}
|
||||
|
||||
/** Updates four expressions in an object or array literal if they have changed. */
|
||||
function updateBinding4(
|
||||
obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any): boolean {
|
||||
let different = updateBinding2(obj, key1, exp1, key2, exp2);
|
||||
return updateBinding2(obj, key3, exp3, key4, exp4) || different;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a blueprint of an object or array if one has already been saved, or copies the
|
||||
* object and saves it for the next change detection run if it hasn't.
|
||||
*/
|
||||
function getMutableBlueprint(index: number, obj: any): any {
|
||||
const tView = getTView();
|
||||
const objectLiterals = tView.objectLiterals;
|
||||
if (objectLiterals && index < objectLiterals.length) {
|
||||
return objectLiterals[index];
|
||||
} else {
|
||||
ngDevMode && objectLiterals && assertEqual(index, objectLiterals.length, 'index');
|
||||
return (objectLiterals || (tView.objectLiterals = []))[index] = copyObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/** Copies an object or array */
|
||||
function copyObject(obj: any): any {
|
||||
return Array.isArray(obj) ? obj.slice() : {...obj};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expression in the given object or array if it has changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with the updated expression.
|
||||
* Or if the expression hasn't changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex Index of object blueprint in objectLiterals
|
||||
* @param obj Object to update
|
||||
* @param key Key to set in object
|
||||
* @param exp Expression to set at key
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
* @param factoryFn Function that returns an updated instance of the object/array
|
||||
* @param exp Updated expression value
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral1(objIndex: number, obj: any, key: string | number, exp: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
if (bind(exp) === NO_CHANGE) {
|
||||
return NO_CHANGE;
|
||||
} else {
|
||||
obj[key] = exp;
|
||||
// Must copy to change identity when binding changes
|
||||
return copyObject(obj);
|
||||
}
|
||||
export function objectLiteral1(factoryFn: (v: any) => any, exp: any): any {
|
||||
let different = false;
|
||||
const latestValue = exp === NO_CHANGE ? peekBinding() : exp;
|
||||
if (bind(exp) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(latestValue) : NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @returns A copy of the array or NO_CHANGE
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral2(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number,
|
||||
exp2: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
return updateBinding2(obj, key1, exp1, key2, exp2) ? copyObject(obj) : NO_CHANGE;
|
||||
export function objectLiteral2(factoryFn: (v1: any, v2: any) => any, exp1: any, exp2: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(latestVal1, latestVal2) : NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral3(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
let different = updateBinding2(obj, key1, exp1, key2, exp2);
|
||||
return updateBinding(obj, key3, exp3) || different ? copyObject(obj) : NO_CHANGE;
|
||||
factoryFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(latestVal1, latestVal2, latestVal3) : NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @param key4
|
||||
* @param exp4
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral4(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
return updateBinding4(obj, key1, exp1, key2, exp2, key3, exp3, key4, exp4) ? copyObject(obj) :
|
||||
NO_CHANGE;
|
||||
factoryFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any, exp3: any,
|
||||
exp4: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal4 = exp4 === NO_CHANGE ? peekBinding() : exp4;
|
||||
if (bind(exp4) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(latestVal1, latestVal2, latestVal3, latestVal4) : NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @param key4
|
||||
* @param exp4
|
||||
* @param key5
|
||||
* @param exp5
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral5(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any, key5: string | number,
|
||||
exp5: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
let different = updateBinding4(obj, key1, exp1, key2, exp2, key3, exp3, key4, exp4);
|
||||
return updateBinding(obj, key5, exp5) || different ? copyObject(obj) : NO_CHANGE;
|
||||
factoryFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any, exp2: any,
|
||||
exp3: any, exp4: any, exp5: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal4 = exp4 === NO_CHANGE ? peekBinding() : exp4;
|
||||
if (bind(exp4) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal5 = exp5 === NO_CHANGE ? peekBinding() : exp5;
|
||||
if (bind(exp5) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(latestVal1, latestVal2, latestVal3, latestVal4, latestVal5) :
|
||||
NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @param key4
|
||||
* @param exp4
|
||||
* @param key5
|
||||
* @param exp5
|
||||
* @param key6
|
||||
* @param exp6
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral6(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any, key5: string | number,
|
||||
exp5: any, key6: string | number, exp6: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
let different = updateBinding4(obj, key1, exp1, key2, exp2, key3, exp3, key4, exp4);
|
||||
return updateBinding2(obj, key5, exp5, key6, exp6) || different ? copyObject(obj) : NO_CHANGE;
|
||||
}
|
||||
factoryFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any, exp1: any, exp2: any,
|
||||
exp3: any, exp4: any, exp5: any, exp6: any): any {
|
||||
let different = false;
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @param key4
|
||||
* @param exp4
|
||||
* @param key5
|
||||
* @param exp5
|
||||
* @param key6
|
||||
* @param exp6
|
||||
* @param key7
|
||||
* @param exp7
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral7(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any, key5: string | number,
|
||||
exp5: any, key6: string | number, exp6: any, key7: string | number, exp7: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
let different = updateBinding4(obj, key1, exp1, key2, exp2, key3, exp3, key4, exp4);
|
||||
different = updateBinding2(obj, key5, exp5, key6, exp6) || different;
|
||||
return updateBinding(obj, key7, exp7) || different ? copyObject(obj) : NO_CHANGE;
|
||||
}
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
/**
|
||||
* Updates the expressions in the given object or array if they have changed and returns a copy.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param objIndex
|
||||
* @param obj
|
||||
* @param key1
|
||||
* @param exp1
|
||||
* @param key2
|
||||
* @param exp2
|
||||
* @param key3
|
||||
* @param exp3
|
||||
* @param key4
|
||||
* @param exp4
|
||||
* @param key5
|
||||
* @param exp5
|
||||
* @param key6
|
||||
* @param exp6
|
||||
* @param key7
|
||||
* @param exp7
|
||||
* @param key8
|
||||
* @param exp8
|
||||
* @returns A copy of the object or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral8(
|
||||
objIndex: number, obj: any, key1: string | number, exp1: any, key2: string | number, exp2: any,
|
||||
key3: string | number, exp3: any, key4: string | number, exp4: any, key5: string | number,
|
||||
exp5: any, key6: string | number, exp6: any, key7: string | number, exp7: any,
|
||||
key8: string | number, exp8: any): any {
|
||||
obj = getMutableBlueprint(objIndex, obj);
|
||||
let different = updateBinding4(obj, key1, exp1, key2, exp2, key3, exp3, key4, exp4);
|
||||
return updateBinding4(obj, key5, exp5, key6, exp6, key7, exp7, key8, exp8) || different ?
|
||||
copyObject(obj) :
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal4 = exp4 === NO_CHANGE ? peekBinding() : exp4;
|
||||
if (bind(exp4) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal5 = exp5 === NO_CHANGE ? peekBinding() : exp5;
|
||||
if (bind(exp5) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal6 = exp6 === NO_CHANGE ? peekBinding() : exp6;
|
||||
if (bind(exp6) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ?
|
||||
factoryFn(latestVal1, latestVal2, latestVal3, latestVal4, latestVal5, latestVal6) :
|
||||
NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param exp2
|
||||
* @param exp3
|
||||
* @param exp4
|
||||
* @param exp5
|
||||
* @param exp6
|
||||
* @param exp7
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral7(
|
||||
factoryFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any,
|
||||
exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal4 = exp4 === NO_CHANGE ? peekBinding() : exp4;
|
||||
if (bind(exp4) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal5 = exp5 === NO_CHANGE ? peekBinding() : exp5;
|
||||
if (bind(exp5) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal6 = exp6 === NO_CHANGE ? peekBinding() : exp6;
|
||||
if (bind(exp6) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal7 = exp7 === NO_CHANGE ? peekBinding() : exp7;
|
||||
if (bind(exp7) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ?
|
||||
factoryFn(
|
||||
latestVal1, latestVal2, latestVal3, latestVal4, latestVal5, latestVal6, latestVal7) :
|
||||
NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param factoryFn
|
||||
* @param exp1
|
||||
* @param exp2
|
||||
* @param exp3
|
||||
* @param exp4
|
||||
* @param exp5
|
||||
* @param exp6
|
||||
* @param exp7
|
||||
* @param exp8
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteral8(
|
||||
factoryFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any,
|
||||
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any): any {
|
||||
let different = false;
|
||||
|
||||
const latestVal1 = exp1 === NO_CHANGE ? peekBinding() : exp1;
|
||||
if (bind(exp1) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal2 = exp2 === NO_CHANGE ? peekBinding() : exp2;
|
||||
if (bind(exp2) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal3 = exp3 === NO_CHANGE ? peekBinding() : exp3;
|
||||
if (bind(exp3) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal4 = exp4 === NO_CHANGE ? peekBinding() : exp4;
|
||||
if (bind(exp4) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal5 = exp5 === NO_CHANGE ? peekBinding() : exp5;
|
||||
if (bind(exp5) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal6 = exp6 === NO_CHANGE ? peekBinding() : exp6;
|
||||
if (bind(exp6) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal7 = exp7 === NO_CHANGE ? peekBinding() : exp7;
|
||||
if (bind(exp7) !== NO_CHANGE) different = true;
|
||||
|
||||
const latestVal8 = exp8 === NO_CHANGE ? peekBinding() : exp8;
|
||||
if (bind(exp8) !== NO_CHANGE) different = true;
|
||||
|
||||
return different ? factoryFn(
|
||||
latestVal1, latestVal2, latestVal3, latestVal4, latestVal5, latestVal6,
|
||||
latestVal7, latestVal8) :
|
||||
NO_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* objectLiteral instruction that can support any number of bindings.
|
||||
*
|
||||
* If the object or array has changed, returns a copy with all updated expressions.
|
||||
* Or if no expressions have changed, returns NO_CHANGE.
|
||||
*
|
||||
* @param factoryFn A factory function that takes binding values and builds an object or array
|
||||
* containing those values.
|
||||
* @param exp An array of binding values
|
||||
* @returns A copy of the object/array or NO_CHANGE
|
||||
*/
|
||||
export function objectLiteralV(factoryFn: (v: any[]) => any, exps: any[]): any {
|
||||
let different = false;
|
||||
|
||||
for (let i = 0; i < exps.length; i++) {
|
||||
const exp = exps[i];
|
||||
if (exp === NO_CHANGE) exps[i] = peekBinding();
|
||||
if (bind(exp) !== NO_CHANGE) different = true;
|
||||
}
|
||||
|
||||
return different ? factoryFn(exps) : NO_CHANGE;
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ describe('compiler specification', () => {
|
|||
r3.E(0, MyComp);
|
||||
r3.e();
|
||||
}
|
||||
r3.p(0, 'names', r3.o1(0, e0_literal, 1, ctx.customName));
|
||||
r3.p(0, 'names', r3.o1(e0_ff, ctx.customName));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
r3.r(1, 0);
|
||||
}
|
||||
|
@ -235,18 +235,118 @@ describe('compiler specification', () => {
|
|||
}
|
||||
|
||||
// NORMATIVE
|
||||
const e0_literal = ['Nancy', null];
|
||||
const e0_ff = (v: any) => ['Nancy', v];
|
||||
// /NORMATIVE
|
||||
|
||||
expect(renderComp(MyApp)).toEqual(`<my-comp><p>Nancy</p><p>Bess</p></my-comp>`);
|
||||
expect(e0_literal).toEqual(['Nancy', null]);
|
||||
});
|
||||
|
||||
it('should support 9+ bindings in array literals', () => {
|
||||
@Component({
|
||||
selector: 'my-comp',
|
||||
template: `
|
||||
{{ names[0] }}
|
||||
{{ names[1] }}
|
||||
{{ names[3] }}
|
||||
{{ names[4] }}
|
||||
{{ names[5] }}
|
||||
{{ names[6] }}
|
||||
{{ names[7] }}
|
||||
{{ names[8] }}
|
||||
{{ names[9] }}
|
||||
{{ names[10] }}
|
||||
{{ names[11] }}
|
||||
`
|
||||
})
|
||||
class MyComp {
|
||||
@Input() names: string[];
|
||||
|
||||
static ngComponentDef = r3.defineComponent({
|
||||
type: MyComp,
|
||||
tag: 'my-comp',
|
||||
factory: function MyComp_Factory() { return new MyComp(); },
|
||||
template: function MyComp_Template(ctx: MyComp, cm: boolean) {
|
||||
if (cm) {
|
||||
r3.T(0);
|
||||
r3.T(1);
|
||||
r3.T(2);
|
||||
r3.T(3);
|
||||
r3.T(4);
|
||||
r3.T(5);
|
||||
r3.T(6);
|
||||
r3.T(7);
|
||||
r3.T(8);
|
||||
r3.T(9);
|
||||
r3.T(10);
|
||||
r3.T(11);
|
||||
}
|
||||
r3.t(0, r3.b(ctx.names[0]));
|
||||
r3.t(1, r3.b(ctx.names[1]));
|
||||
r3.t(2, r3.b(ctx.names[2]));
|
||||
r3.t(3, r3.b(ctx.names[3]));
|
||||
r3.t(4, r3.b(ctx.names[4]));
|
||||
r3.t(5, r3.b(ctx.names[5]));
|
||||
r3.t(6, r3.b(ctx.names[6]));
|
||||
r3.t(7, r3.b(ctx.names[7]));
|
||||
r3.t(8, r3.b(ctx.names[8]));
|
||||
r3.t(9, r3.b(ctx.names[9]));
|
||||
r3.t(10, r3.b(ctx.names[10]));
|
||||
r3.t(11, r3.b(ctx.names[11]));
|
||||
},
|
||||
inputs: {names: 'names'}
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `
|
||||
<my-comp [names]="['start-', n0, n1, n2, n3, n4, '-middle-', n5, n6, n7, n8, '-end']">
|
||||
</my-comp>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
n0 = 'a';
|
||||
n1 = 'b';
|
||||
n2 = 'c';
|
||||
n3 = 'd';
|
||||
n4 = 'e';
|
||||
n5 = 'f';
|
||||
n6 = 'g';
|
||||
n7 = 'h';
|
||||
n8 = 'i';
|
||||
|
||||
// NORMATIVE
|
||||
static ngComponentDef = r3.defineComponent({
|
||||
type: MyApp,
|
||||
tag: 'my-app',
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
template: function MyApp_Template(c: MyApp, cm: boolean) {
|
||||
if (cm) {
|
||||
r3.E(0, MyComp);
|
||||
r3.e();
|
||||
}
|
||||
r3.p(
|
||||
0, 'names', r3.oV(e0_ff, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8]));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
r3.r(1, 0);
|
||||
}
|
||||
});
|
||||
// /NORMATIVE
|
||||
}
|
||||
|
||||
// NORMATIVE
|
||||
const e0_ff = (v: any[]) =>
|
||||
['start-', v[0], v[1], v[2], v[3], v[4], '-middle-', v[5], v[6], v[7], v[8], '-end'];
|
||||
// /NORMATIVE
|
||||
|
||||
expect(renderComp(MyApp)).toEqual(`<my-comp>start-abcde-middle-fghi-end</my-comp>`);
|
||||
});
|
||||
|
||||
it('should support object literals', () => {
|
||||
@Component({
|
||||
selector: 'object-comp',
|
||||
template: `
|
||||
<p> {{ config.duration }} </p>
|
||||
<p> {{ config['duration'] }} </p>
|
||||
<p> {{ config.animation }} </p>
|
||||
`
|
||||
})
|
||||
|
@ -266,7 +366,7 @@ describe('compiler specification', () => {
|
|||
r3.T(3);
|
||||
r3.e();
|
||||
}
|
||||
r3.t(1, r3.b(ctx.config.duration));
|
||||
r3.t(1, r3.b(ctx.config['duration']));
|
||||
r3.t(3, r3.b(ctx.config.animation));
|
||||
},
|
||||
inputs: {config: 'config'}
|
||||
|
@ -276,7 +376,7 @@ describe('compiler specification', () => {
|
|||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `
|
||||
<object-comp [config]="{duration: 500, animation: name}"></object-comp>
|
||||
<object-comp [config]="{'duration': 500, animation: name}"></object-comp>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
|
@ -292,7 +392,7 @@ describe('compiler specification', () => {
|
|||
r3.E(0, ObjectComp);
|
||||
r3.e();
|
||||
}
|
||||
r3.p(0, 'config', r3.o1(0, e0_literal, 'animation', ctx.name));
|
||||
r3.p(0, 'config', r3.o1(e0_ff, ctx.name));
|
||||
ObjectComp.ngComponentDef.h(1, 0);
|
||||
r3.r(1, 0);
|
||||
}
|
||||
|
@ -301,11 +401,10 @@ describe('compiler specification', () => {
|
|||
}
|
||||
|
||||
// NORMATIVE
|
||||
const e0_literal = {duration: 500, animation: null};
|
||||
const e0_ff = (v: any) => { return {'duration': 500, animation: v}; };
|
||||
// /NORMATIVE
|
||||
|
||||
expect(renderComp(MyApp)).toEqual(`<object-comp><p>500</p><p>slide</p></object-comp>`);
|
||||
expect(e0_literal).toEqual({duration: 500, animation: null});
|
||||
});
|
||||
|
||||
it('should support expressions nested deeply in object/array literals', () => {
|
||||
|
@ -367,9 +466,7 @@ describe('compiler specification', () => {
|
|||
}
|
||||
r3.p(
|
||||
0, 'config',
|
||||
r3.o2(
|
||||
2, e0_literal_2, 'animation', ctx.name, 'actions',
|
||||
r3.o1(1, e0_literal_1, 1, r3.o1(0, e0_literal, 'duration', ctx.duration))));
|
||||
r3.o2(e0_ff_2, ctx.name, r3.o1(e0_ff_1, r3.o1(e0_ff, ctx.duration))));
|
||||
NestedComp.ngComponentDef.h(1, 0);
|
||||
r3.r(1, 0);
|
||||
}
|
||||
|
@ -378,10 +475,10 @@ describe('compiler specification', () => {
|
|||
}
|
||||
|
||||
// NORMATIVE
|
||||
const e0_literal = {opacity: 1, duration: null};
|
||||
const e0_ff = (v: any) => { return {opacity: 1, duration: v}; };
|
||||
const c0 = {opacity: 0, duration: 0};
|
||||
const e0_literal_1 = [c0, null];
|
||||
const e0_literal_2 = {animation: null, actions: null};
|
||||
const e0_ff_1 = (v: any) => [c0, v];
|
||||
const e0_ff_2 = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
|
||||
// /NORMATIVE
|
||||
|
||||
expect(renderComp(MyApp))
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {defineComponent} from '../../src/render3/index';
|
||||
import {componentRefresh, elementEnd, elementProperty, elementStart, memory} from '../../src/render3/instructions';
|
||||
import {objectLiteral1, objectLiteral2, objectLiteral3, objectLiteral4, objectLiteral5, objectLiteral6, objectLiteral7, objectLiteral8} from '../../src/render3/object_literal';
|
||||
import {componentRefresh, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, memory} from '../../src/render3/instructions';
|
||||
import {objectLiteral1, objectLiteral2, objectLiteral3, objectLiteral4, objectLiteral5, objectLiteral6, objectLiteral7, objectLiteral8, objectLiteralV} from '../../src/render3/object_literal';
|
||||
import {renderToHtml} from '../../test/render3/render_util';
|
||||
|
||||
describe('array literals', () => {
|
||||
|
@ -32,12 +32,12 @@ describe('array literals', () => {
|
|||
elementStart(0, MyComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(0, 'names', objectLiteral1(0, e0_literal, 1, ctx.customName));
|
||||
elementProperty(0, 'names', objectLiteral1(e0_ff, ctx.customName));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
const e0_literal = ['Nancy', null, 'Bess'];
|
||||
const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
|
||||
|
||||
renderToHtml(Template, {customName: 'Carson'});
|
||||
const firstArray = myComp !.names;
|
||||
|
@ -52,8 +52,6 @@ describe('array literals', () => {
|
|||
|
||||
// Identity must change if binding changes
|
||||
expect(firstArray).not.toBe(myComp !.names);
|
||||
|
||||
expect(e0_literal).toEqual(['Nancy', null, 'Bess']);
|
||||
});
|
||||
|
||||
it('should support multiple array literals passed through to one node', () => {
|
||||
|
@ -72,21 +70,23 @@ describe('array literals', () => {
|
|||
});
|
||||
}
|
||||
|
||||
/** <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]"></many-prop-comp>
|
||||
/**
|
||||
* <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
|
||||
* </many-prop-comp>
|
||||
*/
|
||||
function Template(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, ManyPropComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(0, 'names1', objectLiteral1(0, e0_literal, 1, ctx.customName));
|
||||
elementProperty(0, 'names2', objectLiteral1(1, e0_literal_1, 0, ctx.customName2));
|
||||
elementProperty(0, 'names1', objectLiteral1(e0_ff, ctx.customName));
|
||||
elementProperty(0, 'names2', objectLiteral1(e0_ff_1, ctx.customName2));
|
||||
ManyPropComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
const e0_literal = ['Nancy', null];
|
||||
const e0_literal_1 = [null];
|
||||
const e0_ff = (v: any) => ['Nancy', v];
|
||||
const e0_ff_1 = (v: any) => [v];
|
||||
|
||||
renderToHtml(Template, {customName: 'Carson', customName2: 'George'});
|
||||
expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']);
|
||||
|
@ -95,10 +95,6 @@ describe('array literals', () => {
|
|||
renderToHtml(Template, {customName: 'George', customName2: 'Carson'});
|
||||
expect(manyPropComp !.names1).toEqual(['Nancy', 'George']);
|
||||
expect(manyPropComp !.names2).toEqual(['Carson']);
|
||||
|
||||
expect(e0_literal).toEqual(['Nancy', null]);
|
||||
expect(e0_literal_1).toEqual([null]);
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -109,13 +105,12 @@ describe('array literals', () => {
|
|||
elementStart(0, MyComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(
|
||||
0, 'names', objectLiteral2(0, e0_literal, 1, ctx.customName, 3, ctx.customName2));
|
||||
elementProperty(0, 'names', objectLiteral2(e0_ff, ctx.customName, ctx.customName2));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
const e0_literal = ['Nancy', null, 'Bess', null];
|
||||
const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
|
||||
|
||||
renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'});
|
||||
const firstArray = myComp !.names;
|
||||
|
@ -162,42 +157,40 @@ describe('array literals', () => {
|
|||
o8Comp = memory(11);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(0, 'names', objectLiteral3(0, e0_literal, 5, c[5], 6, c[6], 7, c[7]));
|
||||
elementProperty(0, 'names', objectLiteral3(e0_ff, c[5], c[6], c[7]));
|
||||
elementProperty(2, 'names', objectLiteral4(e2_ff, c[4], c[5], c[6], c[7]));
|
||||
elementProperty(4, 'names', objectLiteral5(e4_ff, c[3], c[4], c[5], c[6], c[7]));
|
||||
elementProperty(6, 'names', objectLiteral6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7]));
|
||||
elementProperty(8, 'names', objectLiteral7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7]));
|
||||
elementProperty(
|
||||
2, 'names', objectLiteral4(1, e2_literal, 4, c[4], 5, c[5], 6, c[6], 7, c[7]));
|
||||
elementProperty(
|
||||
4, 'names', objectLiteral5(2, e4_literal, 3, c[3], 4, c[4], 5, c[5], 6, c[6], 7, c[7]));
|
||||
elementProperty(
|
||||
6, 'names',
|
||||
objectLiteral6(3, e6_literal, 2, c[2], 3, c[3], 4, c[4], 5, c[5], 6, c[6], 7, c[7]));
|
||||
elementProperty(
|
||||
8, 'names',
|
||||
objectLiteral7(
|
||||
4, e8_literal, 1, c[1], 2, c[2], 3, c[3], 4, c[4], 5, c[5], 6, c[6], 7, c[7]));
|
||||
elementProperty(
|
||||
10, 'names', objectLiteral8(
|
||||
5, e10_literal, 0, c[0], 1, c[1], 2, c[2], 3, c[3], 4, c[4], 5, c[5], 6,
|
||||
c[6], 7, c[7]));
|
||||
10, 'names', objectLiteral8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
MyComp.ngComponentDef.h(3, 2);
|
||||
componentRefresh(3, 2);
|
||||
MyComp.ngComponentDef.h(5, 4);
|
||||
componentRefresh(5, 4);
|
||||
MyComp.ngComponentDef.h(7, 6);
|
||||
componentRefresh(7, 6);
|
||||
MyComp.ngComponentDef.h(9, 8);
|
||||
componentRefresh(9, 8);
|
||||
MyComp.ngComponentDef.h(11, 10);
|
||||
componentRefresh(1, 0);
|
||||
componentRefresh(3, 2);
|
||||
componentRefresh(5, 4);
|
||||
componentRefresh(7, 6);
|
||||
componentRefresh(9, 8);
|
||||
componentRefresh(11, 10);
|
||||
}
|
||||
|
||||
const e0_literal = ['a', 'b', 'c', 'd', 'e', null, null, null];
|
||||
const e2_literal = ['a', 'b', 'c', 'd', null, null, null, null];
|
||||
const e4_literal = ['a', 'b', 'c', null, null, null, null, null];
|
||||
const e6_literal = ['a', 'b', null, null, null, null, null, null];
|
||||
const e8_literal = ['a', null, null, null, null, null, null, null];
|
||||
const e10_literal = [null, null, null, null, null, null, null, null];
|
||||
const e0_ff = (v1: any, v2: any, v3: any) => ['a', 'b', 'c', 'd', 'e', v1, v2, v3];
|
||||
const e2_ff = (v1: any, v2: any, v3: any, v4: any) => ['a', 'b', 'c', 'd', v1, v2, v3, v4];
|
||||
const e4_ff =
|
||||
(v1: any, v2: any, v3: any, v4: any, v5: any) => ['a', 'b', 'c', v1, v2, v3, v4, v5];
|
||||
const e6_ff =
|
||||
(v1: any, v2: any, v3: any, v4: any, v5: any,
|
||||
v6: any) => ['a', 'b', v1, v2, v3, v4, v5, v6];
|
||||
const e8_ff =
|
||||
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any) => ['a', v1, v2, v3, v4, v5, v6, v7];
|
||||
const e10_ff =
|
||||
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
|
||||
v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8];
|
||||
|
||||
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
|
||||
expect(o3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
|
||||
|
@ -216,33 +209,74 @@ describe('array literals', () => {
|
|||
expect(o8Comp !.names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
|
||||
});
|
||||
|
||||
it('should support an object literal', () => {
|
||||
let objectComp: ObjectComp;
|
||||
|
||||
class ObjectComp {
|
||||
config: {[key: string]: any};
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: ObjectComp,
|
||||
tag: 'object-comp',
|
||||
factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); },
|
||||
template: function ObjectComp_Template(ctx: ObjectComp, cm: boolean) {},
|
||||
inputs: {config: 'config'}
|
||||
});
|
||||
it('should work with objectLiteralV for 9+ bindings', () => {
|
||||
/**
|
||||
* <my-comp [names]="['start', v0, v1, v2, v3, {name: v4}, v5, v6, v7, v8, 'end']">
|
||||
* </my-comp>
|
||||
*/
|
||||
function Template(c: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, MyComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(
|
||||
0, 'names', objectLiteralV(e0_ff, [
|
||||
c[0], c[1], c[2], c[3], objectLiteral1(e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
|
||||
]));
|
||||
MyComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
/** <object-comp [config]="{duration: 500, animation: ctx.name}"></object-comp> */
|
||||
const e0_ff =
|
||||
(v: any[]) => ['start', v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], 'end'];
|
||||
const e0_ff_1 = (v: any) => { return {name: v}; };
|
||||
|
||||
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
|
||||
expect(myComp !.names).toEqual([
|
||||
'start', 'a', 'b', 'c', 'd', {name: 'e'}, 'f', 'g', 'h', 'i', 'end'
|
||||
]);
|
||||
|
||||
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
|
||||
expect(myComp !.names).toEqual([
|
||||
'start', 'a1', 'b', 'c', 'd', {name: 'e'}, 'f', 'g', 'h', 'i', 'end'
|
||||
]);
|
||||
|
||||
renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e5', 'f', 'g', 'h', 'i']);
|
||||
expect(myComp !.names).toEqual([
|
||||
'start', 'a1', 'b', 'c', 'd', {name: 'e5'}, 'f', 'g', 'h', 'i', 'end'
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
describe('object literals', () => {
|
||||
let objectComp: ObjectComp;
|
||||
|
||||
class ObjectComp {
|
||||
config: {[key: string]: any};
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: ObjectComp,
|
||||
tag: 'object-comp',
|
||||
factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); },
|
||||
template: function ObjectComp_Template(ctx: ObjectComp, cm: boolean) {},
|
||||
inputs: {config: 'config'}
|
||||
});
|
||||
}
|
||||
|
||||
it('should support an object literal', () => {
|
||||
|
||||
/** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */
|
||||
function Template(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, ObjectComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(0, 'config', objectLiteral1(0, e0_literal, 'animation', ctx.name));
|
||||
elementProperty(0, 'config', objectLiteral1(e0_ff, ctx.name));
|
||||
ObjectComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
const e0_literal = {duration: 500, animation: null};
|
||||
const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
|
||||
|
||||
renderToHtml(Template, {name: 'slide'});
|
||||
const firstObj = objectComp !.config;
|
||||
|
@ -257,80 +291,107 @@ describe('array literals', () => {
|
|||
|
||||
// Identity must change if binding changes
|
||||
expect(firstObj).not.toBe(objectComp !.config);
|
||||
|
||||
expect(e0_literal).toEqual({duration: 500, animation: null});
|
||||
});
|
||||
|
||||
it('should support expressions nested deeply in object/array literals', () => {
|
||||
let nestedComp: NestedComp;
|
||||
|
||||
class NestedComp {
|
||||
config: {[key: string]: any};
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: NestedComp,
|
||||
tag: 'nested-comp',
|
||||
factory: function NestedComp_Factory() { return nestedComp = new NestedComp(); },
|
||||
template: function NestedComp_Template(ctx: NestedComp, cm: boolean) {},
|
||||
inputs: {config: 'config'}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <nested-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1,
|
||||
* <object-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1,
|
||||
* duration: duration }]}">
|
||||
* </nested-comp>
|
||||
* </object-comp>
|
||||
*/
|
||||
function Template(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
elementStart(0, NestedComp);
|
||||
elementStart(0, ObjectComp);
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(
|
||||
0, 'config',
|
||||
objectLiteral2(
|
||||
2, e0_literal_2, 'animation', ctx.name, 'actions',
|
||||
objectLiteral1(
|
||||
1, e0_literal_1, 1, objectLiteral1(0, e0_literal, 'duration', ctx.duration))));
|
||||
NestedComp.ngComponentDef.h(1, 0);
|
||||
e0_ff, ctx.name, objectLiteral1(e0_ff_1, objectLiteral1(e0_ff_2, ctx.duration))));
|
||||
ObjectComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
}
|
||||
|
||||
const e0_literal = {opacity: 1, duration: null};
|
||||
const e0_literal_1 = [{opacity: 0, duration: 0}, null];
|
||||
const e0_literal_2 = {animation: null, actions: null};
|
||||
const e0_ff = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
|
||||
const e0_ff_1 = (v: any) => [{opacity: 0, duration: 0}, v];
|
||||
const e0_ff_2 = (v: any) => { return {opacity: 1, duration: v}; };
|
||||
|
||||
renderToHtml(Template, {name: 'slide', duration: 100});
|
||||
expect(nestedComp !.config).toEqual({
|
||||
expect(objectComp !.config).toEqual({
|
||||
animation: 'slide',
|
||||
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
|
||||
});
|
||||
const firstConfig = nestedComp !.config;
|
||||
const firstConfig = objectComp !.config;
|
||||
|
||||
renderToHtml(Template, {name: 'slide', duration: 100});
|
||||
expect(nestedComp !.config).toEqual({
|
||||
expect(objectComp !.config).toEqual({
|
||||
animation: 'slide',
|
||||
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
|
||||
});
|
||||
expect(nestedComp !.config).toBe(firstConfig);
|
||||
expect(objectComp !.config).toBe(firstConfig);
|
||||
|
||||
renderToHtml(Template, {name: 'slide', duration: 50});
|
||||
expect(nestedComp !.config).toEqual({
|
||||
expect(objectComp !.config).toEqual({
|
||||
animation: 'slide',
|
||||
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
|
||||
});
|
||||
expect(nestedComp !.config).not.toBe(firstConfig);
|
||||
expect(objectComp !.config).not.toBe(firstConfig);
|
||||
|
||||
renderToHtml(Template, {name: 'tap', duration: 50});
|
||||
expect(nestedComp !.config).toEqual({
|
||||
expect(objectComp !.config).toEqual({
|
||||
animation: 'tap',
|
||||
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
|
||||
});
|
||||
|
||||
expect(e0_literal).toEqual({opacity: 1, duration: null});
|
||||
expect(e0_literal_1).toEqual([{opacity: 0, duration: 0}, null]);
|
||||
expect(e0_literal_2).toEqual({animation: null, actions: null});
|
||||
renderToHtml(Template, {name: 'drag', duration: 500});
|
||||
expect(objectComp !.config).toEqual({
|
||||
animation: 'drag',
|
||||
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 500}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should support multiple view instances with multiple bindings', () => {
|
||||
let objectComps: ObjectComp[] = [];
|
||||
|
||||
/**
|
||||
* % for(let i = 0; i < 2; i++) {
|
||||
* <object-comp [config]="{opacity: configs[i].opacity, duration: configs[i].duration}">
|
||||
* </object-comp>
|
||||
* % }
|
||||
*/
|
||||
function Template(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
container(0);
|
||||
}
|
||||
containerRefreshStart(0);
|
||||
{
|
||||
for (let i = 0; i < 2; i++) {
|
||||
if (embeddedViewStart(0)) {
|
||||
elementStart(0, ObjectComp);
|
||||
objectComps.push(memory(1));
|
||||
elementEnd();
|
||||
}
|
||||
elementProperty(
|
||||
0, 'config', objectLiteral2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration));
|
||||
ObjectComp.ngComponentDef.h(1, 0);
|
||||
componentRefresh(1, 0);
|
||||
embeddedViewEnd();
|
||||
}
|
||||
}
|
||||
containerRefreshEnd();
|
||||
}
|
||||
|
||||
const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; };
|
||||
|
||||
const configs = [{opacity: 0, duration: 500}, {opacity: 1, duration: 600}];
|
||||
renderToHtml(Template, {configs});
|
||||
expect(objectComps[0].config).toEqual({opacity: 0, duration: 500});
|
||||
expect(objectComps[1].config).toEqual({opacity: 1, duration: 600});
|
||||
|
||||
configs[0].duration = 1000;
|
||||
renderToHtml(Template, {configs});
|
||||
expect(objectComps[0].config).toEqual({opacity: 0, duration: 1000});
|
||||
expect(objectComps[1].config).toEqual({opacity: 1, duration: 600});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue