Priority hints indicate the relative priority of resources to the
browser. They can enable optimal loading and improve Core Web Vitals.
From https://web.dev/priority-hints/
example with fetch API:
<script>
fetch('https://example.com/', {priority: 'low'})
.then(data => {
// Trigger a low priority fetch
});
</script>
how set "priority" to Angular HttpClient?
I have tried to force a priority setting:
import { HttpClient } from '#angular/common/http';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<button (click)="makeRequest()">make request</button><br />
<pre>{{ data | json }}</pre>`,
})
export class AppComponent implements OnInit {
data: any;
constructor(private httpClient: HttpClient) {}
ngOnInit(): void {
this.makeRequest();
}
makeRequest() {
this.data = null;
this.httpClient
.get('https://jsonplaceholder.typicode.com/todos/1', {
priority: 'low',
} as any)
.subscribe((result) => (this.data = result));
}
}
online
but doesn't works... priority is always hight
also suggested to angular team https://github.com/angular/angular/issues/45426
You can use like below:
this.http.get<YourConfig>(this.yourConfigUrl, {priority: 'low'});
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
I am can't get my Angular template to update after i sent out a postrequest,
Here's the component:
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'example',
templateUrl: './example',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent implements AfterViewInit, OnInit {
public mailResult: String;
constructor(private apiService: ApiService) {
this.mailResult = 'notsent'; //updating in template
}
onSubmit() {
this.mailResult = 'pending'; // updating in template
this.apiService.testPostRequest().subscribe((res)=>{
console.log("res", res); // working fine loging res
this.mailResult = 'requestsucess'; // not update in template
});
}
}
and that's the template:
<div class="example-component">
<h1>stateTest {{this.mailResult}}</h1>
</div>
and the apiService
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { of } from 'rxjs';
#Injectable()
export class ApiService {
constructor(private http: HttpClient) {}
testPostRequest () {
return this.http.post('http://localhost:1337/email', {});
}
}
All I need is to update this.mailResult in my Template after the request was successful, all is working fine, but the value in the template just won't update after the request. Any Ideas where the Issue might be hidden?
It's not working because you have your component's change detection set to 'onPush' and mailResult is not decorated with #Input (which it obviously shouldn't).
So, to fix this, you first need to add a changeDetector to your class:
constructor(private apiService: ApiService, private changeDetector: ChangeDetectorRef) {
this.mailResult = 'notsent'; //updating in template
}
And then you use that changeDetector's markForCheck function to let angular know that something has changed and it needs to update the view:
this.apiService.testPostRequest().subscribe((res)=>{
console.log("res", res); // working fine loging res
this.mailResult = 'requestsucess'; // not update in template
this.changeDetector.markForCheck();
});
I don't get i, how to communicate between components and services.. :(
I have read and tried a lot about even if some examples somehow work, I do not understand why (?)
what I want to achieve:
I have one parent and two child-components:
dashboard
toolbar
graph
in the toolbar-component I have a searchfield, which gets it's result from a external source (works via service).. when the result arrives, I need to trigger the updateGraph()-Method in the graph-component
toolbar.component.ts
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import { FormControl } from '#angular/forms';
import { WebsocketsService } from '../../../services/websockets/websockets.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'toolbar',
templateUrl: './toolbar.component.html',
styleUrls: ['./toolbar.component.scss'],
providers: [WebsocketsService, DataService]
})
export class ToolbarComponent implements OnInit {
#Output() newGraphData: EventEmitter<boolean> = new EventEmitter();
searchField: FormControl;
search: string;
private isNewGraph = false;
constructor(private _websocketsService: WebsocketsService, private _dataService: DataService) {
}
ngOnInit() {
this.searchField = new FormControl();
this.searchField.valueChanges
.subscribe(term => {
this.search = term;
});
}
private applySearch() {
const res = this._websocketsService.sendQuery(this.search);
this._dataService.setGraphData(res);
this.newGraphData.emit(true);
this.search = '';
this.searchField.reset();
}
}
graph-component.ts
import { Component, OnInit} from '#angular/core';
import { HttpService } from '../../../services/http/http.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'graph',
templateUrl: './graph.component.html',
styleUrls: ['./graph.component.scss'],
providers: [HttpService, DataService]
})
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
ngOnInit() {
}
public renderResult() {
console.log( this._dataService.getGraphData() );
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class DataService {
private graphData: Subject<string> = new Subject<string>();
public setGraphData(data) {
this.graphData.next( data );
}
public getGraphData() {
return this.graphData;
}
constructor() { }
}
I simply want ´renderResult()´to be executed after the searchresult has been written to ´graphData´. please help i am confused.
If I understand, you want communication between components and service.
A[component] (make a information) -----(notification)-----> B[service] ----(send)----> C[component] (consume the information)
It's correct? Let's go.
You need create a subscription of graphData(data.service.ts) in GraphComponent.
import { Subscription } from 'rxjs/Subscription';
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
private subscription: Subscription;
ngOnInit() {
this.subscription = this._dataService.getGraphData().asObservable().subscribe((data) => {
console.log(data);
});
}
}
Look here to help you.
http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-between-components-with-observable-subject
Short answer, I think you need to subscribe to the getGraphData subject, something like this (NOT RECOMMENDED):
public renderResult() {
this._dataService.getGraphData().subscribe(d => {
console.log(d)
});
}
It is not recommended as per the lead of RxJS says: https://medium.com/#benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93
Better answer, create an observable in your service and subscribe to that instead.
data.service.ts
graphObservable = this.graphData.asObservable();
graph-component.ts
public renderResult() {
this._dataService.graphObservable().subscribe(d => {
console.log(d)
});
}
My http-data.service accepts json for output in the component template. Initially, the console shows that the first few calls are given undefined, and the following calls are already taking json, but also if you check the component, then the component shows that the method that outputs the data to the component is called only once and since the data has not yet arrived it writes undefined , But not updated after the arrival of json. Help please understand why? Thank you
My http-data.service:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import {Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class HttpService{
constructor(private http: Http) {}
getDataOrganizations(): Observable<any[]>{
return this.http.get('http://localhost:3010/data')
.map((resp:Response)=>{
let dataOrganizations = resp.json().organization;
return dataOrganizations;
});
}
getDataModules(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModules = resp.json().modules;
return dataModules;
});
}
getDataPresets(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataPresets = resp.json().presets;
return dataPresets;
});
}
getDataModuleItems(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModuleItems = resp.json().module_items;
return dataModuleItems;
});
}
}
My data-all.service
import { Injectable, EventEmitter } from '#angular/core';
import {Response} from '#angular/http';
import { ModuleModel } from './model-module';
import { ModuleItemsModel } from './model-module-items';
import data from '../data/data-all';
import { PriceService } from './price.service';
import { HttpService } from './http-data.service';
#Injectable()
export class ModuleDataService {
constructor(private priceService: PriceService, private httpService: HttpService){
this.dataMinMaxSum = {minSum: 0, maxSum: 0}
}
private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
private dataModules: ModuleModel[] = this.getDataModules();
private dataMinMaxSum: {};
private dataCalculateVariationOrg: any[];
private dataChangeExecutor: any[];
subscribe(generatorOrNext?: any, error?: any, complete?: any) {
this.currentPopupView.subscribe(generatorOrNext, error, complete);
}
calculte(){
return this.priceService.getDataPrice();
}
getDataModules(){
this.httpService.getDataModules().subscribe(((modules)=>{this.dataModules = modules; console.log(this.dataModules);}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
---------------------------------------------------------------------------
}
My left-block.component
import { Component, OnInit} from '#angular/core';
import { ModuleDataService } from '../../service/data-all.service';
import { ModuleModel } from '../../service/model-module';
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit{
modules: ModuleModel[];
constructor(private modulesAll: ModuleDataService){}
ngOnInit(){
this.modules = this.modulesAll.getDataModules();
console.log("view");
console.log(this.modulesAll.getDataModules());
}
onToggle(module: any){
this.modulesAll.toggleModules(module);
}
}
My left-block.component.html
<div class="modules-all">
<div class="modules-all-title">Все модули</div>
<div class="module-item" *ngFor="let module of modules" [ngClass]="{ 'active': module.completed }" (click)="onToggle(module)">{{module?.title}}</div>
</div>
In the component this.modulesAll.getDataModules () method is why it is executed only once without updating (write in console => undefined), if there are any thoughts, write, thanks.
This behaviour is due to the .subscribe() method does not wait for the data to arrive and I'm guessing you already know this. The problem you're facing is because, you have .subscribe to the getDataModules() service in the wron place. You shouldn't subscribe to a service in another service (at leat in this case). Move the subscribe method to the left-block.component and it should work.
getDataModules() {
this.httpService.getDataModules().subscribe(((modules) => {
this.dataModules = modules;
console.log(this.dataModules);
}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
It should look somethig like this:
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit {
modules: ModuleModel[] = new ModuleModel();
constructor(private modulesAll: ModuleDataService, private httpService: HttpService) {}
ngOnInit() {
this.getDataModles();
//this.modules = this.modulesAll.getDataModules();
console.log("view");
//console.log(this.modulesAll.getDataModules());
}
onToggle(module: any) {
this.modulesAll.toggleModules(module);
}
getDataModules(): void {
this.httpService.getDataModules().subscribe(((modules) => {
this.modules = modules;
console.log(this.dataModules);
}));
}
}
I have this function in my Angular 2 component, which calls Web Api:
getNextConjunctionApi(): Observable<any> {
return this._http.get(this.uri + '/GetNextConjunction')
.map((res: Response) => res.json());
}
Web Api returns a complex object, which I would like to map to an Angular 2 model called ClientModel:
export class ClientModel {
prop1: string;
prop2: string;
...
}
Can this mapping be done by rewriting the map functionality, or need I do it in some other way?
.map((res: Response) => res.json());
I accomplished this with a slightly different approach. I had my component call a service that would return an observable. My component could then use a specific type that I created. I will show you what I have done for a blog.
posts.component.ts
import { Component, OnInit } from '#angular/core';
import { PostsService } from './posts.service';
import { PostComponent } from '../post/post.component'; // --> This is my custom type
import { Observable } from 'rxjs/Rx';
#Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
providers: [PostsService]
})
export class PostsComponent implements OnInit {
posts: Observable<PostComponent[]>; // --> I use the type here
constructor( private _postsService: PostsService ) { }
ngOnInit() {
this._postsService.getAllPosts()
.subscribe(
posts => { this.posts = posts }, // --> I add the return values here
error => { console.log(error) }
);
}
}
The above has three key pieces. I import the custom type, PostComponent, set posts to an Observable of type PostComponent array, and as the Observable comes back, I add the values to the posts array.
posts.service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
export class PostsService {
constructor( private _http: Http ) {}
getAllPosts(){
return this._http.get('[INSERT API CALL]')
.map((response: Response) => response.json())
.catch(msg => Observable.throw(msg));
}
}
In my service, I only map the response to response.json. This gives me more information than I need. I 'filter' it in my post.component
post.component.ts
import { Component, Input } from '#angular/core';
#Component({
selector: 'post',
templateUrl: './post.component.html'
})
export class PostComponent{
#Input() curPost: {
'id': number,
'title': string,
'author': string,
'date': string,
'body' : string,
};
constructor() { }
}