I have a developed a small library (js code) that I want to integrate with angular. the problem is that this library at a certain moment should make request ( ajax ) to push some results to the back-end. How can I make that in angular ? should I develop directives to support binding ?
Sorry I have small knowlege in angular but whats the best way to send data collected by the front end to backend.
thanks
The best way to interact with backend is to use services. For example (the example is for the latest Angular version, previous versions doesn't support HttpClient, it's just Http. I also use toPromise, it's optional, you can deal with observable if you want):
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class YourService {
constructor(
private _http: HttpClient
) { }
public sendDataToServer(data: any): Promise<any> {
return this._http.post(http://fakehost/fakeurl, data)
.toPromise()
.catch(err => console.error(err));
}
And inside your component:
import { Component } from '#angular/core';
import { YourService } from '../../core/your-service.service';
#Component({
selector: 'your-component',
templateUrl: './your-component.component.html',
styles: [``]
})
export class SignUpComponent {
constructor(private _yourService: YourService) {
this.ApiCall();
}
public ApiCall(): void {
this._yourService.sendDataToServer("any data here")
.then(response => {
console.log("Response:", response);
})
.catch(err => console.error(err));
}
}
Related
How to avoid multiple loading in angular loading interceptor
In angular each http call loading spinner and tried implement only one loading for initial page loading. How to solve this
You are working on an existing Angular application.
The application makes HTTP calls to a REST API from lot of various components.
You want to show a custom spinner for every HTTP request. Since this is an existing application, there are lot of places where calls to REST API are made. And changing code one by one at every places is not a feasible option.
So, you would like to implement an abstract solution which would solve this problem.
The code could be written simpler, without creating new observable and storing requests in memory. The below code also uses RxJS 6 with pipeable operators:
import { Injectable } from '#angular/core';
import {
HttpRequest,
HttpHandler,
HttpInterceptor,
HttpResponse
} from '#angular/common/http';
import { finalize } from 'rxjs/operators';
import { LoadingService } from '#app/services/loading.service';
import { of } from 'rxjs';
#Injectable()
export class LoadingInterceptor implements HttpInterceptor {
private totalRequests = 0;
constructor(private loadingService: LoadingService) { }
intercept(request: HttpRequest<any>, next: HttpHandler) {
this.totalRequests++;
this.loadingService.setLoading(true);
return next.handle(request).pipe(
finalize(res => {
this.totalRequests--;
if (this.totalRequests === 0) {
this.loadingService.setLoading(false);
}
})
);
}
}
Add this interceptor service into your module providers:
#NgModule({
// ...
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true }
]
})
export class AppModule { }
Here's an example of the LoadingService implementation:
#Injectable()
export class LoadingService {
private isLoading$$ = new BehaviorSubject<boolean>(false);
isLoading$ = this.isLoading$$.asObservable();
setLoading(isLoading: boolean) {
this.isLoading$$.next(isLoading);
}
}
And here's how you'd use the LoadingService in a component:
#Component({
selector: 'app-root',
template: `
<ng-container *ngIf="loadingService.isLoading$ | async">
<i class="loading"></i>
</ng-container>
<router-outlet></router-outlet>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
constructor(public loadingService: LoadingService) {}
}
I was following a tutorial where a guy showed how to build a news app with ionic 4 using the news API. I also want to create a news app that shows summarized news from different sources on a particular topic but the problem is that I am thinking of using the Firebase cloud firestore for this purpose instead of using the news API and I can't figure out how to get the data from the firestore collection. You can look at the following code for reference.
news.page.ts
import { Component, OnInit } from '#angular/core';
import { NewsService } from '../news.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-news',
templateUrl: './news.page.html',
styleUrls: ['./news.page.scss']
})
export class NewsPage implements OnInit {
data: any;
page = 1;
constructor(private newsService: NewsService, private router: Router) {}
ngOnInit() {
this.newsService
.getData(`top-headlines?country=us&category=business&pageSize=5&page=${this.page}`)
.subscribe(data => {
console.log(data);
this.data = data;
});
}
onGoToNewsSinglePage(article) {
this.newsService.currentArticle = article;
this.router.navigate(['/news-single']);
}
}
news.service.ts
import { Injectable } from '#angular/core';
import { environment } from '../environments/environment';
import { HttpClient } from '#angular/common/http';
const API_URL = environment.apiUrl;
const API_KEY = environment.apiKey;
#Injectable({
providedIn: 'root'
})
export class NewsService {
currentArticle: any;
constructor(private http: HttpClient) { }
getData(url) {
return this.http.get(`${API_URL}/${url}&apiKey=${API_KEY}`);
}
}
news.page.html
<ion-header>
<ion-toolbar>
<ion-title>News</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card *ngFor="let article of data?.articles" (click)="onGoToNewsSinglePage(article)">
<!-- <ion-img [src]="article.urlToImage"></ion-img> -->
<ion-card-content>
<ion-card-title>{{article.title}}</ion-card-title>
<p>{{article.description}}</p>
</ion-card-content>
</ion-card>
</ion-content>
I have installed the angularfire 2 plugin in my project, imported all the files in app.module.ts and also prepared a config file for all the Firebase details. I just want to know how to get the data from Firebase collection and bind it to the html code.
Instead of calling your service this.newsService.getData(...) you will have to use firebase service public AngularFirestore from angularfire2/firestore . Here is an example:
Import the service and inject it in your component news.page.ts:
import {AngularFirestore} from 'angularfire2/firestore';
...
data: any;
constructor ( public db: AngularFirestore ) {
}
...
To retrieve a single post, create the function
getPostEntry ( postTitle: string ): Observable<any> {
return this.db.collection<any> ( "posts" , ref => ref.where ( 'title' , '==' , postTitle ) ).valueChanges ();
}
This will search all entries in your firestore collection called "posts" with attribute title being your postTitle.
Simillarly to retrieve all posts
getAllPosts (): Observable<any> {
return this.db.collection<any>( "post" ).valueChanges ();
}
Then invoke the functions and consume the observables. For instance you can do it in your ngOnInit:
ngOnInit() {
this.getAllPosts().subscribe((data)=>{
this.data = data;
console.log(data);
});
}
Now you have your data in your variable data, you just have to draw it in your html as you would normally do. Have in mind that it will probably be an array with all your posts (if there are any).
here is a gist with the code I edited from your class:
https://gist.github.com/HugoJBello/73fb3c5c0964f29934a2d8021efb128d
EDIT
renamed firebase collection and added subscription to observable
I'm following this tutorial: https://www.youtube.com/watch?v=KhzGSHNhnbI&t=527s
And at 51:41 he uses map. But my code doesn't work. Why I can't use it? I get
Property map does not exists on Observable <Response>
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable({
providedIn: 'root'
})
export class DataService {
constructor(public http:Http) {
console.log("Data service connected...");
}
getPosts() {
this.http.get('https://jsonplaceholder.typicode.com/posts').map(res => res.json());
}
}
Service code you provide is using angular 6 which has dependency of rxjs 6.
So from rxjs 6 onwards you have to use pipeable operators and import paths are modified. so please change the code as follows
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class DataService {
constructor(public http:HttpClient) {
console.log("Data service connected...");
}
getPosts() {
this.http
.get('https://jsonplaceholder.typicode.com/posts')
.pipe(
map(res => res.json())
);
}
}
And one more recommendation please start using HttpClient Module instead of Http Module. So even you dont need to use map to get json response
Please check this link for httpClient Module
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() { }
}
After reading almost everything I found about observables, I still don't understand pretty well how they work.
I am doing the http request here:
import { Component, OnInit, Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { NavController } from 'ionic-angular';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
webs: any;
getWebs(): any{
return this.http.get( 'here the url' )
.map((res: Response) => res.json());
}
constructor(public navCtrl: NavController, private http: Http) {}
ngOnInit(){
this.getWebs().subscribe(response => {
this.webs = response;
console.log(this.webs);
});
}
}
On the console, this.webs is correctly printed. That means, the get request ist working fine and I am retrieving the object I want. That is a normal JSON object.
The problem is, on the view, if I try to print some property of the object (the same properties I see on the console) like that
{{ webs.name }}
I get the whole time that error:
Error in ./HomePage class HomePage - caused by: Cannot read property 'name' of undefined
That was sooo easy with Angular 1 :( I already read a lot of tutorials but I can't find any answer to my problem.
Thanks for your help.
The view is shown before the http response is returned.
{{webs?.name}}
should work.
Or do this.webs=getWebs()
and {{webs.name | async}}
It should be something
this.getWebs().then((webs) => {
webs.subscribe(response => {
this.webs = response;
resolve(webs);
console.log(this.webs);
});
})
so after you getWebs do this.This is untested code but you get the logic.
You are calling before you get data.
ngOnInit(){
return new Promise(resolve => {
this.http.get('webs.json')
.map(res => res.json())
.subscribe(webs => {
this.webs = webs;
resolve(this.webs);
});
});
}