wait till the request completes in angular - javascript

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>

Related

unable to pass data between one component to another component in angular

I am trying to pass data from one component to another component I used the service file method.
I created two components one is login and the second is home. I have to pass data from login to home.
in the login component, I take user input, and the home component should print that.
I used this code below, but when I give input, it is not printing in output.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class SharedService {
message : any;
constructor() { }
setMessage(data: any){
this.message=data;
}
getMessage(){
return this.message;
}
}
this is my home component code
import { Component, OnInit } from '#angular/core';
import { SharedService } from '../shared/shared.service'
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
message : string | undefined;
constructor(private shared:SharedService ) {}
ngOnInit() {
this.message =this.shared.getMessage()
}
}
<h1> {{ message }} </h1>
this is my login component code
import { Component, OnInit } from '#angular/core'
import { SharedService } from "../shared/shared.service"
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
message : any ;
constructor(
private shared: SharedService
) { }
ngOnInit(): void {
this.shared.setMessage(this.message)
}
}
<input required type="text" class="form-control" placeholder="Enter username" [(ngModel)]="message">
ofcourse it will not work this way .the reason it is not working . when you call SharedService in your constructor in box component it create an instance of your service with message : any . if you change it on one component it will not change on the other component .
what you can do is .
on your service . message = new Subject() ; setMessage(data: any){ this.message.next(data) ; }
you call set message on your login component . and on your home component you subscribe to the subject like this . this.sharedService.getMessage().subscribe( (result :any ) => {console.log(result )} .
sorry if this answer is messy , this is my first time using SOF .

How do I pass data from one component to another (New Browser Tab) in angular?

I'm new to angular and I don't know how to pass data between two components using routers. This is my first component view,
when I press view report button I need to call another component with the first component data. This is my first component view report click button code.
<button type="button" (click)="onFuelViewReport()" class="btn btn-success ">
<b>view Report</b>
</button>
when clicking the button it calls onFuelViewReport() function in the first component and using this function it opens the second component view with a new browser window (tab). What I want is to pass data from the first component to the second component from here. Please help me to do this.
onFuelViewReport() {
this.router.navigate([]).then(result => {
window.open("/pages/view-report", "_blank");
});
}
If you want to share data from child component to parent component, you can use #Output event emitter or if your are trying to share data within unrelated components, you can use BehaviourSubject (This also works in case of parent to child component communication and vice versa).
Child to Parent: Sharing Data via Output() and EventEmitter
parent.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-parent',
template: `
Message: {{message}}
<app-child (messageEvent)="receiveMessage($event)"></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
message:string;
receiveMessage($event) {
this.message = $event
}
}
child.component.ts
import { Component, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-child',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message: string = "Hola Mundo!"
#Output() messageEvent = new EventEmitter<string>();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
Unrelated Components: Sharing Data with a Service
data.service.ts
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class DataService {
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
parent.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from "../data.service";
#Component({
selector: 'app-parent',
template: `
{{message}}
`,
styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
sibling.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from "../data.service";
#Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Sibling")
}
}
The window.open looks absolutely awful. Use this.router.navigate(['/heroes']);.
So if I understand correctly you have a list of items and when you click on one of the items, the details page of that item should open?
Best practice is to allow the detail route to have a property to set. the Angular Routing & Navigation page is very complete. It shows that you should use :id - { path: 'hero/:id', component: HeroDetailComponent }. When you open the detail page, you get the id variable and then get the data for it.

data not accessible outside of subscription function

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>

Run function on component display

I want to run a function inside component every time user switch to this component. I tried to use ngOninit (run function inside only once) and other methods like ngOnComponentInit etc. but none of these worked for me.
Maybe I want to do this in a wrong way...
Please advice.
edit:
some example code.
home.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../auth/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private auth: AuthService, private router: Router) {}
ngOnInit() {
if(this.auth.token == null){
this.router.navigate((['/']));
}
}
someFunction(){
console.log("ok");
}
}
I want to run someFunction() everytime user switch to this component.
Do you mean onFocus()? This is what gets called when a user clicks on or tabs into a component.

Angular2 view not updating after model is set from another component

I have a simple web app that has an app model and a couple of components. When I update an array that I have in my model the view where that model is being consumed does not update. When I console log the model array I can see the model being updated just not the view. Any help would be greatly appreciated. Below please have a look at what I currently have.
overview.component.ts
import { Component, OnInit } from '#angular/core';
import { AppModel } from '../models/app-model';
#Component({
selector: 'app-overview',
templateUrl: './overview.component.html',
providers: [AppModel]
})
export class OverviewComponent implements OnInit {
constructor(public AppModel:AppModel) { }
ngOnInit() {}
}
app-model.ts
export class AppModel {
myArray:Array<any> = [];
constructor(){}
}
overview.component.html (This is the view that is not being updated when the model gets updated)
<td *ngFor="let dataItem of AppModel.myArray">
<span{{ dataItem }}</span>
</td>
This is how I am updating the array in the app model from another component
import { Component, OnInit } from '#angular/core';
import { Http, Response } from '#angular/http';
import { AppService } from '../services/app.service';
import { AppModel } from '../models/app-model';
#Component({
selector: 'other-component',
templateUrl: './other-component.component.html',
providers: [AppService, AppModel]
})
export class OtherComponent implements OnInit {
constructor(private http: Http, public AppService:AppService,public AppModel:AppModel) {}
private updateModel() :void {
this.AppModel.myArray = someArray;
}
ngOnInit() {}
}
For a service you get an instance per provider.
If you add a provider to a component, you get as many service instances as you have component instances. Only the component itself and it's children can inject a provider from a component.
You either need to provide the service on a common parent component or in #NgModule().
With providers only in #NgModule() you get a single instance for your whole application

Categories

Resources