this.zone.run() - Ngzone error - node.js

I have a problem with sails + sails socket + angular4
import { Component, OnInit, NgZone } from '#angular/core';
import { routerTransition } from '../../router.animations';
import { Http } from '#angular/http';
import * as socketIOClient from 'socket.io-client';
import * as sailsIOClient from 'sails.io.js';
#Component({
selector: 'app-tables',
templateUrl: './tables.component.html',
styleUrls: ['./tables.component.scss'],
animations: [routerTransition()]
})
export class TablesComponent implements OnInit {
io:any;
smartTableData:any;
constructor(public http: Http, private zone: NgZone) {
this.io = sailsIOClient(socketIOClient);
this.io.sails.url = "http://localhost:1337";
this.io.socket.get('/posts', function(resData, jwr) {
console.log (resData);
return resData;
});
this.io.socket.on('updateposts', function(data) {
this.zone.run(() => {
this.smartTableData = data;
});
});
}
ngOnInit() {
}
}
When the socket broadcasts data, the line this.socket.on("updataposts") is run, but ngZone does not work.
zone.js:196 Uncaught TypeError: Cannot read property 'run' of undefined
I want to update data to view when receiving socket data. Please help me!
Thank you!

Related

How can i asynchronouslycall this service function in another component? Angular 11

I have an async function getIdentByInfo and in the console i get the right output if i log it in this function. As soon as i call it in another component it doesnt work and i only get 'undefined'. I know it has something to do with beeing ssynchrone and Promises but i cant figure out how to solve my issue. I need the Model class filled with attributes coming from the http request in another component to send them to another service
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
constructor(private http: HttpClient) { }
// promise vom typ IdentModel zurückgeben
getIdentByInfo(id: string, vwk: string) {
this.http.get(this.url).toPromise().then(data => {
for (let i in data){
this.ident.push(data[i])
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
return this.ident[i];
}
}
});
}
}
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { InfoWebservice } from '../../webservices/info.webservice'
import { ImageWebservice } from '../../webservices/image.webservice'
import { IdentModel } from "../../models/identmodel.model";
#Component({
selector: 'app-identteil',
templateUrl: './identteil.component.html',
styleUrls: ['./identteil.component.scss']
})
export class IdentteilComponent implements OnInit {
ident = [];
identNr:string;
vwk:string;
imgFrontLink:string;
imgBackLink:string;
constructor(private router: Router, private service: InfoWebservice, private image: ImageWebservice) { }
getIdentNr() : string {
var split = this.router.url.split("/");
this.identNr = split[2];
return this.identNr;
}
//return type is STRING
getVwk() {
// output von window.location.host = repapp-maw.dbl.de
// var splitHost = window.location.host.split(".");
var splitHost = 'repapp-maw';
var splitV = splitHost.split("-");
this.vwk = splitV[1];
return this.vwk;
}
callInfoService = async () => {
return await this.service.getIdentByInfo(this.getIdentNr(), this.getVwk());
}
ngOnInit() {
console.log(this.callInfoService());
}
}
When you use angular, its always preferred not to use await/Promise. Angular has an in-built RX-JS library which has tonnes of super-awesome functionalities that you can use.
For Example, in your case, you can do something like this:
// Your Service File can make use of 'Behavior Subject'
// Please read more about it here: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
initialIdentValues: IdentModel = [];
private identSource: BehaviorSubject<IdentModel[]> = new BehaviorSubject<IdentModel[]>(this.initialIdentValues);
public identValuesObs$: Observable<IdentModel[]> = this.identSource.asObservable();
// Create a method to set the values in component-1
setIdentValues(identValues: IdentModel[]) {
this.identSource.next(identValues);
}
// Create a method to return values in component-2 or any component
returnIdentValues() {
return this.identValuesObs$;
}
constructor(private http: HttpClient) { }
// Change your service call to this:
getIdentByInfo(id: string, vwk: string): Observable<any> {
return this.http.get(this.url);
}
}
Now in your component-1 where you want to set the values of this identvalues:
// Component-1
constructor(private infoWebService: InfoWebService){}
// Create a method where you get the values
someMethod() {
// Call the API method here and subscribe and then set the values
this.infoWebService.getIdentInfoById(id, vwk).subscribe((data: any) => {
// Your logic goes here ANDD
if (data) {
for (let i in data){
this.ident.push(data[i])
let localIdentsWithRequiredLogic = [];
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
localIdentsWithRequiredLogic.push(this.ident[i]);
}
// THIS IS IMPORTANT
this.infoWebService.setIdentValues(localIdentsWithRequiredLogic);
}
}
})
}
Then in component-2 or whatever component you want, you can retrieve it using the returnIdentValues method like this:
// In component-2
inSomeMethodWhereYouRequireIdentValues() {
this.infoWebService.returnIdentValues().subscribe(data => {
console.log(data) // this is data that you set in component one
})
}

How to send events from nodeJS/express to angular

