Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 角度2:显示不同的“;工具栏“;取决于主导航的组件_Angular_Angular2 Routing_Angular2 Template - Fatal编程技术网

Angular 角度2:显示不同的“;工具栏“;取决于主导航的组件

Angular 角度2:显示不同的“;工具栏“;取决于主导航的组件,angular,angular2-routing,angular2-template,Angular,Angular2 Routing,Angular2 Template,这是一个关于如何使用Angular 2以“正确”的方式实现所需功能的概念性问题 我的应用程序有一个导航菜单、一个工具栏和一个内容区。后者包含主要的,并显示不同的视图,如列表和详细信息 我想要实现的是,工具栏显示不同的组件,具体取决于内容区域中呈现的组件/视图。例如,列表组件需要工具栏中的搜索控件,而详细信息组件需要保存按钮 A)我的第一次尝试是将另一个(命名的)添加到工具栏,并基于静态路由显示工具栏组件。这有什么不对的地方: 静态内容工具栏关系的耦合过于松散,不合我的口味 该关系在URL中可见(

这是一个关于如何使用Angular 2以“正确”的方式实现所需功能的概念性问题

我的应用程序有一个导航菜单、一个工具栏和一个内容区。后者包含主要的
,并显示不同的视图,如列表和详细信息

我想要实现的是,工具栏显示不同的组件,具体取决于内容区域中呈现的组件/视图。例如,列表组件需要工具栏中的搜索控件,而详细信息组件需要保存按钮

A)我的第一次尝试是将另一个(命名的)
添加到工具栏,并基于静态路由显示工具栏组件。这有什么不对的地方:

  • 静态内容工具栏关系的耦合过于松散,不合我的口味
  • 该关系在URL中可见(且可更改)
  • 即使用户离开,工具栏出口也会保持此路径
  • B)我的第二次尝试是在主视图组件的
    ngOnInit
    中强制导航到工具栏组件(也使用命名的工具栏出口),这将使它更紧密地结合在一起。什么气味难闻:

  • A2
  • A3,为了防止出现这种情况,我可以“清除”Ngondestory上的工具栏出口,但我还没有找到方法
  • C)给路由器最后一次机会,因为我发现这种方法是有效的:

    const ROUTES:ROUTES=[
    {路径:“建筑物”,儿童:[
    {path:,组件:BuildingListComponent,路径匹配:“full”,出口:“primary”},
    {路径:,组件:BuildingListToolbarComponent,路径匹配:“完整”,出口:“工具栏”},
    {路径:“:id”,组件:BuildingDashboardComponent,出口:“主”}
    ]}
    ];
    
    这个想法是路由器将选择每个插座的匹配路径。但是(不,这可能很容易)不幸的是,这不起作用:

    const ROUTES:ROUTES=[
    {路径:“建筑物”,儿童:[
    {路径:“列表”,组件:BuildingListComponent,路径匹配:“完整”,出口:“主”},
    {路径:“列表”,组件:BuildingListToolbarComponent,路径匹配:“完整”,出口:“工具栏”},
    {路径:“:id”,组件:BuildingDashboardComponent,出口:“主”}
    ]}
    ];
    
    它显然(可能是偶然)只在空路径下工作。为什么,为什么

    D)一个完全不同的策略是修改我的组件层次结构,以便每个主视图组件都包含一个适当的工具栏,并使用。我还没有尝试过这个,但是我担心工具栏的多个实例会出现问题


    有时,这似乎是一个常见的用例,我想知道Angular 2专家会如何解决这个问题。有什么想法吗?

    正如Günter Zöchbauer(谢谢!)所建议的,我最终在工具栏上添加和删除了动态组件。所需的工具栏组件在路由的数据属性中指定,并由包含工具栏的中心组件(导航栏)进行评估。
    请注意,导航栏组件不需要了解工具栏组件的任何信息(这些组件在feauture模块中定义)。
    希望这对别人有帮助

    建筑物布线.module.ts

    const ROUTES:ROUTES=[
    {路径:“建筑物”,儿童:[
    {
    路径:“”,
    组件:BuildingListComponent,
    路径匹配:“满”,
    数据:{工具栏:BuildingListToolbarComponent}
    },
    {
    路径:“:id”,
    组件:BuildingDashboardComponent,
    数据:{工具栏:BuildingDashboardToolbarComponent}
    }
    ]}
    ];
    @NGD模块({
    进口:[
    RouterModule.forChild(路由)
    ],
    出口:[
    路由模块
    ]
    })
    导出类BuildingRoutingModule{
    }
    
    navbar.component.html

    
    
    navbar.component.ts

    @组件({
    选择器:“导航栏”,
    templateUrl:'./navbar.component.html',
    样式URL:['./navbar.component.scss']
    })
    导出类NavbarComponent实现OnInit、OnDestroy{
    @ViewChild(“toolbarTarget”,{read:ViewContainerRef})
    工具栏目标:ViewContainerRef;
    toolbarComponents:ComponentRef[]=新数组();
    routerEventSubscription:ISubscription;
    构造函数(专用路由器:路由器、,
    专用componentFactoryResolver:componentFactoryResolver){
    }
    ngOnInit():void{
    this.routerEventSubscription=this.router.events.subscribe(
    (事件:事件)=>{
    if(NavigationEnd的事件实例){
    this.updateToolbarContent(this.router.routerState.snapshot.root);
    }
    }
    );
    }
    ngOnDestroy():void{
    此.routereventsubscribe.unsubscribe();
    }
    私有updateToolbarContent(快照:ActivatedRouteSnapshot):无效{
    这个.clearToolbar();
    让toolbar:any=(snapshot.data为{toolbar:Type});
    if(类型的工具栏实例){
    让工厂:ComponentFactory=this.componentFactoryResolver.resolveComponentFactory(工具栏);
    让componentRef:componentRef=this.toolbarTarget.createComponent(工厂);
    这个.toolbarComponents.push(componentRef);
    }
    for(让snapshot.children的childSnapshot){
    此.updateToolbarContent(childSnapshot);
    }
    }
    专用clearToolbar(){
    this.toolbarTarget.clear();
    for(让toolbarComponents成为此.toolbarComponents的一部分){
    toolbarComponent.destroy();
    }
    }
    }
    
    参考文献:




    我的角度6解决方案

    我遇到了一些延迟加载模块的问题,最终通过添加
    import { ParamMap } from '@angular/router';
    
    import { SEvent, SService } from '../s-service.service';
    
    import { Observable } from 'rxjs';
    import { switchMap, tap } from 'rxjs/operators';
    
    import { Component, OnInit, OnDestroy, ViewChild, ViewContainerRef, ComponentRef, ComponentFactory, ComponentFactoryResolver, Type  } from '@angular/core';
    
    import { SubscriptionLike } from 'rxjs';
    import { Router, NavigationEnd, ActivatedRouteSnapshot, ResolveStart, ChildActivationEnd, ActivatedRoute } from '@angular/router';
    import { Event } from '@angular/router';
    import { filter, take } from 'rxjs/operators';
    
    @Component({
      selector: 'app-list',
      templateUrl: './s-list.component.html',
      styleUrls: ['./s-list.component.scss']
    })
    export class SListComponent implements OnInit, OnDestroy {
    
      isActive = false;
    
      @ViewChild("toolbarTarget", {read: ViewContainerRef}) toolbarTarget: ViewContainerRef;
    
      toolbarComponents: ComponentRef<Component>[] = new Array<ComponentRef<Component>>();
      routerEventSubscription: SubscriptionLike;
    
        seismicEvents: Observable<SEvent[]>;
        selectedId: number;
    
       constructor(private service: SService,
        private router: Router,
        private route: ActivatedRoute,
        private componentFactoryResolver: ComponentFactoryResolver) { }
    
        ngOnInit() {
            this.sEvents = this.route.paramMap.pipe(
                switchMap((params: ParamMap) => {
                        this.selectedId = +params.get('id');
                        return this.service.getSEvents();
                    })
          );
    
          // used this on component init to trigger updateToolbarContent 
          this.updateToolbarContent(this.route.snapshot);
    
          // kept this like above (with minor modification) to trigger subsequent changes
          this.routerEventSubscription = this.router.events.pipe(
            filter(e => e instanceof ChildActivationEnd),
            take(1)
          ).subscribe(
            (event: Event) => {
                if (event instanceof ChildActivationEnd) {
                  this.updateToolbarContent(this.route.snapshot);
                }
            }
          );
       }
    
      ngOnDestroy() {
        this.routerEventSubscription.unsubscribe();
      }
    
      private clearToolbar() {
        this.toolbarTarget.clear();
        for (let toolbarComponent of this.toolbarComponents) {
            toolbarComponent.destroy();
        }
      }
    
      private updateToolbarContent(snapshot: ActivatedRouteSnapshot) {
    
        // some minor modifications here from above for my use case
    
        this.clearToolbar();
        console.log(snapshot);
        let toolbar: any = (snapshot.data as {toolbar: Type<Component>}).toolbar;
        if (toolbar instanceof Type) {
          let factory: ComponentFactory<Component> = this.componentFactoryResolver.resolveComponentFactory(toolbar);
          let componentRef: ComponentRef<Component> = this.toolbarTarget.createComponent(factory);
          this.toolbarComponents.push(componentRef);
        }
      }
    }
    
    <app-toolbar></app-toolbar>
    
    <ng-template #toolbaractions>
      <button (click)="refresh()">refresh</button>
    </ng-template>
    
    export class S3BrowsePageComponent implements AfterViewInit {
    
        @ViewChild('toolbaractions', { read: TemplateRef })
        public toolbaractions: TemplateRef<any>;
    
        menu = new BehaviorSubject<TemplateRef<any>>(null);
    
        ngAfterViewInit(): void {
            this.menu.next(this.toolbaractions)
        }
        ...
    
    <toolbar>
       <ng-container [ngTemplateOutlet]="menu"></ng-container>
    </toolbar>
    
    <sidenav>...</sidenav>
    
    <maincontent>
        <router-outlet (activate)='onActivate($event)'
                   (deactivate)='onDeactivate($event)'></router-outlet>
    </maincontent>
    
    onActivate($event: any) {
      console.log($event);
      if ($event.hasOwnProperty('menu')) {
        this.menuSubscription = $event['menu']
          .subscribe((tr: TemplateRef<any>) => this.menu = tr)
        }
      }
    }
    
    onDeactivate($event: any) {
      this.menu = null;
      this.menuSubscription.unsubscribe();
    }