Angular 4显示其他组件

时间:2017-08-14 14:43:44

标签: javascript angular typescript

我正在努力解决这个问题并且无法弄清楚。 我只需要在我的navbar.component中的菜单条目中单击页面中的弹出窗口。

我添加了一个属性" show"在我的弹出窗口打印" show"在我的div上使用ngClass(with if)指令。如果动作按钮我的弹出组件中,我可以使用它,但我无法打印show class点击另一个组件。对象中的属性更新但不打印该类。我使用角度4和ng-bootstrap。我尝试了服务和父/子发射事件。

这是我的情况:

app.component.html

<app-nav-bar></app-nav-bar>
<app-login></app-login>
<router-outlet></router-outlet>
<app-footer></app-footer>

navbar.component.html

...
 <button class="dropdown-item" (click)="showPopup()">LOGIN</button>
...

navbar.component.ts

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

@Component({
    moduleId: module.id,
    selector: 'app-nav-bar',
    templateUrl: 'navbar.component.html',
    styleUrls: ['./navbar.component.css'],
})

export class NavbarComponent implements OnInit {
    @Output() show = new EventEmitter<boolean>();

    ngOnInit() {
    }


    showPopup() {
        this.show.emit(true);
    }
}

login.component.html

<div id="wrapper-login-popup" class="fade-from-top" [(class.show)]="show">
    <div id="container-login-popup">
        <div class="row">
            <div class="col-sm-12 text-center">
                <img id="popup-bomb" src="assets/images/bomb.png" alt="bomb"/>
                <img id="popup-close" class="close-icon" src="assets/images/close.png" alt="close"
                     (click)="closePopup()"/>
            </div>
        </div>
   </div>
</div>

login.component.ts

import {Component, Input, OnInit} from '@angular/core';
import {AuthService} from '../services/auth.service';
import {IUser} from './user';

@Component({
    selector: 'app-login',
    templateUrl: 'login.component.html',
    styleUrls: ['login.css']
})

export class LoginComponent implements OnInit {
    private username: string;
    private password: string;

    @Input() show: boolean = false;

    constructor(private AuthService: AuthService) {
    }

    ngOnInit() {
    }

    login() {
        ...
    }

    showPopup() {
        console.log(this); //Show is false
        this.show = true;
        console.log(this); //Show is true but does not trigger the show class
    }

    closePopup() {
        this.show = false;
    }
}

1 个答案:

答案 0 :(得分:4)

这里的问题是你的导航栏和登录组件是兄弟姐妹,不能直接相互通信。您已将show显示为导航栏的输出并作为登录输入,但您尚未连接点。

您需要更新app.component才能连接它们。

export class AppComponent implements OnInit {
    show = false;
    onShow() { this.show = true; }
}

并在模板中:

<app-nav-bar (show)="onShow()"></app-nav-bar>
<app-login [(show)]="show"></app-login>

这里有很多双向绑定,这对于简单的谎言来说很有用,但一般来说这是一个坏主意,因为它会导致无法维护的代码。您应该选择show变量的一个所有者并通过他强制对其进行所有更改。在这种情况下,应用程序组件是最合乎逻辑的所有者,因此我更改登录组件以发出更改应用程序组件中的show变量的事件,并删除所有双向绑定,但在更大的应用程序中,您甚至可能想要一个管理隐藏/显示弹出窗口的单独服务。这样就无需在组件树中上下发送消息,您可以将服务注入所需的位置。

正如另一位评论者所提到的,你也应该使用ngClass进行类操作,如

[ngClass]="{'show':show}"

基于服务的解决方案看起来像

import {Subject} from 'rxjs/Subject';
@Injectable()
export class PopUpService {
    private showPopUpSource = new Subject();
    showPopUp$ = this.showPopUpSource.asObservable();
    showPopUp() { this.popUpSource.next(true); }
    closePopUp() { this.popUpSource.next(false); }
}

然后您在app模块或app组件级别提供:

providers:[PopUpService]

请确保您以后不再提供此内容,因为您只需要存在一个副本,以便每个人都共享它。

然后注入两个组件,让他们调用服务关闭或显示弹出方法。

然后在登录组件中绑定到popUp $ observable,如

constructor(private popUpSvc:PopUpService){}
show$;
ngOnInit() { this.show$ = this.popUpSvc.showPopUp$; }
showPopUp() { this.popUpSvc.showPopUp(); }
closePopUp() { this.popUpSvc.closePopUp(); }

并在模板中订阅w async管道,如

<div id="wrapper-login-popup" class="fade-from-top" [ngClass]="{'show': (show$ | async) }">

使用异步管道的原因是垃圾回收managemetn更简单。如果您不使用异步,则需要通过调用unsubscribe()手动在ngOnDestroy中进行垃圾收集,否则您的订阅将继续堆叠。异步管道触发更改检测还有一个更细微的好处,但只有在开始使用onPush更改检测进行性能优化时,这才会变得非常重要。