feat(upgrade): fix support for `directive.link` in upgraded components

(#17971)

Although, pre- and post-linking functions are correctly called during directive
linking, directives with `link.post` would throw an error. Interestingly, having
`link.pre` only or defining `link: fn` (which is an alias for `link.post: fn`)
would not throw.

This commit removes this check and allows directives with pre- and/or
post-linking functions to work.
This commit is contained in:
Georgios Kalpakas 2017-05-29 20:52:50 +03:00 committed by Jason Aden
parent 2ea73513ea
commit 0193be7c9b
2 changed files with 238 additions and 6 deletions

View File

@ -90,12 +90,6 @@ export class UpgradeHelper {
if (directive.terminal) this.notSupported('terminal'); if (directive.terminal) this.notSupported('terminal');
if (directive.compile) this.notSupported('compile'); if (directive.compile) this.notSupported('compile');
const link = directive.link;
// QUESTION: why not support link.post?
if (typeof link == 'object') {
if (link.post) this.notSupported('link.post');
}
return directive; return directive;
} }

View File

@ -1069,6 +1069,244 @@ export function main() {
})); }));
}); });
describe('linking', () => {
it('should run the pre-linking after instantiating the controller', async(() => {
const log: string[] = [];
// Define `ng1Directive`
const ng1Directive: angular.IDirective = {
template: '',
link: {pre: () => log.push('ng1-pre')},
controller: class {constructor() { log.push('ng1-ctrl'); }}
};
// Define `Ng1ComponentFacade`
@Directive({selector: 'ng1'})
class Ng1ComponentFacade extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
super('ng1', elementRef, injector);
}
}
// Define `Ng2Component`
@Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2Component {
}
// Define `ng1Module`
const ng1Module = angular.module('ng1', [])
.directive('ng1', () => ng1Directive)
.directive('ng2', downgradeComponent({component: Ng2Component}));
// Define `Ng2Module`
@NgModule({
imports: [BrowserModule, UpgradeModule],
declarations: [Ng1ComponentFacade, Ng2Component],
entryComponents: [Ng2Component],
})
class Ng2Module {
ngDoBootstrap() {}
}
// Bootstrap
const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
expect(log).toEqual(['ng1-ctrl', 'ng1-pre']);
});
}));
it('should run the pre-linking function before linking', async(() => {
const log: string[] = [];
// Define `ng1Directive`
const ng1DirectiveA: angular.IDirective = {
template: '<ng1-b></ng1-b>',
link: {pre: () => log.push('ng1A-pre')}
};
const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')};
// Define `Ng1ComponentAFacade`
@Directive({selector: 'ng1A'})
class Ng1ComponentAFacade extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
super('ng1A', elementRef, injector);
}
}
// Define `Ng2Component`
@Component({selector: 'ng2', template: '<ng1A></ng1A>'})
class Ng2Component {
}
// Define `ng1Module`
const ng1Module = angular.module('ng1', [])
.directive('ng1A', () => ng1DirectiveA)
.directive('ng1B', () => ng1DirectiveB)
.directive('ng2', downgradeComponent({component: Ng2Component}));
// Define `Ng2Module`
@NgModule({
imports: [BrowserModule, UpgradeModule],
declarations: [Ng1ComponentAFacade, Ng2Component],
entryComponents: [Ng2Component],
})
class Ng2Module {
ngDoBootstrap() {}
}
// Bootstrap
const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
expect(log).toEqual(['ng1A-pre', 'ng1B-post']);
});
}));
it('should run the post-linking function after linking (link: object)', async(() => {
const log: string[] = [];
// Define `ng1Directive`
const ng1DirectiveA: angular.IDirective = {
template: '<ng1-b></ng1-b>',
link: {post: () => log.push('ng1A-post')}
};
const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')};
// Define `Ng1ComponentAFacade`
@Directive({selector: 'ng1A'})
class Ng1ComponentAFacade extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
super('ng1A', elementRef, injector);
}
}
// Define `Ng2Component`
@Component({selector: 'ng2', template: '<ng1A></ng1A>'})
class Ng2Component {
}
// Define `ng1Module`
const ng1Module = angular.module('ng1', [])
.directive('ng1A', () => ng1DirectiveA)
.directive('ng1B', () => ng1DirectiveB)
.directive('ng2', downgradeComponent({component: Ng2Component}));
// Define `Ng2Module`
@NgModule({
imports: [BrowserModule, UpgradeModule],
declarations: [Ng1ComponentAFacade, Ng2Component],
entryComponents: [Ng2Component],
})
class Ng2Module {
ngDoBootstrap() {}
}
// Bootstrap
const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
expect(log).toEqual(['ng1B-post', 'ng1A-post']);
});
}));
it('should run the post-linking function after linking (link: function)', async(() => {
const log: string[] = [];
// Define `ng1Directive`
const ng1DirectiveA: angular.IDirective = {
template: '<ng1-b></ng1-b>',
link: () => log.push('ng1A-post')
};
const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')};
// Define `Ng1ComponentAFacade`
@Directive({selector: 'ng1A'})
class Ng1ComponentAFacade extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
super('ng1A', elementRef, injector);
}
}
// Define `Ng2Component`
@Component({selector: 'ng2', template: '<ng1A></ng1A>'})
class Ng2Component {
}
// Define `ng1Module`
const ng1Module = angular.module('ng1', [])
.directive('ng1A', () => ng1DirectiveA)
.directive('ng1B', () => ng1DirectiveB)
.directive('ng2', downgradeComponent({component: Ng2Component}));
// Define `Ng2Module`
@NgModule({
imports: [BrowserModule, UpgradeModule],
declarations: [Ng1ComponentAFacade, Ng2Component],
entryComponents: [Ng2Component],
})
class Ng2Module {
ngDoBootstrap() {}
}
// Bootstrap
const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
expect(log).toEqual(['ng1B-post', 'ng1A-post']);
});
}));
it('should run the post-linking function before `$postLink`', async(() => {
const log: string[] = [];
// Define `ng1Directive`
const ng1Directive: angular.IDirective = {
template: '',
link: () => log.push('ng1-post'),
controller: class {$postLink() { log.push('ng1-$post'); }}
};
// Define `Ng1ComponentFacade`
@Directive({selector: 'ng1'})
class Ng1ComponentFacade extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
super('ng1', elementRef, injector);
}
}
// Define `Ng2Component`
@Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2Component {
}
// Define `ng1Module`
const ng1Module = angular.module('ng1', [])
.directive('ng1', () => ng1Directive)
.directive('ng2', downgradeComponent({component: Ng2Component}));
// Define `Ng2Module`
@NgModule({
imports: [BrowserModule, UpgradeModule],
declarations: [Ng1ComponentFacade, Ng2Component],
entryComponents: [Ng2Component],
})
class Ng2Module {
ngDoBootstrap() {}
}
// Bootstrap
const element = html(`<ng2></ng2>`);
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => {
expect(log).toEqual(['ng1-post', 'ng1-$post']);
});
}));
});
describe('controller', () => { describe('controller', () => {
it('should support `controllerAs`', async(() => { it('should support `controllerAs`', async(() => {
// Define `ng1Directive` // Define `ng1Directive`