Currently, I am dealing with an angular project, I need to trigger an event on routing change/URL change from one page to another page (as it is an angular project page wont be refreshed).
I have tried with different scenarios in index.html page like below:
window.onbeforeunload = function () {
//not fit;
});
window.onhashchange = function () {
//not fit;
});
Can we have any other solutions to trigger an event on url change (I don't want to use listeners in angular).
You can do this by implementing hashchange even on window
And if you are using jQuery, this plugin might help you.
Or in your case check pure JS code
function hashHandler() {
this.oldHash = window.location.hash;
this.Check;
var that = this;
var detect = function() {
if(that.oldHash != window.location.hash) {
alert("HASH CHANGED - new has" + window.location.hash);
that.oldHash = window.location.hash;
}
};
this.Check = setInterval(function() { detect() }, 100);
}
var hashDetection = new hashHandler();
Pure demo code example for angular with router:
import { Component, OnInit } from '#angular/core'; // I import Location so that I can query the current path
import { Location } from '#angular/common'; // I also import Router so that I can subscribe to events
import { Router } from '#angular/router';
#Component(
{ selector: 'app-top-nav',
templateUrl: './top-nav.component.html',
styleUrls: ['./top-nav.component.scss'] }
)
export class TopNavComponent implements OnInit {
route: string;
constructor(location: Location, router: Router) { // within our constructor we can define our subscription
// and then decide what to do when this event is triggered.
// in this case I simply update my route string.
router.events.subscribe((val) => { if(location.path() != '') { this.route = location.path(); } else { this.route = 'Home' } });
}
ngOnInit() {
}
}
The above code should work.
Related
I'm Facing an issue with the window.postMessage is firing multiple times whenever I returned to that component so I would like to get a solution for this issue. Thank you.
ngOnInit() {
this.service.userDetails = JSON.parse(localStorage.getItem('userDetails'))
window["ReactNativeWebView"] && window["ReactNativeWebView"].postMessage(JSON.stringify({"change": false}))
console.log("notifyReact")
if(this.service.userDetails==null)
this.router.navigate(['health/login'])
else {
this.getPatientList()
this.getDoctorList()
}
}
Well, ngOnInit is fired every time the component intializes, so whenever you return to it that piece of code is going to be executed.
An easy solution would be having a little service injected in root that holds a variable such as:
#Injectable({ providedIn: 'root' })
export class MyService
initialized: boolean = false;
}
and then in your component:
constructor(private myService:MyService) {}
ngOnInit() {
this.service.userDetails = JSON.parse(localStorage.getItem('userDetails'))
if(!myService.initialized) {
window["ReactNativeWebView"] && window["ReactNativeWebView"].postMessage(JSON.stringify({"change": false}))
console.log("notifyReact")
myService.initialized = true;
}
if(this.service.userDetails==null)
this.router.navigate(['health/login'])
else {
this.getPatientList()
this.getDoctorList()
}
Our AngularJS project had start it's long way to the modern Angular.
The ngMigration util recommend me to remove all the $rootScope dependecies because Angular doesn't contain a similar concept like $rootScope. It is pretty simple in some cases but I don't know what to do with event subscription mechanisms.
For example I have a some kind of Idle watchdog:
angular
.module('myModule')
//...
.run(run)
//...
function run($rootScope, $transitions, Idle) {
$transitions.onSuccess({}, function(transition) {
//...
Idle.watch(); // starts watching for idleness
});
$rootScope.$on('IdleStart', function() {
//...
});
$rootScope.$on('IdleTimeout', function() {
logout();
});
}
On which object instead of $rootScope I have to call the $on function if I want to get rid of the $rootScope?
UPD
The question was not about "how to migrate on Angular2 event system". It was about how to remove a $rootScope dependencies but keep a event system. Well it seems to be impossible.
I don't know what to do with event subscription mechanisms.
Angular 2+ frameworks replace the $scope/$rootScope event bus with observables.
From the Docs:
Transmitting data between components
Angular provides an EventEmitter class that is used when publishing values from a component. EventEmitter extends RxJS Subject, adding an emit() method so it can send arbitrary values. When you call emit(), it passes the emitted value to the next() method of any subscribed observer.
A good example of usage can be found in the EventEmitter documentation.
For more information, see
Angular Developer Guide - Observables in Angular
You can implement TimeOutService which will do the log out after x minutes (in this case 15 min) of inactivity or it will reset the timer after certain action(s).
import { Injectable, OnDestroy } from '#angular/core';
import { Router } from '#angular/router';
import { Observable, Subject, Subscription, timer } from 'rxjs';
import { startWith, switchMap } from 'rxjs/operators';
import { AuthService } from 'path/to/auth.service';
#Injectable()
export class TimeoutService implements OnDestroy {
limitMinutes = 15;
secondsLimit: number = this.limitMinutes * 60;
private reset$ = new Subject();
timer$: Observable<any>;
subscription: Subscription;
constructor(private router: Router,
private authService: AuthService,
) {
}
startTimer() {
this.timer$ = this.reset$.pipe(
startWith(0),
switchMap(() => timer(0, 1000))
);
this.subscription = this.timer$.subscribe((res) => {
if (res === this.secondsLimit) {
this.logout();
}
});
}
resetTimer() {
this.reset$.next(void 0);
}
endTimer() {
if (typeof this.subscription !== 'undefined') {
this.subscription.unsubscribe();
}
}
logout(): boolean {
this.authService.signOut().subscribe((res) => {
this.subscription.unsubscribe();
});
return false;
}
ngOnDestroy():void {
this.subscription.unsubscribe();
}
}
And in the AppComponent have listener which will reset timeout on certain actions
In case as bellow it listens for keyboard strokes, mouse wheel, or mouse click
constructor(
private timeoutService: TimeoutService
) {
}
#HostListener('document:keyup', ['$event'])
#HostListener('document:click', ['$event'])
#HostListener('document:wheel', ['$event'])
resetTimer () {
this.timeoutService.resetTimer();
}
I'm trying to create window event listener that must listen for the event in the other tab, where opened another instance of the same application.
Some service:
public validateItemAgainstServer = (item: EspApplication) => {
...
window.localStorage.setItem('item', "|")
...
});
}
Component
constructor(private winRef: WindowRef) {
winRef.nativeWindow.addEventListener('storage', function (e) {
console.log("storage event occured");
}, false);
window.addEventListener('storage', function (e) {
console.log("storage event occured");
}, false);
}
WinRef
import { Injectable } from '#angular/core';
function _window(): any {
// return the global native browser window object
return window;
}
#Injectable()
export class WindowRef {
get nativeWindow(): any {
return _window();
}
}
Regretfully, onstorage event was not fired. Is it possible to fix this solution or may be there is some better ideas of how to synchronize two tabs in Angular?
Check the live example here!
#HostListener('window:storage')
onStorageChange() {
console.log('change...');
}
I have a DataServive, that fetches content from an API:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { map, catchError, retry } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
#Injectable()
export class DataService {
this.request = {
count: 10
}
constructor(private http: HttpClient) { }
private handleError(error) {
console.log(error);
}
public getData(count): Observable<any> {
this.request.count = count;
return this.http.post<any>(environment.api + '/path', this.request).pipe(
map(response => {
return response;
}),
catchError(error => {
this.handleError(error);
return [];
})
);
}
}
This DataServie is consumned by a component like this:
ngOnInit() {
const subscriber = this.dataService.getData(this.count).subscribe((data) => { this.data = data; });
}
And it works fine.
However the user is able to change the variable this.count (how many items should be displayed) in the component. So I want to get new data from the server as soon as this value changes.
How can I achieve this?
Of course I could call destroy on this.subscriber and call ngOnInit() again, but that dosn't seem like the right way.
Easiest ways is just to unsubscribe:
subscriber: Subscription;
ngOnInit() {
this.makeSubscription(this.count);
}
makeSubscription(count) {
this.subscriber = this.dataService.getData(this.count).subscribe((data) => { this.data = data; });
}
functionInvokedWhenCountChanges(newCount) {
this.subscriber.unsubscribe();
makeSubscription(newCount);
}
But because count argument is just a one number it means HTTP always asks for data from 0 to x. In this case, you can better create another subject where you can store previous results (so you don't need to make useless HTTP requests) and use that subject as your data source. That needs some planning on your streams, but is definitely the preferred way.
When the user changes count, call getData(count) again with the updated count value. Need to see your html file, but having a button with (click)="getData(count)" may help.
When angular receive the data from the API via HTTP call then how to check some property has an image or not.
Here is how to solve this real world example in a very easy way.
organaization.component.ts
import { Component, OnInit } from '#angular/core';
export class OrganizationComponent implements OnInit {
organizationObj:any = {
logo: 'http://someurl.com/assets/images/'
image: 'http://someurl.com/assets/images/someimg.jpg'
};
imgNoExt:boolean = false;
// here is the simple image extension check function
private urlImgHasExt(url){
return(url.match(/\.(jpeg|jpg|gif|png)$/) != null);
}
ngOnInit() {
this.imgNoExt = this.urlImgHasExt(this.organizationObj.logo);
console.log(this.imgNoExt) //this will return false value
this.imgNoExt = this.urlImgHasExt(this.organizationObj.image);
console.log(this.imgNoExt) //this will now return true value
}
}