gpt4 book ai didi

Angular 4 : passing breadcrumb view components through the router's `data` property

转载 作者:太空狗 更新时间:2023-10-29 19:29:21 25 4
gpt4 key购买 nike

在我的 Angular (v4) 应用程序中,我正在尝试创建一个面包屑导航模块。我找到了 this S.O. question有帮助,建议我像这样将面包屑信息存储在路由器的 data 属性中

{ path: '', component: HomeComponent, data: {breadcrumb: 'home'}}

但我想做的是在数据属性中存储一个组件,然后让面包屑模块​​提取并呈现它。允许我像这样与面包屑模块​​交互

{ path: '', component: HomeComponent, data: {breadcrumb: CustomViewComponent}}

跟随 Angular Dynamic Component Loader guide和一个 helpful blog post ,我试图让我的面包屑渲染组件这样做:

import { Component, Input, OnInit, AfterViewInit,
ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';

import { MainLogoComponent } from '../my-material/main-logo/main-logo.component';

@Component({
selector: 'app-breadcrumbs',
template: `<div #parent></div>`,
styleUrls: ['./breadcrumbs.component.scss']
})
export class BreadcrumbsComponent implements OnInit, AfterViewInit {
breadcrumbs: Array<any>;
@ViewChild('parent', {read: ViewContainerRef}) parent: ViewContainerRef;

constructor(private componentFactoryResolver: ComponentFactoryResolver,
private router:Router, private route:ActivatedRoute) { }

ngOnInit() {
this.router.events
.filter(event => event instanceof NavigationEnd)
.subscribe(event => { // note, we don't use event
this.breadcrumbs = [];
let currentRoute = this.route.root,
url = '';
do {
let childrenRoutes = currentRoute.children;
currentRoute = null;
childrenRoutes.forEach(route => {
if(route.outlet === 'primary') {
let routeSnapshot = route.snapshot;
url += '/' + routeSnapshot.url.map(segment => segment.path).join('/');
this.breadcrumbs.push({
label: route.snapshot.data.breadcrumb,
url: url });
currentRoute = route;
}
})
} while(currentRoute);
})
}

ngAfterViewInit() {
const logoComponent = this.componentFactoryResolver
.resolveComponentFactory(this.breadcrumbs[0]); // at the moment just using breadcrumbs[0] for simplicity
this.parent.createComponent(logoComponent);
}
}

不幸的是,路由数据属性似乎不能/不会存储组件。深入调试控制台,数据属性被保存为 {data: {breadcrumb: }}

如果有人知道让这段代码工作的方法,或者有更好的建议来实现我构建使用其他 View 组件的面包屑组件的目标,我会非常感谢!!

PS:如果我跳过 data 属性,只是手动要求面包屑组件将 MainLogoComponent 添加到页面,如下所示:

ngAfterViewInit() {
const logoComponent = this.componentFactoryResolver.resolveComponentFactory(MainLogoComponent);
this.parent.createComponent(logoComponent);
}

有效

并且,为了完整起见,关联路由的代码。

const routes: Routes = [
{
path: 'calendar',
data: {
breadcrumb: MainLogoComponent
},
canActivate: [ AuthGuard ],
children: [
{
path: '',
component: CalendarComponent
}
]
}
];

更新

这是相关的 NgModule:

@NgModule({
imports: [
CommonModule,
MyMaterialModule
],
exports: [
BreadcrumbsComponent
],
entryComponents: [BreadcrumbsComponent, MainLogoComponent],
declarations: [BreadcrumbsComponent] // MainLogoComponent is declared in MyMaterialModule
})
export class BreadcrumbsModule { }

最佳答案

所以我让它按照我想要的方式工作(非常感谢@yurzui 花时间创建一个 plnkr 来展示它应该工作,在概念上!!!!!!真的真的帮了大忙,我非常感激!!)。我仍然不确定我哪里做错了,但我创建了一个新应用程序来制作面包屑模块​​,使其正常工作,然后将其移植到我的真实应用程序中。我发现,一个可能的问题是 ng serve 似乎偶尔会错过我更改过的重新编译文件(或者我的浏览器可能存在缓存错误)。现在有好几次,编译器都吐出有关我已删除的变量的错误,当我重新启动 ng serve(不更改任何内容)时,错误消失了。对其他人解决问题的警告(尽管它可能与我的开发设置无关)。

这是最终的工作面包屑代码(请注意,如果您试图复制我的方法,还请通读原始问题中的信息/链接)。

import { Component, AfterViewInit, ViewChild, ComponentFactoryResolver, ViewContainerRef } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';

import { BreadDividerComponent } from './bread-divider/bread-divider.component';

@Component({
selector: 'app-breadcrumbs',
template: `
<div #breadContainer></div>
<div #iconContainer></div>
<div #lastBreadContainer></div>`
})
export class BreadcrumbsComponent implements AfterViewInit {
breadcrumbs: Array<any>;
storedBreadcrumbs: Array<Component>;
@ViewChild('breadContainer', {read: ViewContainerRef}) breadContainer: ViewContainerRef;
@ViewChild('iconContainer', {read: ViewContainerRef}) iconContainer: ViewContainerRef;
@ViewChild('lastBreadContainer', {read: ViewContainerRef}) lastBreadContainer: ViewContainerRef;

constructor(private componentFactoryResolver: ComponentFactoryResolver,
private router: Router) { }

ngAfterViewInit() {
this.router.events
.filter(event => event instanceof NavigationEnd)
.subscribe(event => {
// Reset variables and clear breadcrumb component on view change
this.breadcrumbs = [];
this.storedBreadcrumbs = [];
this.breadContainer.clear();
this.iconContainer.clear();
this.lastBreadContainer.clear();

// Drill down through child routes
let currentRoute = this.router.routerState.snapshot.root.firstChild;
if (currentRoute) {
do {
this.breadcrumbs.push(currentRoute.data.breadcrumb);
currentRoute = currentRoute.firstChild;
} while (currentRoute)
}

// Because each route's home path is actually itself a child route
// e.g. { path: 'two', children: [ { path: '', component: ... } ] }
if (this.breadcrumbs.length === 2
&& this.breadcrumbs[0] === this.breadcrumbs[1]) {
this.breadcrumbs = [this.breadcrumbs[0]];
}

this.breadcrumbs.forEach((breadcrumb, index, array) => {
if (array.length > 1) {
if (index < array.length - 1) {
const breadFactory = this.componentFactoryResolver
.resolveComponentFactory(breadcrumb);
this.storedBreadcrumbs.push(this.breadContainer.createComponent(breadFactory));

const iconFactory = this.componentFactoryResolver
.resolveComponentFactory(BreadDividerComponent);
this.storedBreadcrumbs.push(this.iconContainer.createComponent(iconFactory));
} else {
const breadFactory = this.componentFactoryResolver
.resolveComponentFactory(breadcrumb);
this.storedBreadcrumbs.push(this.lastBreadContainer.createComponent(breadFactory));
}
} else {
const breadFactory = this.componentFactoryResolver
.resolveComponentFactory(breadcrumb);
this.storedBreadcrumbs.push(this.lastBreadContainer.createComponent(breadFactory));
}
});
});
}
}

面包屑 View 组件通过路由器的数据属性传递,如下所示:

const routes: Routes = [
{
path: 'calendar',
data: {
breadcrumb: CalendarBreadcrumbComponent,
menu: CalendarMenuComponent
},
canActivate: [ AuthGuard ],
children: [
{
path: 'events',
data: {
breadcrumb: EventsBreadcrumbComponent
},
component: EventsComponent
},
{
path: '',
pathMatch: 'full',
redirectTo: 'events'
}
]
}
];

我也使用这种策略来构建我的应用菜单。这是面包屑 View 组件的示例

import { Component, HostBinding } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
selector: 'app-calendar-breadcrumb',
templateUrl: './calendar-breadcrumb.component.html',
styleUrls: ['./calendar-breadcrumb.component.scss']
})
export class CalendarBreadcrumbComponent {
// Modify this components parent element so that it is displayed with flexbox
@HostBinding('attr.style') style = this.sanitizer
.bypassSecurityTrustStyle('display: flex; flex-direction: row;');

constructor(private sanitizer: DomSanitizer) {}
}

和关联的 View 文件(我现在意识到,它真的不需要它自己的文件...)

<md-icon>event</md-icon><h3>Calendar</h3>

关于 Angular 4 : passing breadcrumb view components through the router's `data` property,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43648410/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com