Angular - 来自另一个组件

时间:2018-01-03 07:35:32

标签: angular typescript

我使用角度(最新版本)和角度材料。

有3个组成部分:

  • header.component,其中有一个右侧的控制按钮
  • rigth-sidenav.component,其中是right-sidenav
  • sidenav.component(这是左侧主菜单),此组件调用header.component,right-sidenav.component和content

我第一次使用Angular,请告诉我,如何打开/关闭另一个组件的sidenav(在我的例子中,按钮位于header.component中)。

尝试了以下选项(但得到了错误:TypeError:this.RightSidenavComponent.rightSidenav未定义):

header.component.html



<button mat-button (click)="toggleRightSidenav()">Согласование до 16:00 сегодня</button>
&#13;
&#13;
&#13;

header.component.ts

&#13;
&#13;
import { Component } from '@angular/core';
import { RightSidenavComponent } from '../right-sidenav/right-sidenav.component';
@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss']
})
export class HeaderComponent {

	constructor(public RightSidenavComponent:RightSidenavComponent) {	}
	toggleRightSidenav() {
		this.RightSidenavComponent.rightSidenav.toggle();
	}
	
}
&#13;
&#13;
&#13;

sidenav.component.html

&#13;
&#13;
<mat-sidenav-container class="sidenav-container">
	<mat-sidenav #sidenav mode="side" opened="true" class="sidenav"
				 [fixedInViewport]="true"> Sidenav	</mat-sidenav>
	<mat-sidenav-content>
		<app-header></app-header>
		<router-outlet></router-outlet>
		<app-right-sidenav #rSidenav></app-right-sidenav>
	</mat-sidenav-content>
</mat-sidenav-container>
&#13;
&#13;
&#13;

sidenav.component.ts

&#13;
&#13;
import { Component, Directive, ViewChild } from '@angular/core';
import { RightSidenavComponent } from '../right-sidenav/right-sidenav.component';

@Component({
  selector: 'app-sidenav',
  templateUrl: './sidenav.component.html',
  styleUrls: ['./sidenav.component.scss']
})

export class SidenavComponent {
	
	@ViewChild('rSidenav') public rSidenav;
	constructor(public RightSidenavComponent: RightSidenavComponent) {
		this.RightSidenavComponent.rightSidenav = this.rSidenav;
	}
	
}
&#13;
&#13;
&#13;

右sidenav.component.html

&#13;
&#13;
<mat-sidenav #rightSidenav mode="side" opened="true" class="rightSidenav"
			 [fixedInViewport]="true" [fixedTopGap]="250">
	Sidenav
</mat-sidenav>
&#13;
&#13;
&#13;

右sidenav.component.ts

&#13;
&#13;
import { Component, Injectable } from '@angular/core';

@Component({
  selector: 'app-right-sidenav',
  templateUrl: './right-sidenav.component.html',
  styleUrls: ['./right-sidenav.component.scss']
})

@Injectable()
export class RightSidenavComponent {
	
	public rightSidenav: any;

	constructor() { }

}
&#13;
&#13;
&#13;

Non-working sample with code stackblitz

8 个答案:

答案 0 :(得分:28)

我遇到了同样的问题。我这样解决了。

SidenavService

import { Injectable } from '@angular/core';
import { MatSidenav } from '@angular/material';

@Injectable()
export class SidenavService {
    private sidenav: MatSidenav;


    public setSidenav(sidenav: MatSidenav) {
        this.sidenav = sidenav;
    }

    public open() {
        return this.sidenav.open();
    }


    public close() {
        return this.sidenav.close();
    }

