我的页面结构是:
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
如何在不刷新整个页面的情况下更新/刷新app-header
组件?
我想在用户成功登录后,在标题中隐藏“登录”链接。标题在所有组件/路由中都是相同的。
我的页面结构是:
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
如何在不刷新整个页面的情况下更新/刷新app-header
组件?
我想在用户成功登录后,在标题中隐藏“登录”链接。标题在所有组件/路由中都是相同的。
你可以使用BehaviorSubject
在整个应用程序中不同的组件之间进行通信。你可以定义一个包含BehaviorSubject
的数据共享服务,向其订阅并发出更改。
定义一个数据共享服务
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataSharingService {
public isUserLoggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
}
将DataSharingService
添加到您的AppModule
提供程序中。
接下来,在<app-header>
和执行登录操作的组件中导入DataSharingService
。在<app-header>
中订阅对isUserLoggedIn
主题的更改:
import { DataSharingService } from './data-sharing.service';
export class AppHeaderComponent {
// Define a variable to use for showing/hiding the Login button
isUserLoggedIn: boolean;
constructor(private dataSharingService: DataSharingService) {
// Subscribe here, this will automatically update
// "isUserLoggedIn" whenever a change to the subject is made.
this.dataSharingService.isUserLoggedIn.subscribe( value => {
this.isUserLoggedIn = value;
});
}
}
在您的 <app-header>
HTML 模板中,您需要添加 *ngIf
条件,例如:
<button *ngIf="!isUserLoggedIn">Login</button>
<button *ngIf="isUserLoggedIn">Sign Out</button>
最后,只需在用户登录后触发该事件,例如:
someMethodThatPerformsUserLogin() {
// Some code
// .....
// After the user has logged in, emit the behavior subject changes.
this.dataSharingService.isUserLoggedIn.next(true);
}
CanActivate
Guard
添加到登录组件路由中。在守卫中,检查令牌是否存在,然后将用户带到所需的路由。 - FAISALngOnInit(): void {
setTimeout(() => { this.ngOnInit() }, 1000 * 10)
}
//10 is the number of seconds
其中一种解决方案是创建一个@Injectable()
类,该类保存您想要在标题中显示的数据。其他组件也可以访问此类并更改此数据,从而有效地更改标题。
另一个选项是设置@Input()
变量和@Output()
EventEmitters,您可以使用它们来更改标题数据。
编辑 按您的要求进行示例:
@Injectable()
export class HeaderService {
private _data;
set data(value) {
this._data = value;
}
get data() {
return this._data;
}
}
在其他组件中:
constructor(private headerService: HeaderService) {}
// Somewhere
this.headerService.data = 'abc';
在头部组件中:
let headerData;
constructor(private headerService: HeaderService) {
this.headerData = this.headerService.data;
}
我其实没有试过这个。如果get/set不起作用,你可以改成使用Subject();
// Simple Subject() example:
let subject = new Subject();
this.subject.subscribe(response => {
console.log(response); // Logs 'hello'
});
this.subject.next('hello');
您只需要使用ChangeDetectorRef
通知Angular更新组件。因此,在您的头部组件中:
constructor(private cd: ChangeDetectorRef) {}
loggedUserEvent(user: User): void {
this.username = user.username;
this.enableDisconnectButton();
//... Add more logic to it
this.cd.detectChanges();
}
这应该足够了
main.html
<app-header [header-data]="headerData"></app-header>
main.component.ts
public headerData:int = 0;
ngOnInit(){
setInterval(()=>{this.headerData++;}, 250);
}
header.html
<p>{{data}}</p>
header.ts
@Input('header-data') data;
关于Angular的生命周期钩子的更多信息,请参见:https://angular.io/guide/lifecycle-hooks
header.component
监听。然后 onChange
生命周期钩子将被触发,头部将更新。 - Zze @Injectable()
export class LoginService{
private isUserLoggedIn: boolean = false;
public setLoggedInUser(flag) { // you need set header flag true false from other components on basis of your requirements, header component will be visible as per this flag then
this.isUserLoggedIn= flag;
}
public getUserLoggedIn(): boolean {
return this.isUserLoggedIn;
}
Login Component ts
Login Component{
constructor(public service: LoginService){}
public login(){
service.setLoggedInUser(true);
}
}
Inside Header component
Header Component ts
HeaderComponent {
constructor(public service: LoginService){}
public getUserLoggedIn(): boolean { return this.service.getUserLoggedIn()}
}
template of header component: Check for user sign in here
<button *ngIf="getUserLoggedIn()">Sign Out</button>
<button *ngIf="!getUserLoggedIn()">Sign In</button>
您可以使用多种方法,例如使用ngIf来显示或隐藏内容。
App Component ts
AppComponent {
public showHeader: boolean = true;
}
App Component html
<div *ngIf='showHeader'> // you show hide on basis of this ngIf and header component always get visible with it's lifecycle hook ngOnInit() called all the time when it get visible
<app-header></app-header>
</div>
<router-outlet></router-outlet>
<app-footer></app-footer>
你也可以使用服务
@Injectable()
export class AppService {
private showHeader: boolean = false;
public setHeader(flag) { // you need set header flag true false from other components on basis of your requirements, header component will be visible as per this flag then
this.showHeader = flag;
}
public getHeader(): boolean {
return this.showHeader;
}
}
App Component.ts
AppComponent {
constructor(public service: AppService){}
}
App Component.html
<div *ngIf='service.showHeader'> // you show hide on basis of this ngIf and header component always get visible with it's lifecycle hook ngOnInit() called all the time when it get visible
<app-header></app-header>
</div>
<router-outlet></router-outlet>
<app-footer></app-footer>
之前的所有答案都很好。但是为了多样性,这里提供一个不同的解决方案:
步骤1 - 在子组件.ts文件中添加一个新的事件发射器作为输出。
步骤2 - 当您的子组件执行所需操作时,触发该输出。
步骤3 - 将输出附加到父组件.html中的子选择器上。
步骤4 - 在父组件中添加必要的函数以更改数据。
完整代码将类似于:
// --- child.ts ---
import { Component, OnInit,Input,Output,EventEmitter } from '@angular/core';
@Output() refreshData = new EventEmitter<{ update: boolean }>(); // note: the 'update' variable isn't needed in the code I've given you, but I've included it in case you want to know how to pass data in the event emitter
@Input() myData: boolean | undefined;
signInOut(){
this.refreshData.emit({update:true})
}
// --- child.html ---
<div>Signed in = {{myData}}</div>
<button (click) = signInOut()>Click me to sign in or out and refresh the data</button>
// --- parent.html ---
<child-selector [myData] = "isSignedIn" (refreshData) = dataChange($event)></child-selector>
// --- parent.ts ---
isSignedIn = false
dataChange(eventData: { update: boolean }){
console.log('test')
this.isSignedIn = !this.isSignedIn
}
希望这能帮到你!