fix(upgrade): use correct attribute name for upgraded component's bindings (#16128)
Previously, when using a different property/attribute name for an upgraded component's binding (e.g. `bindings: {propName: '<attrName'}`), the property and attribute names were swapped (e.g. using `attrName` as the property name and `propName` as the attribute name). This resulted in unexpected behavior. This commit fixes this using the correct names for properties and attributes. This only affects `upgrade/dynamic`. `upgrade/static` works correctly already. Fixes #8856 PR Close #16128
This commit is contained in:
parent
2f977312be
commit
d1fb066d07
@ -101,49 +101,50 @@ export class UpgradeNg1ComponentAdapterBuilder {
|
|||||||
const context = (btcIsObject) ? this.directive !.bindToController : this.directive !.scope;
|
const context = (btcIsObject) ? this.directive !.bindToController : this.directive !.scope;
|
||||||
|
|
||||||
if (typeof context == 'object') {
|
if (typeof context == 'object') {
|
||||||
for (const name in context) {
|
Object.keys(context).forEach(propName => {
|
||||||
if ((<any>context).hasOwnProperty(name)) {
|
const definition = context[propName];
|
||||||
let localName = context[name];
|
const bindingType = definition.charAt(0);
|
||||||
const type = localName.charAt(0);
|
const bindingOptions = definition.charAt(1);
|
||||||
const typeOptions = localName.charAt(1);
|
const attrName = definition.substring(bindingOptions === '?' ? 2 : 1) || propName;
|
||||||
localName = typeOptions === '?' ? localName.substr(2) : localName.substr(1);
|
|
||||||
localName = localName || name;
|
|
||||||
|
|
||||||
const outputName = 'output_' + name;
|
// QUESTION: What about `=*`? Ignore? Throw? Support?
|
||||||
const outputNameRename = outputName + ': ' + name;
|
|
||||||
const outputNameRenameChange = outputName + ': ' + name + 'Change';
|
const inputName = `input_${attrName}`;
|
||||||
const inputName = 'input_' + name;
|
const inputNameRename = `${inputName}: ${attrName}`;
|
||||||
const inputNameRename = inputName + ': ' + name;
|
const outputName = `output_${attrName}`;
|
||||||
switch (type) {
|
const outputNameRename = `${outputName}: ${attrName}`;
|
||||||
case '=':
|
const outputNameRenameChange = `${outputNameRename}Change`;
|
||||||
this.propertyOutputs.push(outputName);
|
|
||||||
this.checkProperties.push(localName);
|
switch (bindingType) {
|
||||||
this.outputs.push(outputName);
|
case '@':
|
||||||
this.outputsRename.push(outputNameRenameChange);
|
case '<':
|
||||||
this.propertyMap[outputName] = localName;
|
this.inputs.push(inputName);
|
||||||
this.inputs.push(inputName);
|
this.inputsRename.push(inputNameRename);
|
||||||
this.inputsRename.push(inputNameRename);
|
this.propertyMap[inputName] = propName;
|
||||||
this.propertyMap[inputName] = localName;
|
break;
|
||||||
break;
|
case '=':
|
||||||
case '@':
|
this.inputs.push(inputName);
|
||||||
// handle the '<' binding of angular 1.5 components
|
this.inputsRename.push(inputNameRename);
|
||||||
case '<':
|
this.propertyMap[inputName] = propName;
|
||||||
this.inputs.push(inputName);
|
|
||||||
this.inputsRename.push(inputNameRename);
|
this.outputs.push(outputName);
|
||||||
this.propertyMap[inputName] = localName;
|
this.outputsRename.push(outputNameRenameChange);
|
||||||
break;
|
this.propertyMap[outputName] = propName;
|
||||||
case '&':
|
|
||||||
this.outputs.push(outputName);
|
this.checkProperties.push(propName);
|
||||||
this.outputsRename.push(outputNameRename);
|
this.propertyOutputs.push(outputName);
|
||||||
this.propertyMap[outputName] = localName;
|
break;
|
||||||
break;
|
case '&':
|
||||||
default:
|
this.outputs.push(outputName);
|
||||||
let json = JSON.stringify(context);
|
this.outputsRename.push(outputNameRename);
|
||||||
throw new Error(
|
this.propertyMap[outputName] = propName;
|
||||||
`Unexpected mapping '${type}' in '${json}' in '${this.name}' directive.`);
|
break;
|
||||||
}
|
default:
|
||||||
|
let json = JSON.stringify(context);
|
||||||
|
throw new Error(
|
||||||
|
`Unexpected mapping '${bindingType}' in '${json}' in '${this.name}' directive.`);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,13 +240,11 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
|
|||||||
(this as any /** TODO #9100 */)[inputs[i]] = null;
|
(this as any /** TODO #9100 */)[inputs[i]] = null;
|
||||||
}
|
}
|
||||||
for (let j = 0; j < outputs.length; j++) {
|
for (let j = 0; j < outputs.length; j++) {
|
||||||
const emitter = (this as any /** TODO #9100 */)[outputs[j]] = new EventEmitter();
|
const emitter = (this as any)[outputs[j]] = new EventEmitter<any>();
|
||||||
this.setComponentProperty(
|
this.setComponentProperty(
|
||||||
outputs[j], ((emitter: any /** TODO #9100 */) => (value: any /** TODO #9100 */) =>
|
outputs[j], (emitter => (value: any) => emitter.emit(value))(emitter));
|
||||||
emitter.emit(value))(emitter));
|
|
||||||
}
|
}
|
||||||
for (let k = 0; k < propOuts.length; k++) {
|
for (let k = 0; k < propOuts.length; k++) {
|
||||||
(this as any /** TODO #9100 */)[propOuts[k]] = new EventEmitter();
|
|
||||||
this.checkLastValues.push(INITIAL_VALUE);
|
this.checkLastValues.push(INITIAL_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,18 +305,16 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
|
|||||||
const destinationObj = this.destinationObj;
|
const destinationObj = this.destinationObj;
|
||||||
const lastValues = this.checkLastValues;
|
const lastValues = this.checkLastValues;
|
||||||
const checkProperties = this.checkProperties;
|
const checkProperties = this.checkProperties;
|
||||||
for (let i = 0; i < checkProperties.length; i++) {
|
const propOuts = this.propOuts;
|
||||||
const value = destinationObj ![checkProperties[i]];
|
checkProperties.forEach((propName, i) => {
|
||||||
|
const value = destinationObj ![propName];
|
||||||
const last = lastValues[i];
|
const last = lastValues[i];
|
||||||
if (value !== last) {
|
if (value !== last &&
|
||||||
if (typeof value == 'number' && isNaN(value) && typeof last == 'number' && isNaN(last)) {
|
(value === value || last === last)) { // ignore NaN values (NaN !== NaN)
|
||||||
// ignore because NaN != NaN
|
const eventEmitter: EventEmitter<any> = (this as any)[propOuts[i]];
|
||||||
} else {
|
eventEmitter.emit(lastValues[i] = value);
|
||||||
const eventEmitter: EventEmitter<any> = (this as any /** TODO #9100 */)[this.propOuts[i]];
|
|
||||||
eventEmitter.emit(lastValues[i] = value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
|
if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
|
||||||
this.controllerInstance.$doCheck();
|
this.controllerInstance.$doCheck();
|
||||||
|
@ -6,4 +6,13 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {UpgradeAdapterRef} from '@angular/upgrade';
|
||||||
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||||
|
import {$ROOT_SCOPE} from '@angular/upgrade/src/common/constants';
|
||||||
|
|
||||||
export * from '../common/test_helpers';
|
export * from '../common/test_helpers';
|
||||||
|
|
||||||
|
export function $digest(adapter: UpgradeAdapterRef) {
|
||||||
|
const $rootScope = adapter.ng1Injector.get($ROOT_SCOPE) as angular.IRootScopeService;
|
||||||
|
$rootScope.$digest();
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@ import {BrowserModule} from '@angular/platform-browser';
|
|||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||||
import {UpgradeAdapter, UpgradeAdapterRef} from '@angular/upgrade/src/dynamic/upgrade_adapter';
|
import {UpgradeAdapter, UpgradeAdapterRef} from '@angular/upgrade/src/dynamic/upgrade_adapter';
|
||||||
import {html, multiTrim} from './test_helpers';
|
import {$digest, html, multiTrim} from './test_helpers';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('adapter: ng1 to ng2', () => {
|
describe('adapter: ng1 to ng2', () => {
|
||||||
@ -607,22 +607,268 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('upgrade ng1 component', () => {
|
describe('upgrade ng1 component', () => {
|
||||||
|
it('should support `@` bindings', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
let ng2ComponentInstance: Ng2Component;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
template: 'Inside: {{ $ctrl.inputA }}, {{ $ctrl.inputB }}',
|
||||||
|
bindings: {inputA: '@inputAttrA', inputB: '@'}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: `
|
||||||
|
<ng1 inputAttrA="{{ dataA }}" inputB="{{ dataB }}"></ng1>
|
||||||
|
| Outside: {{ dataA }}, {{ dataB }}
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class Ng2Component {
|
||||||
|
dataA = 'foo';
|
||||||
|
dataB = 'bar';
|
||||||
|
|
||||||
|
constructor() { ng2ComponentInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2></ng2>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready(ref => {
|
||||||
|
const ng1 = element.querySelector('ng1') !;
|
||||||
|
const ng1Controller = angular.element(ng1).controller !('ng1');
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng1Controller.inputA = 'baz';
|
||||||
|
ng1Controller.inputB = 'qux';
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng2ComponentInstance.dataA = 'foo2';
|
||||||
|
ng2ComponentInstance.dataB = 'bar2';
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent))
|
||||||
|
.toBe('Inside: foo2, bar2 | Outside: foo2, bar2');
|
||||||
|
|
||||||
|
ref.dispose();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should support `<` bindings', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
let ng2ComponentInstance: Ng2Component;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
template: 'Inside: {{ $ctrl.inputA.value }}, {{ $ctrl.inputB.value }}',
|
||||||
|
bindings: {inputA: '<inputAttrA', inputB: '<'}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: `
|
||||||
|
<ng1 [inputAttrA]="dataA" [inputB]="dataB"></ng1>
|
||||||
|
| Outside: {{ dataA.value }}, {{ dataB.value }}
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class Ng2Component {
|
||||||
|
dataA = {value: 'foo'};
|
||||||
|
dataB = {value: 'bar'};
|
||||||
|
|
||||||
|
constructor() { ng2ComponentInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2></ng2>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready(ref => {
|
||||||
|
const ng1 = element.querySelector('ng1') !;
|
||||||
|
const ng1Controller = angular.element(ng1).controller !('ng1');
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng1Controller.inputA = {value: 'baz'};
|
||||||
|
ng1Controller.inputB = {value: 'qux'};
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng2ComponentInstance.dataA = {value: 'foo2'};
|
||||||
|
ng2ComponentInstance.dataB = {value: 'bar2'};
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent))
|
||||||
|
.toBe('Inside: foo2, bar2 | Outside: foo2, bar2');
|
||||||
|
|
||||||
|
ref.dispose();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should support `=` bindings', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
let ng2ComponentInstance: Ng2Component;
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
template: 'Inside: {{ $ctrl.inputA.value }}, {{ $ctrl.inputB.value }}',
|
||||||
|
bindings: {inputA: '=inputAttrA', inputB: '='}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: `
|
||||||
|
<ng1 [(inputAttrA)]="dataA" [(inputB)]="dataB"></ng1>
|
||||||
|
| Outside: {{ dataA.value }}, {{ dataB.value }}
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class Ng2Component {
|
||||||
|
dataA = {value: 'foo'};
|
||||||
|
dataB = {value: 'bar'};
|
||||||
|
|
||||||
|
constructor() { ng2ComponentInstance = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2></ng2>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready(ref => {
|
||||||
|
const ng1 = element.querySelector('ng1') !;
|
||||||
|
const ng1Controller = angular.element(ng1).controller !('ng1');
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng1Controller.inputA = {value: 'baz'};
|
||||||
|
ng1Controller.inputB = {value: 'qux'};
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: baz, qux');
|
||||||
|
|
||||||
|
ng2ComponentInstance.dataA = {value: 'foo2'};
|
||||||
|
ng2ComponentInstance.dataB = {value: 'bar2'};
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent))
|
||||||
|
.toBe('Inside: foo2, bar2 | Outside: foo2, bar2');
|
||||||
|
|
||||||
|
ref.dispose();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should support `&` bindings', fakeAsync(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
|
||||||
|
// Define `ng1Component`
|
||||||
|
const ng1Component: angular.IComponent = {
|
||||||
|
template: 'Inside: -',
|
||||||
|
bindings: {outputA: '&outputAttrA', outputB: '&'}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define `Ng2Component`
|
||||||
|
@Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: `
|
||||||
|
<ng1 (outputAttrA)="dataA = $event" (outputB)="dataB = $event"></ng1>
|
||||||
|
| Outside: {{ dataA }}, {{ dataB }}
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class Ng2Component {
|
||||||
|
dataA = 'foo';
|
||||||
|
dataB = 'bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define `ng1Module`
|
||||||
|
const ng1Module = angular.module('ng1Module', [])
|
||||||
|
.component('ng1', ng1Component)
|
||||||
|
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
||||||
|
|
||||||
|
// Define `Ng2Module`
|
||||||
|
@NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
||||||
|
imports: [BrowserModule]
|
||||||
|
})
|
||||||
|
class Ng2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
const element = html(`<ng2></ng2>`);
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1Module']).ready(ref => {
|
||||||
|
const ng1 = element.querySelector('ng1') !;
|
||||||
|
const ng1Controller = angular.element(ng1).controller !('ng1');
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar');
|
||||||
|
|
||||||
|
ng1Controller.outputA('baz');
|
||||||
|
ng1Controller.outputB('qux');
|
||||||
|
$digest(ref);
|
||||||
|
|
||||||
|
expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: baz, qux');
|
||||||
|
|
||||||
|
ref.dispose();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should bind properties, events', async(() => {
|
it('should bind properties, events', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const ng1Module = angular.module('ng1', []);
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
const ng1 = () => {
|
const ng1 = () => {
|
||||||
return {
|
return {
|
||||||
template: 'Hello {{fullName}}; A: {{dataA}}; B: {{dataB}}; C: {{modelC}}; | ',
|
template: 'Hello {{fullName}}; A: {{modelA}}; B: {{modelB}}; C: {{modelC}}; | ',
|
||||||
scope: {fullName: '@', modelA: '=dataA', modelB: '=dataB', modelC: '=', event: '&'},
|
scope: {fullName: '@', modelA: '=dataA', modelB: '=dataB', modelC: '=', event: '&'},
|
||||||
link: function(scope: any) {
|
link: function(scope: any) {
|
||||||
scope.$watch('dataB', (v: string) => {
|
scope.$watch('modelB', (v: string) => {
|
||||||
if (v == 'Savkin') {
|
if (v == 'Savkin') {
|
||||||
scope.dataB = 'SAVKIN';
|
scope.modelB = 'SAVKIN';
|
||||||
scope.event('WORKS');
|
scope.event('WORKS');
|
||||||
|
|
||||||
// Should not update because [model-a] is uni directional
|
// Should not update because [model-a] is uni directional
|
||||||
scope.dataA = 'VICTOR';
|
scope.modelA = 'VICTOR';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -633,9 +879,9 @@ export function main() {
|
|||||||
Component({
|
Component({
|
||||||
selector: 'ng2',
|
selector: 'ng2',
|
||||||
template:
|
template:
|
||||||
'<ng1 fullName="{{last}}, {{first}}, {{city}}" [modelA]="first" [(modelB)]="last" [modelC]="city" ' +
|
'<ng1 fullName="{{last}}, {{first}}, {{city}}" [dataA]="first" [(dataB)]="last" [modelC]="city" ' +
|
||||||
'(event)="event=$event"></ng1>' +
|
'(event)="event=$event"></ng1>' +
|
||||||
'<ng1 fullName="{{\'TEST\'}}" modelA="First" modelB="Last" modelC="City"></ng1>' +
|
'<ng1 fullName="{{\'TEST\'}}" dataA="First" dataB="Last" modelC="City"></ng1>' +
|
||||||
'{{event}}-{{last}}, {{first}}, {{city}}'
|
'{{event}}-{{last}}, {{first}}, {{city}}'
|
||||||
}).Class({
|
}).Class({
|
||||||
constructor: function() {
|
constructor: function() {
|
||||||
@ -671,15 +917,15 @@ export function main() {
|
|||||||
|
|
||||||
const ng1 = () => {
|
const ng1 = () => {
|
||||||
return {
|
return {
|
||||||
template: 'Hello; A: {{dataA}}; B: {{modelB}}; | ',
|
template: 'Hello; A: {{modelA}}; B: {{modelB}}; | ',
|
||||||
scope: {modelA: '=?dataA', modelB: '=?'}
|
scope: {modelA: '=?dataA', modelB: '=?'}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ng1Module.directive('ng1', ng1);
|
ng1Module.directive('ng1', ng1);
|
||||||
const Ng2 = Component({
|
const Ng2 = Component({
|
||||||
selector: 'ng2',
|
selector: 'ng2',
|
||||||
template: '<ng1 [modelA]="first" [modelB]="last"></ng1>' +
|
template: '<ng1 [dataA]="first" [modelB]="last"></ng1>' +
|
||||||
'<ng1 modelA="First" modelB="Last"></ng1>' +
|
'<ng1 dataA="First" modelB="Last"></ng1>' +
|
||||||
'<ng1></ng1>' +
|
'<ng1></ng1>' +
|
||||||
'<ng1></ng1>'
|
'<ng1></ng1>'
|
||||||
}).Class({
|
}).Class({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user