I have a long running transaction, and I would like to inform the client of the progress. My front end is Angular 4 and backend is nodeJS/Express . The client initiates the transaction via HTTP Post .
Angular does provide a facility to listen to event progress . https://angular.io/guide/http#listening-to-progress-events
My question is, how can I send events from my express App to Angular app?
As of the moment I don't want to use sockets.io .
Listening to upload progress events is actually a client-side feature. What it does behind the scenes is that it tells you the progress based on how much data the client i.e. the browser, has sent to the server. It doesn't actually get a response from the server (as I assume what you are thinking) for how much data the server has received and then displaying the progress to the user. So, if you would think logically and technically, it can not help you in any way. Also, as far as my knowledge goes, sockets are the only way to get a real-time update of the things happening on the server side.
Based on Angular's documentation, progress events can be handled by client, and after doing some searching I cam across server side events - SSE, which is basically sending response headers with connection alive header, and then progress data .
I was able to do it, but I still have issues sending and handling custom user events per angular. Here is what that I have.
App component.ts
import { Component ,OnInit} from '#angular/core';
import { CommonService} from './common.service';
import { Observable,Subscription } from "rxjs/Rx";
import 'rxjs/add/operator/timeout';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css','../../node_modules/bootstrap/dist/css/bootstrap-
theme.min.css']
})
export class AppComponent implements OnInit {
private sseStream: Subscription;
messages:Array<string> = [];
progress:number=0;
totalProgress:number=7;
constructor(private commonService: CommonService ) { }
ngOnInit(){
this.commonService.getHttpObj().subscribe(event=>{
if(event){
if(event['loaded']){
console.log(event['loaded']);
this.progress=(event['loaded'] / this.totalProgress)*100;
}
}
});
}
title = 'Angular4';
}
common.service.ts
import { Injectable } from '#angular/core';
import {HttpRequest} from '#angular/common/http';
import { Observable } from "rxjs/Rx";
import { catchError, map, tap , last} from 'rxjs/operators';
import { HttpClient } from '#angular/common/http';
import { HttpEventType } from '#angular/common/http';
const req = new HttpRequest('GET', 'http://localhost:9080/event', {
reportProgress: true
});
#Injectable()
export class CommonService {
constructor(private http: HttpClient) { }
getHttpObj(){
return this.http.request(req).pipe(
map(event => this.getEventMessage(event)),
tap(message => this.showProgress(message)),
// last(), // return last (completed) message to caller
// catchError(this.handleError())
);
};
private getEventMessage(event: any) {
switch (event.type) {
// case HttpEventType.Sent:
// return `Uploading file `;
case HttpEventType.UploadProgress:
// Compute and show the % done:
const percentDone = Math.round(100 * event.loaded / event.total);
return `File is ${percentDone}% uploaded.`;
case HttpEventType.Response:
return `Complete`;
case HttpEventType.User:
return event;
case HttpEventType.UploadProgress:
return `${JSON.stringify(event)}`;
case HttpEventType.DownloadProgress:
return event;
default:
return event;
}
}
showProgress(a:any){
//console.log(a);
return a;
}
private handleError<T> () {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
// console.error('error'); // log to console instead
// TODO: better job of transforming error for user consumption
// console.log(`${error.message}`);
// Let the app keep running by returning an empty result.
return null;
};
}
}
app.component.html
`<div class="container">
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
<input type="text" [(ngModel)]="test">
<p>{{test}}</p>
</div>
<div class="progress">
<div class="progress-bar bg-success" [ngStyle]="{'width':progress + '%'}"></div>
</div>
</div> `
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms'
import { AppComponent } from './app.component';
import { ServerComponent } from './server/server.component';
import { ServersComponent } from './servers/servers.component';
import { HttpClientModule } from '#angular/common/http';
import {CommonService } from './common.service';
import { HttpModule } from '#angular/http';
#NgModule({
declarations: [
AppComponent,
ServerComponent,
ServersComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule
],
providers: [CommonService],
bootstrap: [AppComponent]
})
export class AppModule { }
server.js
var express=require('express');
var app=express();
app.listen(9080);
app.get('/event',(req,res)=>{
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write("\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
res.write(JSON.stringify({})) ;
res.end();
},
2000);
},
2000);
},
2000);
},
2000);
},
2000);
[enter image description here][1]});

How to wait for async HTTP requests to return values on Angular 4?