    public toggle(): void {
    this.sidenav.toggle();
   }

您的组件

constructor(
private sidenav: SidenavService) { }

toggleRightSidenav() {
   this.sidenav.toggle();
}
  

根据您的要求绑定您的html toggle()。

应用组件。

@ViewChild('sidenav') public sidenav: MatSidenav;

constructor(private sidenavService: SidenavService) {
}

ngOnInit(): void {
  this.sidenavService.setSidenav(this.sidenav);
}

应用模块

providers: [YourServices , SidenavService],

Working sample with code stackblitz

答案 1 :(得分:5)

如果您使用的是Angular 9+,请记住在static: true中添加@ViewChild的参数,例如:

@ViewChild('rightSidenav', {static: true}) sidenav: MatSidenav;

您可以在这里看到我的代码在Angular 9上运行:

https://stackblitz.com/edit/angular-kwfinn-matsidenav-angular9

答案 2 :(得分:2)

我在父组件的另一个组件中使用了#> set.seed(1337) #> tmp<-data.frame(p = runif(99999999)*.007) #> microbenchmark::microbenchmark(+(tmp[["p"]]<0.001) , ifelse(tmp[["p"]]<0.001, 1, 0), times = 4) #Unit: milliseconds # expr min lq mean median uq max neval cld # +(tmp[["p"]] < 0.001) 463.054 527.4309 1779.396 1440.110 3031.362 3774.312 4 a # ifelse(tmp[["p"]] < 0.001, 1, 0) 7071.470 7140.4354 8021.247 7887.672 8902.058 9238.173 4 b ,以将sideNav对象作为子组件的目标属性传递。它按预期工作。顺便说一句,我喜欢@Eldho的服务实现:)

Child.component.html

@Input() remoteSideNav: MatSideNav

layout-header.component.html

<app-layout-header [inputSideNav]="sideNav"></app-layout-header>
<mat-sidenav-container>
  <mat-sidenav #sideNav (click)="sideNav.toggle()" mode="side">
    <a routerLink="/">List Products</a>
  </mat-sidenav>
  <mat-sidenav-content>
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>

layout-header.component.ts

<section>
  <mat-toolbar>
    <span (click)="inputSideNav.toggle()">Menu</span>
  </mat-toolbar>
</section>

答案 3 :(得分:1)

首先,您不需要在sideNav组件中调用rightSideNav。 您的切换按钮位于标题组件中。 因此,您可以在标题组件中执行此操作。

header.component.ts:

    import { Component } from '@angular/core';
    import { RightSidenavComponent } from '../right-sidenav/right-sidenav.component';
    @Component({
      selector: 'app-header',
      templateUrl: './header.component.html',
      styleUrls: ['./header.component.scss']
    })
    export class HeaderComponent {
        rightSideNav : boolean ;
        constructor(public RightSidenavComponent:RightSidenavComponent) {   }


        sideNavBtnToggle(){
        if(this.rightSideNav == false)
        {
               this.rightSideNav = true;
        }
        else{
               this.rightSideNav = false;
        } 
}
}

header.component.html

把这段代码:

<app-right-sidenav *ngIf="rightSideNav"></app-right-sidenav>

这将使您的工作变得轻松。

答案 4 :(得分:1)

为了更简单的解决方案,只需使用@ouput() 事件发射器。

在你的父组件中

 <mat-sidenav
    #sidenav
    class="sidenav"
    fixedInViewport
    [opened]="opened"
    [mode]="mode"
  >
// catch the emitted output from child component 
<childcomponent (sidenav)="sidenav.toggle()"></childcomponent>
....
</mat-sidenav>

子组件

<mat-toolbar>
 <div>
  <button mat-button (click)="toggle()">
   <mat-icon>menu</mat-icon>
  </button>
 </div>
</mat-toolbar>

子组件.ts

import {Component, EventEmitter, Output} from '@angular/core';

@Component({
  selector: 'childcomponent',
  templateUrl: './childcomponent.component.html',
  styleUrls: ['./childcomponent.component.scss'],
})
export class ChildComponent {
 @Output() sidenav: EventEmitter<any> = new EventEmitter();

toggle() {
 this.sidenav.emit();
 }
}

答案 5 :(得分:0)

只需添加到Eldho的答案中,您就可以禁用动画以获得真正的隐藏效果。

    <mat-sidenav #leftbar opened mode="side" class="ng-sidenav" [@.disabled]="true">

答案 6 :(得分:0)

尽管上面的人已经回答了,但是我相信当我自己解决问题时,我的解决方案会更简单。

您需要在中间提供一项服务来支持这两个组件。

比方说,这样的服务是NavService,下面的代码进入NavService

public toggleNav: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  public toggle(): void {
    this.toggleNav.next(!this.toggleNav.value);
  }

然后,您有一个要从中打开或关闭SideNav的组件。就我而言,我在Navbar中创建的按钮为:

button *ngIf="this.loginService.tokenSubject.value"  mat-mini-fab color="warn" (click)="onToggle()"><mat-icon>menu</mat-icon></button>

然后在您将为SideNavComponent创建的SideNav中,将其放在mat-sidenav标记中:

[opened]="this.sideNavService.toggleNav.value"

当然,我在该组件的构造函数中将NavService作为sideNavService注入了。

答案 7 :(得分:0)

为了扩展 eldho 服务响应,我在单击时出错 this.sidenav 未定义'我通过确保我的 Side nav 被标记为 #sidenav 以匹配 app.component.ts 文件上的选择器来修复它。

还有 mat-drawer-container 和 mat-drawer 似乎是 sidenav 的新名称

<mat-drawer-container autosize>
   <mat-drawer #sidenav class="example-sidenav" mode="side" position="end">
    
   </mat-drawer>

   <mat-drawer-content autosize="true">
   
   </mat-drawer-content>
</mat-drawer-container>

app.component.ts

@ViewChild('sidenav') public sidenav: MatSidenav;