I am passing data between components onload. When the component receives the information within the subscribe function it is able to use the data and do whatever with it, so a console.log works fine, so it is clearly receiving it, but immediately outside of the subscribe function the information is unaccessible and is undefined. So I can't run a console.log or do anything with the information. In the html, it says that it is undefined as well.
The component.
import { Observable } from 'rxjs/Rx';
import { User } from '../User';
import { AccountInfo } from './../AccountInfo';
import { LoginService } from './../login.service';
import { Component, OnInit, AfterViewInit, OnDestroy, ElementRef, ViewChild } from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit, AfterViewInit {
public user: User;
public subscription: Subscription;
constructor(route: ActivatedRoute, private loginService: LoginService) {}
ngOnInit() {
this.loginService.getMessage().subscribe(data =>
{
this.user = data;
console.log(this.user.vendorname);
});
console.log(this.user.vendorname);
}
ngAfterViewInit() {
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
//Add 'implements AfterViewInit' to the class.
}
}
relevant section of html
<h1>Welcome {{user.vendorname}}</h1>
Yes.. that's how async functions work. The thing you pass into the subscribe function is another function.
data => {
this.user = data;
console.log(this.user.vendorname);
}
This will be called once the getMessage() has received answer from your server. Any statements after the subscribe will be called immediately, and that's why this.user.vendorname is still undefined when you try to log it there.
If you are receiving an error in your html you should use the safe navigation operator (?.):
<h1>Welcome {{user?.vendorname}}</h1>
Related
I would like to call a function from external JS file to handle elements which are in a component (content coming from an HTTP request). The script is loading fine but way before the HTTP response so I cannot use my function. Here is my code:
import { Component, OnInit } from '#angular/core';
import { HttpService } from '../http.service'
import * as $ from 'jquery';
declare const myFunc: any;
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
items: object;
constructor(private _http: HttpService) { }
ngOnInit(): void {
this._http.myList().subscribe(
data =>{
this.items= data;
console.log(this.items);
},
myFunc(),
)
}
}
Any idea how I can load my script after all the data of the component is loaded?
thanks!
If I understood your problem correctly, you should leverage ngAfterViewInit. This method is called once your view is initialized, and by this time data returned from api is used in html.
export class HomeComponent implements OnInit, AfterViewInit {
items: object;
constructor(private _http: HttpService) { }
ngOnInit(): void {
this._http.myList().subscribe(
data => {
this.items = data;
console.log(this.items);
}
)
}
ngAfterViewInit() {
myFunc();
}
}
Your current func call doesn't make sense as it will work as the error callback function of subscribe as pointed by #Robin.
ngAfterViewInit
Its now 8 hours trying to solve a trivial issue & I can't believe it !
here below a script of angular service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class GetStockDataService {
constructor(public http:HttpClient) { }
RequestData={"query":"{\n stock{\n history{\n \n low\n high\n demand\n }\n }\n}"}
getstockdata(){
return this.http.post('http://localhost:3000/',this.RequestData)
}
}
and here is a component script which is calling that service
import { Component, OnInit } from '#angular/core';
import { GetStockDataService } from '../services/get-stock-data.service';
import { Platform } from '#ionic/angular';
#Component({
selector: 'app-Stocks',
templateUrl: 'Stocks.page.html',
styleUrls: ['Stocks.page.scss']
})
export class StocksPage implements OnInit {
constructor(private GetStockData:GetStockDataService , private platform : Platform) {}
res:any
ngOnInit(){
this.getdata().subscribe(data=>{this.res=data});
console.log(this.res)
}
getdata(){
return this.GetStockData.getstockdata() }}
WHY the "res" variable is always returning NULL ????
knowing that when I put the console log the variable inside there in the function in the subscription part .. it returns data
but I can't make this variable global ... how could I do that ? I just want to get the data from the subscription to the "res" variable to use it the HTML file later .
Due to Async call, console.log(this.res) executes before server call is processed.
Change
this.getdata().subscribe(data=>
{
this.res=data
});
console.log(this.res)
To
this.getdata().subscribe(data=>
{
this.res=data;
console.log(this.res)
});
I have repetitive problem in angular but I had search a lot about this problem and use all of Technics that answer in stackoverflow and... .
my problem is in my loader component when I subscribe over than one.
this is my loader component
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, DoCheck, OnChanges, AfterViewInit, OnInit } from '#angular/core';
import { Subject, BehaviorSubject } from 'rxjs';
import { LoaderService } from './loader.service';
#Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent implements OnInit {
isLoading: BehaviorSubject<boolean>=this.loaderService.isLoading;
constructor(private loaderService: LoaderService, private changeDetector: ChangeDetectorRef) {
}
color = 'accent';
mode = 'indeterminate';
value = 50;
ngOnInit(): void {
}
}
and this is my service loader component
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class LoaderService {
constructor() { }
isLoading: BehaviorSubject<boolean> = new BehaviorSubject(false);
count=0;
show(): void {
debugger
console.log(`show`+this.count++)
this.isLoading.next(true);
}
hide(): void {
debugger
console.log(`hide`+this.count++)
this.isLoading.next(false);
}
}
and this is my interceptor loader
import { Injectable } from '#angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '#angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoaderService } from './loader/loader.service';
#Injectable()
export class LoaderInterceptor implements HttpInterceptor {
constructor(public loaderService: LoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loaderService.show();
return next.handle(req).pipe(
finalize(() => {this.loaderService.hide(); })
);
}
}
my error message is
"
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: true'.
at viewDebugError (core.js:17871)
at expressionChangedAfterItHasBeenCheckedError (core.js:17859)
at checkBindingNoChanges (core.js:18059)
at checkNoChangesNodeInline (core.js:27635)
at checkNoChangesNode (core.js:27624)
at debugCheckNoChangesNode (core.js:28228)
at debugCheckDirectivesFn (core.js:28156)
at Object.updateDirectives (loader.component.html:2)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:28145)
at checkNoChangesView ("
please help me to solve it.it's my big problem :-(
I was changing "behavior subject" to observable. subscribe data in loading page and used angular change detector in life cycle.Now, the problem is solve and work correctly
I'm not exactly sure where the 'ngIf' statement is being used, but an alternative might be instead to use css to hide the loader when not in use. E.g.
<div #myLoader [style.display]="isLoading ? 'block' : 'none'>...
To avoid it put a default value for your isLoading property (false for example), and wait the ngOnInit or ngAfterViewInit to change the property in the component.
Tried to replicate your code in a standalone stackblitz instance https://stackblitz.com/edit/angular-multisub with multiple subscriptions for loaderService.
Works without any problem.
Could you fork the above instance and modify to reproduce the same.
In my angular application, I have one parent component i.e. Dashboard Component having 2 Sub Components i.e. Analytics Component & Stats Component. My dashboard.component.html looks like this
<div class="row">
<div class="col-lg-6"><app-analytics></app-analytics></div>
<div class="col-lg-6"><app-stats></app-stats></div>
</div>
I am also using a Global Component which is available to all the components works like a global storage. Now in the dashboard.component.ts. I am making a HTTP call to the server, getting the data and saving it into the Global component.
dashboard.component.ts
import { Component, OnInit } from '#angular/core';
import { Global } from 'app/shared/global';
import { Http } from '#angular/http';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor(private http : Http){
};
ngOnInit(){
this.http.get('/api/getUserPreferences').subscribe(response=>{
var data = response.json();
Global.userPreferences = data.preferences;
})
}
User preferences I am using in the sub components i.e. Analytics Component and Stats Component.
analytics.component.ts
import { Component, OnInit } from '#angular/core';
import { Global } from 'app/shared/global';
import { Http } from '#angular/http';
#Component({
selector: 'app-analytics',
templateUrl: './analytics.component.html',
styleUrls: ['./analytics.component.css']
})
export class AnalyticsComponent implements OnInit {
public analyticsUserPreferences : any;
constructor(private http : Http){
};
ngOnInit(){
this.analyticsUserPreferences = Global.userPreferences.analytics;
// Printing just for the question purpose
console.log(this.analyticsUserPreferences);
}
}
stats.component.ts
import { Component, OnInit } from '#angular/core';
import { Global } from 'app/shared/global';
import { Http } from '#angular/http';
#Component({
selector: 'app-stats',
templateUrl: './stats.component.html',
styleUrls: ['./stats.component.css']
})
export class StatsComponent implements OnInit {
public statsUserPreferences : any;
constructor(private http : Http){
};
ngOnInit(){
this.statsUserPreferences = Global.userPreferences.stats;
// Printing just for the question purpose
console.log(this.statsUserPreferences);
}
}
Now, in these sub components. I am getting undefined every time in the console. Is there any way that it should wait till the Global.userPreferences doesn't contain the values. Or is there other way to do the same. I just want that it should wait till the http request is completed and print whenever the values are store inside the Global.userPreferences.
You can use the async pipe and an *ngIf to wait for the http request to be completed before rendering the child components. Then use binding to pass the data down to the child component and receive it with an #Input().
dashboard.component.ts
public userPreferences$: Observable<any>;
ngOnInit(){
this.userPreferences$ = this.http.get('/api/getUserPreferences').subscribe();
})
dashboard.html
<app-analytics *ngIf="userPreferences$ | async as userPreferences" [userPreferences]="userPreferences"></app-analytics>
I'm having problems setting a member variable on an ng2 component. In the component below, I'm trying to set some service results to a member variable. updateSearchResults1() sets the member variable as expected but updateSearchResults2 delegates the promise to processSearchResults which returns the error: "TypeError: Cannot set property 'blogPostListItems' of null." My understanding was that these 2 implementations were functionally the same. So why can I set this.blogPostListItems from updateSearchResults1() whereas I get an error that this.blogPostListItems is null from updateSearchResults2()?
import { Component, OnInit, ViewChild, ElementRef } from '#angular/core';
import { Router } from '#angular/router';
import { BlogService } from '../../services/blog.service';
import { BlogLanding } from '../../entities/blog-landing';
import { Response } from '#angular/http';
#Component({
selector: 'blog-landing',
templateUrl: '../../../ng2/templates/blog-landing.component.html'
})
export class BlogLandingComponent implements OnInit
{
#ViewChild('ddlAuthor') ddlAuthor;
blogLanding: BlogLanding;
blogPostListItems: Array<Object>;
constructor(
private router: Router,
private blogService: BlogService){}
ngOnInit(): void
{
}
updateSearchResults1()
{
this.blogService
.getBlogPosts()
.then(blogPostListItems => this.blogPostListItems = blogPostListItems)
}
updateSearchResults2()
{
this.blogService
.getBlogPosts()
.then(this.processSearchResults);
}
processSearchResults(responseObject)
{
this.blogPostListItems = responseObject;
}
}