I have some "cards" that I want to get information for them on an Angular service, the problem is that I get this information with http requests on an API, and I want the return to happen after ALL requests are completed.
cards.component.ts
import {Component} from '#angular/core';
import {CardsService} from './cards.service';
import 'easy-pie-chart/dist/jquery.easypiechart.js';
#Component({
selector: 'cards',
templateUrl: './cards.html',
styleUrls: ['./cards.scss']
})
// TODO: move easypiechart to component
export class Cards {
public charts: any;
constructor(private _cardsService: CardsService) {
this.charts = this._cardsService.getData();
}
}
cards.service.ts
import {Injectable} from '#angular/core';
import {BaThemeConfigProvider, colorHelper} from '../../../theme';
import { Http, Headers, Response } from '#angular/http';
import {Observable} from "rxjs/Observable";
#Injectable()
export class CardsService {
_meterCountURL = 'http://localhost:8080/meter/count';
_cardMeter;
_cardConsumption;
constructor(private _baConfig:BaThemeConfigProvider, private http: Http) {
}
getData() {
let pieColor = this._baConfig.get().colors.custom.dashboardPieChart;
let headers = new Headers({'Content-type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + localStorage.getItem('id_token')});
Observable.forkJoin(
this.http.get(this._meterCountURL, {headers: headers}).map((response) => {response.json()['data'];}),
this.http.get(this._meterCountURL, {headers: headers}).map((response) => {response.json()['data'];})
).subscribe(
data => {
this._cardMeter = data[0];
this._cardConsumption = data[1];
},
error => console.log(error)
);
return [
color: pieColor,
description: 'Consumo do mês atual',
stats: 0 || this._cardConsumption,
icon: 'ion-flash',
}, {
color: pieColor,
description: 'Número de unidades ativas',
stats: 0 || this._cardMeter,
icon: 'ion-ios-speedometer',
}
];
}
}
When It runs, where it should have an Integer, it appears:
[object Object].
If I try to put the return statement INSIDE the subscribe function, 'cards.component.ts' gives me the following error:
Type 'void' is not assignable to type 'Object[]'.
How can I return the card information after the http requests finishes correctly?
You should be returning the observable in your getData() method, then subscribe in your component. This way the component knows when the observable completes (in the subscribe method).
// card.service.ts
getData() {
return Observable.forkJoin(...);
}
// cards.component.ts
this._cardsService.getData().subscribe(data => {
this.charts = ...;
});

getting query params from url Angular

I want to grab id from url http://localhost:4200/courses/5a0eb3d7f6b50c2589c34e57 so in my app.module.ts I have such route {path:'courses/:id', component:CourseComponent, canActivate:[AuthGuard]} and in my course.component.ts I have the following code :
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-course',
templateUrl: './course.component.html',
styleUrls: ['./course.component.css']
})
export class CourseComponent implements OnInit {
id: String;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.id = this.route.snapshot.queryParams["id"];
console.log(this.id)
}
}
Actually in my developer console I can see following
And if I try to console.log(params) I get following
You should use rxjs.
this.route.params.pluck('id').subscribe(v => console.log(v));
Preferable, since .params might be depracated soon:
this.route.paramMap.subscribe(paramMap => paramMap.get('id'));
Everything is in documentation... https://angular.io/guide/router#parammap-api
This is a route param and you should be using the params property
this.id = this.route.snapshot.params["id"];

I am not getting response from nodeJS server in angular 2 [duplicate]

This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
Closed 5 years ago.
I am newbie to MEAN stack development. So, please help me to figure out the problem.
app.js
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static(path.join(__dirname, './darwin-src/public')));
const port = 3000;
app.get('/images', (req, res) => {
console.log('In server');
var data;
var Scraper = require ('images-scraper')
, google = new Scraper.Google();
google.list({
keyword: 'banana',
num: 10,
detail: true,
nightmare: {
show: false
}
})
.then(function (data) {
console.log('first 10 results from google', data);
res.end("" + data);
})
.catch(function(err) {
console.log('err', err);
});
});
app.listen(port, () => {
console.log(`Starting the server at port ${port}`);
});
image-service.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { Image } from './model/image';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/of';
#Injectable()
export class ImageServiceService {
constructor(private http: Http) { }
private serverApi = 'http://localhost:3000';
public getImages(image: string): Observable<Image[]> {
console.log('Inside Service');
let URI = `${this.serverApi}/images`;
return this.http.get(URI)
.map(function(res) {
return res.json();
});
}
}
image-view.component.ts
import { Component, OnInit } from '#angular/core';
import { ImageServiceService } from '../image-service.service';
import { Image } from '../model/image';
#Component({
selector: 'app-image-view',
templateUrl: './image-view.component.html',
styleUrls: ['./image-view.component.css']
})
export class ImageViewComponent implements OnInit {
private data: Image[] = [];
constructor(private imageService: ImageServiceService) { }
ngOnInit() {
}
onSubmit(image: string) {
console.log(image);
this.imageService.getImages(image).subscribe(response => this.data = response);
console.log(this.data.length);
}
}
The length of array is zero and I can't figure out why. The response comes on nodejs console after a while but the frontend displays the result before the response comes. Please help!
Hit the server url separately in browser and see if you get the expected response. If this is okay, then the problem is with the client.
On seeing your client code, one issue seems obvious. You are not using the observable from ImageServiceService properly. All your manipulations should be within the subscribe method.
onSubmit(image: string) {
this.imageService.getImages(image).subscribe(response => {
this.data = response;
console.log(this.data.length);
// Do other manipulations that you wish to do
});
}
If you using the observable to display something in the view, then
consider . using async pipe
The code in the subscribe handler is not executed synchronously. So, your console.log statement is executed before you get a response from your server. I don't see your image-view.component.html markup. But, I believe you need to use the async pipe in your bound option.
private data$: Observable<Image[]>;
onSubmit(image: string) {
console.log(image);
this.data$ = this.imageService.getImages(image);
}
And you HTML:
<div *ngFor="let image of data$ | async">
{{image.value}}
</div>

Resources