fix(upgrade): bind optional properties when upgrading from ng1 (#11411)
Previously, optional properties of a directive/component would be wrongly mapped and thus ignored. Closes #10181
This commit is contained in:
parent
36bc2ff269
commit
42b4b6d21b
@ -86,7 +86,10 @@ export class UpgradeNg1ComponentAdapterBuilder {
|
|||||||
if ((<any>context).hasOwnProperty(name)) {
|
if ((<any>context).hasOwnProperty(name)) {
|
||||||
var localName = context[name];
|
var localName = context[name];
|
||||||
var type = localName.charAt(0);
|
var type = localName.charAt(0);
|
||||||
localName = localName.substr(1) || name;
|
var typeOptions = localName.charAt(1);
|
||||||
|
localName = typeOptions === '?' ? localName.substr(2) : localName.substr(1);
|
||||||
|
localName = localName || name;
|
||||||
|
|
||||||
var outputName = 'output_' + name;
|
var outputName = 'output_' + name;
|
||||||
var outputNameRename = outputName + ': ' + name;
|
var outputNameRename = outputName + ': ' + name;
|
||||||
var outputNameRenameChange = outputName + ': ' + name + 'Change';
|
var outputNameRenameChange = outputName + ': ' + name + 'Change';
|
||||||
|
@ -297,12 +297,12 @@ export function main() {
|
|||||||
describe('upgrade ng1 component', () => {
|
describe('upgrade ng1 component', () => {
|
||||||
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));
|
||||||
var ng1Module = angular.module('ng1', []);
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
var ng1 = function() {
|
const ng1 = () => {
|
||||||
return {
|
return {
|
||||||
template: 'Hello {{fullName}}; A: {{dataA}}; B: {{dataB}}; | ',
|
template: 'Hello {{fullName}}; A: {{dataA}}; B: {{dataB}}; C: {{modelC}}; | ',
|
||||||
scope: {fullName: '@', modelA: '=dataA', modelB: '=dataB', event: '&'},
|
scope: {fullName: '@', modelA: '=dataA', modelB: '=dataB', modelC: '=', event: '&'},
|
||||||
link: function(scope: any /** TODO #9100 */) {
|
link: function(scope: any /** TODO #9100 */) {
|
||||||
scope.$watch('dataB', (v: any /** TODO #9100 */) => {
|
scope.$watch('dataB', (v: any /** TODO #9100 */) => {
|
||||||
if (v == 'Savkin') {
|
if (v == 'Savkin') {
|
||||||
@ -317,37 +317,82 @@ export function main() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
ng1Module.directive('ng1', ng1);
|
ng1Module.directive('ng1', ng1);
|
||||||
var Ng2 =
|
const Ng2 =
|
||||||
Component({
|
Component({
|
||||||
selector: 'ng2',
|
selector: 'ng2',
|
||||||
template:
|
template:
|
||||||
'<ng1 fullName="{{last}}, {{first}}" [modelA]="first" [(modelB)]="last" ' +
|
'<ng1 fullName="{{last}}, {{first}}, {{city}}" [modelA]="first" [(modelB)]="last" [modelC]="city" ' +
|
||||||
'(event)="event=$event"></ng1>' +
|
'(event)="event=$event"></ng1>' +
|
||||||
'<ng1 fullName="{{\'TEST\'}}" modelA="First" modelB="Last"></ng1>' +
|
'<ng1 fullName="{{\'TEST\'}}" modelA="First" modelB="Last" modelC="City"></ng1>' +
|
||||||
'{{event}}-{{last}}, {{first}}'
|
'{{event}}-{{last}}, {{first}}, {{city}}'
|
||||||
}).Class({
|
}).Class({
|
||||||
constructor: function() {
|
constructor: function() {
|
||||||
this.first = 'Victor';
|
this.first = 'Victor';
|
||||||
this.last = 'Savkin';
|
this.last = 'Savkin';
|
||||||
|
this.city = 'SF';
|
||||||
this.event = '?';
|
this.event = '?';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
var element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
// we need to do setTimeout, because the EventEmitter uses setTimeout to schedule
|
// we need to do setTimeout, because the EventEmitter uses setTimeout to schedule
|
||||||
// events, and so without this we would not see the events processed.
|
// events, and so without this we would not see the events processed.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(multiTrim(document.body.textContent))
|
expect(multiTrim(document.body.textContent))
|
||||||
.toEqual(
|
.toEqual(
|
||||||
'Hello SAVKIN, Victor; A: VICTOR; B: SAVKIN; | Hello TEST; A: First; B: Last; | WORKS-SAVKIN, Victor');
|
'Hello SAVKIN, Victor, SF; A: VICTOR; B: SAVKIN; C: SF; | Hello TEST; A: First; B: Last; C: City; | WORKS-SAVKIN, Victor, SF');
|
||||||
|
ref.dispose();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should bind optional properties', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
|
const ng1 = () => {
|
||||||
|
return {
|
||||||
|
template: 'Hello; A: {{dataA}}; B: {{modelB}}; | ',
|
||||||
|
scope: {modelA: '=?dataA', modelB: '=?'}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ng1Module.directive('ng1', ng1);
|
||||||
|
const Ng2 = Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: '<ng1 [modelA]="first" [modelB]="last"></ng1>' +
|
||||||
|
'<ng1 modelA="First" modelB="Last"></ng1>' +
|
||||||
|
'<ng1></ng1>' +
|
||||||
|
'<ng1></ng1>'
|
||||||
|
}).Class({
|
||||||
|
constructor: function() {
|
||||||
|
this.first = 'Victor';
|
||||||
|
this.last = 'Savkin';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
// we need to do setTimeout, because the EventEmitter uses setTimeout to schedule
|
||||||
|
// events, and so without this we would not see the events processed.
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(multiTrim(document.body.textContent))
|
||||||
|
.toEqual(
|
||||||
|
'Hello; A: Victor; B: Savkin; | Hello; A: First; B: Last; | Hello; A: ; B: ; | Hello; A: ; B: ; |');
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user