My Page structure is:
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
How can I update/refresh the app-header
component, without refreshing the whole page?
I want to hide a "Sign-In" link in the header, once the user had successfully logged in. The header is common in all the components/routes.
To refresh, or better to say update another component from a different component, we can use the concept of Observables and Subject (which is a kind of Observable). This concept has an added benefit when data are to be received from APIs for CRUD operations.
You cannot prevent page refresh. The browser user can always hit F5. The "onbeforeunload" approach will allow you to warn the user, but you can't prevent it.
You can use a BehaviorSubject
for communicating between different components throughout the app. You can define a data sharing service containing the BehaviorSubject
to which you can subscribe and emit changes.
Define a data sharing service
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable() export class DataSharingService { public isUserLoggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); }
Add the DataSharingService
in your AppModule
providers entry.
Next, import the DataSharingService
in your <app-header>
and in the component where you perform the sign-in operation. In <app-header>
subscribe to the changes to isUserLoggedIn
subject:
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; }); } }
In your <app-header>
html template, you need to add the *ngIf
condition e.g.:
<button *ngIf="!isUserLoggedIn">Login</button> <button *ngIf="isUserLoggedIn">Sign Out</button>
Finally, you just need to emit the event once the user has logged in e.g:
someMethodThatPerformsUserLogin() { // Some code // ..... // After the user has logged in, emit the behavior subject changes. this.dataSharingService.isUserLoggedIn.next(true); }
To refresh the component at regular intervals I found this the best method. In the ngOnInit method setTimeOut function
ngOnInit(): void { setTimeout(() => { this.ngOnInit() }, 1000 * 10) } //10 is the number of seconds
One of many solutions is to create an @Injectable()
class which holds data that you want to show in the header. Other components can also access this class and alter this data, effectively changing the header.
Another option is to set up @Input()
variables and @Output()
EventEmitters which you can use to alter the header data.
Edit Examples as you requested:
@Injectable()
export class HeaderService {
private _data;
set data(value) {
this._data = value;
}
get data() {
return this._data;
}
}
in other component:
constructor(private headerService: HeaderService) {}
// Somewhere
this.headerService.data = 'abc';
in header component:
let headerData;
constructor(private headerService: HeaderService) {
this.headerData = this.headerService.data;
}
I haven't actually tried this. If the get/set doesn't work you can change it to use a Subject();
// Simple Subject() example:
let subject = new Subject();
this.subject.subscribe(response => {
console.log(response); // Logs 'hello'
});
this.subject.next('hello');
You just need to notify Angular to update the component with a ChangeDetectorRef
. So, inside your header component:
constructor(private cd: ChangeDetectorRef) {}
loggedUserEvent(user: User): void {
this.username = user.username;
this.enableDisconnectButton();
//... Add more logic to it
this.cd.detectChanges();
}
That should be enough
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With