【问题标题】:Angular 4 show popup onclick by other componentAngular 4显示弹出点击其他组件
【发布时间】:2018-01-22 10:43:37
【问题描述】:

我正在为这个问题而苦苦挣扎,无法弄清楚。 我只需要从我的 navbar.component 中的菜单条目单击显示位于页面中的弹出 div。

我在弹出窗口中添加了一个属性“show”,它使用 ngClass (with if) 指令在我的 div 上打印“show”类。如果操作按钮在我的弹出组件inside 中,我可以让它工作,但我无法打印单击另一个组件的显示类。对象中的属性得到更新,但未打印类。我正在使用 Angular 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;
    }
}

【问题讨论】:

  • 你能为同一个@SBO创建plunker吗
  • 这听起来可能很傻,但你可以尝试使用像[ngClass]= " {'show' : show} "这样的ngClass
  • 您是在开发模式还是生产模式下运行代码?
  • 开发。我会理解如何在 Angular 4 中操作非嵌套组件的属性(不使用子/父)
  • 如何通知登录组件在导航栏中的显示事件?您已将“显示”列为登录的输入和导航栏的输出,但它们没有连接到我能看到的任何地方。您需要让您的应用组件传递消息或为其提供服务。

标签: javascript angular typescript


【解决方案1】:

这里的问题是您的导航栏和登录组件是同级的,不能直接相互通信。您已显示为导航栏的输出和登录的输入,但您尚未连接点。

您需要更新您的 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 变量并删除所有 2 路绑定,但在更大的应用程序中,您甚至可能想要一个管理隐藏/显示弹出窗口的单独服务。这消除了在组件树上上下发送消息的需要,您可以在需要的地方注入服务。

正如另一位评论者提到的,您还应该使用 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); }
}

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

providers:[PopUpService]

确保您以后不要重新提供此内容,因为您只希望存在一份副本,以便所有人共享。

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

然后在登录组件中绑定到 popUp$ 可观察对象

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

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

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

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

【讨论】:

  • 谢谢布莱恩。您的代码有效,但只是在第一次点击时。我想知道,在您看来,管理具有此功能的弹出窗口的最佳方法是什么: 1)必须在单击登录注册菜单条目时显示弹出窗口。 2) 单击其他组件时必须显示弹出窗口。 3)弹出窗口必须显示在需要登录的私人页面上。你会使用哪种结构?非常感谢!
  • 我添加了一些代码,以反映基于服务的解决方案的外观,作为一个简单的示例。
  • 这非常有效,谢谢!再问一个问题,我确实在每个组件中重用了相同的服务,但是为什么我要在每个组件中实现这 2 个方法(例如:showPopUp() { this.popUpSvc.showPopUp(); })?我不能直接使用从模板调用它的服务方法吗?
  • 您可以,但如果以后发生任何变化,则不建议这样做。您在模板代码中引入了依赖项,这不是一个好习惯。一般来说,你的模板应该只依赖于它的组件文件,并且它们应该尽可能简洁明了。
  • 非常感谢,我明白了很多东西。
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多