如何在 Angular2 的特定路径上操作组件
How to manipulate a component on specific routes in Angular2
我有一个简单的 TopbarComponent
,它基本上在我的视图顶部添加了一个引导式导航栏。
因为我 90% 的模板都应该包含这个指令,我想通过我的 app.component
来处理它,它看起来像这样:
import ...;
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, TopbarComponent, ...],
providers: [ROUTER_PROVIDERS, ...]
})
@RouteConfig([
{
path: '/login',
name: 'Login',
component: LoginComponent
},
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
useAsDefault: true
}
])
其模板如下所示:
<my-topbar></my-topbar>
<div class="container-fluid">
<div class="row">
<router-outlet></router-outlet>
</div>
</div>
现在我想使用 ngIf
(或除了用 css 隐藏它之外的任何其他方式)来隐藏几条路线上的顶部栏,例如 /login
。
我尝试了几种使用 @CanAcitvate()
或在我的 LoginComponent
中实现 OnActivate
的方法(以及从我的 AppComponent
中尝试它)但没有效果(甚至无法获得功能开火)。
我最接近的是直接在我的 AppComponent
中使用 Router
,如下所示:
export class AppComponent implements OnInit{
showTopbar:boolean;
constructor(private _router:Router) {}
ngOnInit():any {
this.showTopbar = this._router.lastNavigationAttempt != '/login';
}
}
在我的 app.component.html
中,我将指令更改为 <my-topbar *ngIf="showTopbar"></my-topbar>
但这只适用于我的应用程序的初始加载,因为 ngOnInit
不会在每次状态更改时触发。有没有我可以使用的类似方法(只是找不到),还是我走错了方向?
编辑:
目前,PierreDuc 的答案对我不起作用,但我使用 location.path()
尝试了类似的方法,如下所示:
constructor(private _location:Location) {}
private get _hideTopbar() : boolean {
switch(this._location.path()){
case '/register':
case '/login':
return true;
default:
return false;
}
};
太糟糕了,我不能在这种方法中使用 @RouteConfig
中的 data
属性。感觉会更好
差不多了,试试这个
模板
<my-topbar *ngIf="shouldShowTopbar()">
</my-topbar>
应用组件
export class AppComponent implements OnInit{
hideWhen: Array<string> = ['Login', 'Help', 'SomeOtherRoute'];
// put all the route names where you want it hidden in above array
constructor(private _router:Router) {}
shouldShowTopbar() {
return (hideWhen.indexOf(this._router.currentInstruction.component.routeName) > -1);
}
}
不确定这是否正确,但您可以在 Login
对象的 @RouteConfig()
object. For instance you can place in the RouteDefinition
的 data
参数中添加任何数据 hideTopbar
环境。如果它应该设置为 true,你只需要将它放在一个路由中:
警告,前面的代码未经测试:)
@RouteConfig([{
path: '/login',
name: 'Login',
component: LoginComponent,
data : {hideTopbar : true}
},
//...
])
您可以在 AppComponent
class 中访问此数据,例如:
export class AppComponent {
private get _hideTopbar() : boolean {
return this._data.get('hideTopbar');
};
constructor(private _data:RouteData) {}
}
并将 AppComponent
模板更改为:
<my-topbar *ngIf="!_hideTopbar"></my-topbar>
<div class="container-fluid">
<div class="row">
<router-outlet></router-outlet>
</div>
</div>
我也有类似的问题。也许这不是最好的方法。但我是这样解决的:
我创建了一个新组件。该组件处理所有需要导航栏的路线。其他路由由 app.component
.
处理
这里有一些代码需要理解:
app.component
@RouteConfig([
{
path: '/...',
name: '...',
component: MyComponentWhoAddsNavbar,
useAsDefault: true
},
{ path: '/login',
name: 'Login',
component: LoginComponent
}
])
@Component({
selector: 'my-app',
template: '<router-outlet></router-outlet>',
})
export class AppComponent {}
这里是MyComponentWhoAddsNavbar
@RouteConfig([
put your routes here who need a navbar
])
@Component({
selector: '...',
template: `
<navbar></navbar>
<router-outlet></router-outlet>
`,
})
export class MyComponentWhoAddsNavbar{}
一段时间以来,我一直为类似的问题而头疼。
我找到的解决方案一开始可能会被视为棘手,但将来可以为我解决许多此类类似问题。
基本上,您必须让 router-outlet
在路由更改时发出事件,让您的 AppComponent
监听该自定义事件。
第一步是创建自定义路由器插座:
@Directive({
selector: 'custom-router-outlet'
})
export class CustomRouterOutlet extends RouterOutlet {
private parentRouter:Router;
constructor(_elementRef: ElementRef,
_loader: DynamicComponentLoader,
_parentRouter: Router,
@Attribute('name') nameAttr: string) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
}
activate(nextInstruction: ComponentInstruction): Promise<any> {
//***YOUR CUSTOM LOGIC HERE***
return super.activate(nextInstruction);
}
}
这是自定义路由器插座的非常基本的实现。您的逻辑必须在 activate 方法中实现,在每次路由更改时调用。
在这种方法中,您可以检查路线中的数据属性。
主要问题是,现在,指令 无法发出事件...它们只接受输入,不能触发任何输出...
我找到了解决此问题的方法:使用 EventEmitter
:
创建一个 Service 用于组件和指令之间的通信
@Injectable()
export class PubsubService {
private _pubSubber: EventEmitter<any> = new EventEmitter();
routeisChanging(obj:any) {
this._pubSubber.emit(obj);
}
onRouteChanged() {
return this._pubSubber;
}
}
AppComponent订阅了onRouteChanged
事件:
subscription:any;
constructor(private _pubsubService:PubsubService) {
this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {
/**YOUR CUSTOM LOGIC HERE*/});
}
CustomRouterOutlet 在需要时触发 activate
方法中的事件:
activate(nextInstruction: ComponentInstruction): Promise<any> {
//***YOUR CUSTOM LOGIC HERE***
this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);
return super.activate(nextInstruction);
}
通过这种方式,您可以使用任何逻辑轻松实现路由器与 AppComponent
之间的通信。
您必须记得在您的应用程序的 RootComponent
中注入通信服务。
我在
工作
"@angular/common": "~2.1.0"
我解决这个问题的方法是创建一个应用程序范围的数据对象 global
和一个服务 GlobalService
。任何组件都可以 subscribe()
全局对象的全部或部分。为了您的目的,您应该创建一个布尔值 属性 isTopBar: true
。您可以订阅您的 <topBar>
组件并使用该值来切换它。
isTopBar: boolean;
ngOnInit(){
this._globalService.getIsTopBar().subscribe(isTopBar => this.isTopBar = isTopBar)
}
<my-topbar *ngIf="isTopBar"></my-topbar>
我发现这种 'GlobalService' 的一大优势是我可以将大量状态信息保存到我的后端。它在您的示例中用处不大,但可以想象您有一组内部选项卡;您可以保存用户最后选择的选项卡,并在他们以后重新访问该页面时重新加载到该视图。
这可能根本不是正确的方法,但它对我有用。它不会根据路线本身改变可见性,而是根据该路线中显示的组件改变可见性。
我已经在使用一种服务来为导航栏提供所有部分等等,所以我认为它也可以告诉导航栏何时出现或不出现。
我主要是在这个服务中创建了一个主题来确定它是否应该可见,并使用一系列方法来改变这种可见性。
@Injectable()
export class NavigationService {
mobileNavbarIsVisible = true;
mobileNavbarIsVisibleChanged = new Subject<boolean>();
constructor() { }
getSections() {
return this.sections;
}
getMobileNavbarIsVisible() {
return this.mobileNavbarIsVisible;
}
hideMobileNavbar() {
this.mobileNavbarIsVisible = false;
this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
}
showMobileNavbar() {
this.mobileNavbarIsVisible = true;
this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
}
}
然后,我在影响可见性的组件中调用那些方法 - 在我的例子中,每次我编辑项目列表中的项目时,我希望导航栏消失 -。我在这个组件启动时调用 hide 方法,在它被销毁时调用 show 方法。
@Component({
selector: 'app-item-edit',
templateUrl: './item-edit.component.html',
styleUrls: ['./item-edit.component.css']
})
export class ItemEditComponent implements OnInit, OnDestroy {
constructor(private navigationService: NavigationService) {}
ngOnInit() {
this.navigationService.hideMobileNavbar();
}
ngOnDestroy() {
this.navigationService.showMobileNavbar();
}
}
然后,我的 NavbarComponent 正在侦听该主题,并根据该值显示或不显示:
@Component({
selector: 'app-mobile-navbar',
templateUrl: './mobile-navbar.component.html',
styleUrls: ['./mobile-navbar.component.css']
})
export class MobileNavbarComponent implements OnInit {
isVisible = true;
ngOnInit() {
this.isVisible = this.navigationService.getMobileNavbarIsVisible();
this.navigationService.mobileNavbarIsVIsibleChanged.subscribe(
(visibilityValue) => this.isVisible = visibilityValue
);
}
}
正如我所说,这很可能不是正确或最有效的方法,但如果您只想在启动其他组件时隐藏导航栏,它会起作用,因为它们只是将导航服务用作一种沟通方式。
我有一个简单的 TopbarComponent
,它基本上在我的视图顶部添加了一个引导式导航栏。
因为我 90% 的模板都应该包含这个指令,我想通过我的 app.component
来处理它,它看起来像这样:
import ...;
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, TopbarComponent, ...],
providers: [ROUTER_PROVIDERS, ...]
})
@RouteConfig([
{
path: '/login',
name: 'Login',
component: LoginComponent
},
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
useAsDefault: true
}
])
其模板如下所示:
<my-topbar></my-topbar>
<div class="container-fluid">
<div class="row">
<router-outlet></router-outlet>
</div>
</div>
现在我想使用 ngIf
(或除了用 css 隐藏它之外的任何其他方式)来隐藏几条路线上的顶部栏,例如 /login
。
我尝试了几种使用 @CanAcitvate()
或在我的 LoginComponent
中实现 OnActivate
的方法(以及从我的 AppComponent
中尝试它)但没有效果(甚至无法获得功能开火)。
我最接近的是直接在我的 AppComponent
中使用 Router
,如下所示:
export class AppComponent implements OnInit{
showTopbar:boolean;
constructor(private _router:Router) {}
ngOnInit():any {
this.showTopbar = this._router.lastNavigationAttempt != '/login';
}
}
在我的 app.component.html
中,我将指令更改为 <my-topbar *ngIf="showTopbar"></my-topbar>
但这只适用于我的应用程序的初始加载,因为 ngOnInit
不会在每次状态更改时触发。有没有我可以使用的类似方法(只是找不到),还是我走错了方向?
编辑:
目前,PierreDuc 的答案对我不起作用,但我使用 location.path()
尝试了类似的方法,如下所示:
constructor(private _location:Location) {}
private get _hideTopbar() : boolean {
switch(this._location.path()){
case '/register':
case '/login':
return true;
default:
return false;
}
};
太糟糕了,我不能在这种方法中使用 @RouteConfig
中的 data
属性。感觉会更好
差不多了,试试这个
模板
<my-topbar *ngIf="shouldShowTopbar()">
</my-topbar>
应用组件
export class AppComponent implements OnInit{
hideWhen: Array<string> = ['Login', 'Help', 'SomeOtherRoute'];
// put all the route names where you want it hidden in above array
constructor(private _router:Router) {}
shouldShowTopbar() {
return (hideWhen.indexOf(this._router.currentInstruction.component.routeName) > -1);
}
}
不确定这是否正确,但您可以在 Login
对象的 @RouteConfig()
object. For instance you can place in the RouteDefinition
的 data
参数中添加任何数据 hideTopbar
环境。如果它应该设置为 true,你只需要将它放在一个路由中:
警告,前面的代码未经测试:)
@RouteConfig([{
path: '/login',
name: 'Login',
component: LoginComponent,
data : {hideTopbar : true}
},
//...
])
您可以在 AppComponent
class 中访问此数据,例如:
export class AppComponent {
private get _hideTopbar() : boolean {
return this._data.get('hideTopbar');
};
constructor(private _data:RouteData) {}
}
并将 AppComponent
模板更改为:
<my-topbar *ngIf="!_hideTopbar"></my-topbar>
<div class="container-fluid">
<div class="row">
<router-outlet></router-outlet>
</div>
</div>
我也有类似的问题。也许这不是最好的方法。但我是这样解决的:
我创建了一个新组件。该组件处理所有需要导航栏的路线。其他路由由 app.component
.
这里有一些代码需要理解:
app.component
@RouteConfig([
{
path: '/...',
name: '...',
component: MyComponentWhoAddsNavbar,
useAsDefault: true
},
{ path: '/login',
name: 'Login',
component: LoginComponent
}
])
@Component({
selector: 'my-app',
template: '<router-outlet></router-outlet>',
})
export class AppComponent {}
这里是MyComponentWhoAddsNavbar
@RouteConfig([
put your routes here who need a navbar
])
@Component({
selector: '...',
template: `
<navbar></navbar>
<router-outlet></router-outlet>
`,
})
export class MyComponentWhoAddsNavbar{}
一段时间以来,我一直为类似的问题而头疼。 我找到的解决方案一开始可能会被视为棘手,但将来可以为我解决许多此类类似问题。
基本上,您必须让 router-outlet
在路由更改时发出事件,让您的 AppComponent
监听该自定义事件。
第一步是创建自定义路由器插座:
@Directive({
selector: 'custom-router-outlet'
})
export class CustomRouterOutlet extends RouterOutlet {
private parentRouter:Router;
constructor(_elementRef: ElementRef,
_loader: DynamicComponentLoader,
_parentRouter: Router,
@Attribute('name') nameAttr: string) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
}
activate(nextInstruction: ComponentInstruction): Promise<any> {
//***YOUR CUSTOM LOGIC HERE***
return super.activate(nextInstruction);
}
}
这是自定义路由器插座的非常基本的实现。您的逻辑必须在 activate 方法中实现,在每次路由更改时调用。 在这种方法中,您可以检查路线中的数据属性。
主要问题是,现在,指令 无法发出事件...它们只接受输入,不能触发任何输出...
我找到了解决此问题的方法:使用 EventEmitter
:
@Injectable()
export class PubsubService {
private _pubSubber: EventEmitter<any> = new EventEmitter();
routeisChanging(obj:any) {
this._pubSubber.emit(obj);
}
onRouteChanged() {
return this._pubSubber;
}
}
AppComponent订阅了onRouteChanged
事件:
subscription:any;
constructor(private _pubsubService:PubsubService) {
this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {
/**YOUR CUSTOM LOGIC HERE*/});
}
CustomRouterOutlet 在需要时触发 activate
方法中的事件:
activate(nextInstruction: ComponentInstruction): Promise<any> {
//***YOUR CUSTOM LOGIC HERE***
this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);
return super.activate(nextInstruction);
}
通过这种方式,您可以使用任何逻辑轻松实现路由器与 AppComponent
之间的通信。
您必须记得在您的应用程序的 RootComponent
中注入通信服务。
我在
工作"@angular/common": "~2.1.0"
我解决这个问题的方法是创建一个应用程序范围的数据对象 global
和一个服务 GlobalService
。任何组件都可以 subscribe()
全局对象的全部或部分。为了您的目的,您应该创建一个布尔值 属性 isTopBar: true
。您可以订阅您的 <topBar>
组件并使用该值来切换它。
isTopBar: boolean;
ngOnInit(){
this._globalService.getIsTopBar().subscribe(isTopBar => this.isTopBar = isTopBar)
}
<my-topbar *ngIf="isTopBar"></my-topbar>
我发现这种 'GlobalService' 的一大优势是我可以将大量状态信息保存到我的后端。它在您的示例中用处不大,但可以想象您有一组内部选项卡;您可以保存用户最后选择的选项卡,并在他们以后重新访问该页面时重新加载到该视图。
这可能根本不是正确的方法,但它对我有用。它不会根据路线本身改变可见性,而是根据该路线中显示的组件改变可见性。
我已经在使用一种服务来为导航栏提供所有部分等等,所以我认为它也可以告诉导航栏何时出现或不出现。
我主要是在这个服务中创建了一个主题来确定它是否应该可见,并使用一系列方法来改变这种可见性。
@Injectable()
export class NavigationService {
mobileNavbarIsVisible = true;
mobileNavbarIsVisibleChanged = new Subject<boolean>();
constructor() { }
getSections() {
return this.sections;
}
getMobileNavbarIsVisible() {
return this.mobileNavbarIsVisible;
}
hideMobileNavbar() {
this.mobileNavbarIsVisible = false;
this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
}
showMobileNavbar() {
this.mobileNavbarIsVisible = true;
this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
}
}
然后,我在影响可见性的组件中调用那些方法 - 在我的例子中,每次我编辑项目列表中的项目时,我希望导航栏消失 -。我在这个组件启动时调用 hide 方法,在它被销毁时调用 show 方法。
@Component({
selector: 'app-item-edit',
templateUrl: './item-edit.component.html',
styleUrls: ['./item-edit.component.css']
})
export class ItemEditComponent implements OnInit, OnDestroy {
constructor(private navigationService: NavigationService) {}
ngOnInit() {
this.navigationService.hideMobileNavbar();
}
ngOnDestroy() {
this.navigationService.showMobileNavbar();
}
}
然后,我的 NavbarComponent 正在侦听该主题,并根据该值显示或不显示:
@Component({
selector: 'app-mobile-navbar',
templateUrl: './mobile-navbar.component.html',
styleUrls: ['./mobile-navbar.component.css']
})
export class MobileNavbarComponent implements OnInit {
isVisible = true;
ngOnInit() {
this.isVisible = this.navigationService.getMobileNavbarIsVisible();
this.navigationService.mobileNavbarIsVIsibleChanged.subscribe(
(visibilityValue) => this.isVisible = visibilityValue
);
}
}
正如我所说,这很可能不是正确或最有效的方法,但如果您只想在启动其他组件时隐藏导航栏,它会起作用,因为它们只是将导航服务用作一种沟通方式。