feat(router): add activate and deactivate events to RouterOutlet
This commit is contained in:
parent
a77db44129
commit
245b0910ed
|
@ -6,16 +6,17 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Attribute, ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, NoComponentFactoryError, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
import {Attribute, ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, NoComponentFactoryError, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
||||||
|
|
||||||
import {RouterOutletMap} from '../router_outlet_map';
|
import {RouterOutletMap} from '../router_outlet_map';
|
||||||
import {ActivatedRoute} from '../router_state';
|
import {ActivatedRoute} from '../router_state';
|
||||||
import {PRIMARY_OUTLET} from '../shared';
|
import {PRIMARY_OUTLET} from '../shared';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A router outlet is a placeholder that Angular dynamically fills based on the application's route.
|
* A router outlet is a placeholder that Angular dynamically fills based on the application's route.
|
||||||
*
|
*
|
||||||
* ## Use
|
* ## Example
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* <router-outlet></router-outlet>
|
* <router-outlet></router-outlet>
|
||||||
|
@ -23,6 +24,16 @@ import {PRIMARY_OUTLET} from '../shared';
|
||||||
* <router-outlet name="right"></router-outlet>
|
* <router-outlet name="right"></router-outlet>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* A router outlet will emit an activate event any time a new component is being instantiated,
|
||||||
|
* and a deactivate event when it is being destroyed.
|
||||||
|
*
|
||||||
|
* ## Example
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* <router-outlet (activate)="onActivate($event)"
|
||||||
|
* (deactivate)="onDeactivate($event)"></router-outlet>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@Directive({selector: 'router-outlet'})
|
@Directive({selector: 'router-outlet'})
|
||||||
|
@ -31,6 +42,9 @@ export class RouterOutlet {
|
||||||
private _activatedRoute: ActivatedRoute;
|
private _activatedRoute: ActivatedRoute;
|
||||||
public outletMap: RouterOutletMap;
|
public outletMap: RouterOutletMap;
|
||||||
|
|
||||||
|
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||||
|
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
parentOutletMap: RouterOutletMap, private location: ViewContainerRef,
|
parentOutletMap: RouterOutletMap, private location: ViewContainerRef,
|
||||||
private resolver: ComponentFactoryResolver, @Attribute('name') name: string) {
|
private resolver: ComponentFactoryResolver, @Attribute('name') name: string) {
|
||||||
|
@ -49,8 +63,10 @@ export class RouterOutlet {
|
||||||
|
|
||||||
deactivate(): void {
|
deactivate(): void {
|
||||||
if (this.activated) {
|
if (this.activated) {
|
||||||
|
const c = this.component;
|
||||||
this.activated.destroy();
|
this.activated.destroy();
|
||||||
this.activated = null;
|
this.activated = null;
|
||||||
|
this.deactivateEvents.emit(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,5 +102,7 @@ export class RouterOutlet {
|
||||||
const inj = ReflectiveInjector.fromResolvedProviders(providers, this.location.parentInjector);
|
const inj = ReflectiveInjector.fromResolvedProviders(providers, this.location.parentInjector);
|
||||||
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
||||||
this.activated.changeDetectorRef.detectChanges();
|
this.activated.changeDetectorRef.detectChanges();
|
||||||
|
|
||||||
|
this.activateEvents.emit(this.activated.instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -415,6 +415,48 @@ describe('Integration', () => {
|
||||||
.toHaveText('primary {simple} right {user victor}');
|
.toHaveText('primary {simple} right {user victor}');
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('should emit an event when an outlet gets activated',
|
||||||
|
fakeAsync(inject(
|
||||||
|
[Router, TestComponentBuilder, Location],
|
||||||
|
(router: Router, tcb: TestComponentBuilder, location: Location) => {
|
||||||
|
@Component({
|
||||||
|
selector: 'container',
|
||||||
|
template:
|
||||||
|
`<router-outlet (activate)="recordActivate($event)" (deactivate)="recordDeactivate($event)"></router-outlet>`
|
||||||
|
})
|
||||||
|
class Container {
|
||||||
|
activations: any[] = [];
|
||||||
|
deactivations: any[] = [];
|
||||||
|
|
||||||
|
recordActivate(component: any): void { this.activations.push(component); }
|
||||||
|
|
||||||
|
recordDeactivate(component: any): void { this.deactivations.push(component); }
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = createRoot(tcb, router, Container);
|
||||||
|
const cmp = fixture.debugElement.componentInstance;
|
||||||
|
|
||||||
|
router.resetConfig(
|
||||||
|
[{path: 'blank', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]);
|
||||||
|
|
||||||
|
cmp.activations = [];
|
||||||
|
cmp.deactivations = [];
|
||||||
|
|
||||||
|
router.navigateByUrl('/blank');
|
||||||
|
advance(fixture);
|
||||||
|
|
||||||
|
expect(cmp.activations.length).toEqual(1);
|
||||||
|
expect(cmp.activations[0] instanceof BlankCmp).toBe(true);
|
||||||
|
|
||||||
|
router.navigateByUrl('/simple');
|
||||||
|
advance(fixture);
|
||||||
|
|
||||||
|
expect(cmp.activations.length).toEqual(2);
|
||||||
|
expect(cmp.activations[1] instanceof SimpleCmp).toBe(true);
|
||||||
|
expect(cmp.deactivations.length).toEqual(2);
|
||||||
|
expect(cmp.deactivations[1] instanceof BlankCmp).toBe(true);
|
||||||
|
})));
|
||||||
|
|
||||||
describe('data', () => {
|
describe('data', () => {
|
||||||
class ResolveSix implements Resolve<TeamCmp> {
|
class ResolveSix implements Resolve<TeamCmp> {
|
||||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): number { return 6; }
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): number { return 6; }
|
||||||
|
|
|
@ -180,8 +180,10 @@ export declare class RouterModule {
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class RouterOutlet {
|
export declare class RouterOutlet {
|
||||||
|
activateEvents: EventEmitter<any>;
|
||||||
activatedRoute: ActivatedRoute;
|
activatedRoute: ActivatedRoute;
|
||||||
component: Object;
|
component: Object;
|
||||||
|
deactivateEvents: EventEmitter<any>;
|
||||||
isActivated: boolean;
|
isActivated: boolean;
|
||||||
outletMap: RouterOutletMap;
|
outletMap: RouterOutletMap;
|
||||||
constructor(parentOutletMap: RouterOutletMap, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string);
|
constructor(parentOutletMap: RouterOutletMap, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string);
|
||||||
|
|
Loading…
Reference in New Issue