window.postMessage is firing multiple times in angular Onint function - javascript

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()
}

Related

How to return multiple statement in angular?

I am creating Login page and want to call /login and /send-otp api together by a single function.
I have already created a login and registration page.
My code :
user-data.service.ts :
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class UserdataService {
url= 'http://localhost:9197/register';
url2= 'http://localhost:9197/login';
url3= 'http://localhost:9197/send-otp';
constructor(private http:HttpClient) {}
saveRegistration(data:any){
return this.http.post(this.url, data);
}
loginDone(ldata:any){
return this.http.post(this.url2, ldata);
return this.http.post(this.url3, ldata);
}
}
How to call multiply api ??
loginDone(ldata:any){
return this.http.post(this.url2, ldata);
return this.http.post(this.url3, ldata);
}
Apply TypeScript alias definition to your code:
Here in a more simplificated way, you have a multiple return with an alias structure.
type multi={
x:PelotaAzul,
y:PelotaRugosa,
}
function multiple():multi{
let x:PelotaAzul=new PelotaAzul("jj",5);
let y:PelotaRugosa=new PelotaRugosa("s",3,6)
let ab : multi ={x,y};
return ab;
}
You can also return an array of the both parameters like this
loginDone(ldata:any){
return [this.http.post(this.url2, ldata),this.http.post(this.url3, ldata)];
}
I find creating aliases more elegant but for faster results do the second one.
You are probably miss thinking your problem.
First of all. A return statement will always stop the function execution, doesn't matters if theres 100 lines after it.
Second, your logic probably will be: call login first then after (using or not the response) call the send-otp.
Or, your logic might be: call login and send-otp concurrently, but the loginDone method should only return some valid state if both requests run fine.
That's why other answers are completely wrong.
You must cascade your observables using pipe and switchmap for example:
return of([this.url2, this.url3]).pipe(
switchMap((url) => this.http.post(url, ldata))
)
If you want to return multiple values, you can return like this.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class UserdataService {
url= 'http://localhost:9197/register';
url2= 'http://localhost:9197/login';
url3= 'http://localhost:9197/send-otp';
constructor(private http:HttpClient) {}
saveRegistration(data:any){
return this.http.post(this.url, data);
}
loginDone(ldata:any){
return {url1: this.url, url2: this.url2, url3: this.url3};
}
}
If you want to call multiple api, check this one .
https://medium.com/bb-tutorials-and-thoughts/how-to-make-parallel-api-calls-in-angular-applications-4b99227e7458

TypeError: this.canvasContainer is undefined in unit test Angular

I want to test my service in angular with karma and jasmine, I begin with unit tests and I don't found any solution for my case or because I don't know how I can fix the issue. I always have a problem with my fields which are often undefined I don't understand why. If you can explain me what is the real problem It will be very nice to be able to progress in my tests.
My service
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CanvasElementService {
public canvasContainer: HTMLDivElement;
private scaleProperty: string = 'scale(1)';
public updateScale(scale: number) {
this.scaleProperty = `scale(${scale})`;
this.update();
}
public update(): void {
this.canvasContainer.style.transform = this.scaleProperty;
}
}
And my test
import { Component } from '#angular/core';
import { TestBed } from '#angular/core/testing';
import { CanvasElementService } from './canvas-element.service';
fdescribe('CanvasElementService', () => {
let service: CanvasElementService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CanvasElementService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe("updateScale", () => {
it("updatescale 2", () => {
let scale = 3;
spyOn(service, 'update').and.callThrough();
service.updateScale(scale);
expect(service['scaleProperty']).toBe('scale(3)');
});
});
});
After run test I got :
thanks for help If you have any idea to fix it.
Im not quite sure how to access a htmlElement in services. I think its only meant to be used by components (which have access to elements via #ViewChild() decorator).
You can try to achieve it by injecting your document into the service constructor and search for your element. Something like this:
constructor(#Inject(DOCUMENT) private document: HTMLDocument) {}
But its really not recommend to use services to access your dom. Use components or directives for it.
https://medium.com/#smarth55/angular-bad-practices-patterns-service-that-touch-the-dom-57ea978dca92

Values are undefined on load time

I'm working on angular app.
In my service file, I created a function configure. And it as been called in AfterViewInit in an component.
But On load time, this.config is undefined, If I use it inside setTimeOut I could able to access the value of the this.config.
The below code works,
configure() {
setTimeout(() => {
if(this.config) {
this.apply();
}
}, 200);
}
Is there any better way to do it ? without using setTimeOut.
Please help
try with markForCheck method
constructor(private cdr: ChangeDetectorRef) {}
ngOnInit(){
{
this.cdr.markForCheck();
this.configure()
}
configure(){
if(this.config) {
// your code
}
}
add the below code to #Component decorator
changeDetection: ChangeDetectionStrategy.OnPush,
Can you please try with below code
configure() {
var self = this;
setTimeout(() => {
if(self.config) {
self.apply();
}
}, 200);
}

AngularJS $rootScope.$on alternative in context of migration to Angular2

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();
}

How to trigger a Javascript event on url change

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.

Categories