API not getting called in service file Angular 7 - javascript

I am working with a news App. When I try to call API, it is not getting called in service file function. When I try to console it is getting consoled but when I see network tab there is no API called.
Component file:
newPostView(postId: { split: (arg0: string) => any[]; }) {
postId = postId.split("-")[1];
this.data = {
postId: postId,
postType: localStorage.language
}
this._newsService.newsCount(this.data);
}
Below is my function in the service file.
newsCount(data) {
console.log("post data", data);
return this.http.put(config.baseApiUrl + 'post-views', data);
}

If you are returning from the service file then you should subscribe in component file. So your updated code should look like this.
Component File:
newPostView(postId: { split: (arg0: string) => any[]; }) {
postId = postId.split("-")[1];
this.data = {
postId: postId,
postType: localStorage.language
}
this._newsService.newsCount(this.data).subscribe((res:any) =>{
});
}

Related

Why shareReply() method is not working as expected - Angular 15

Trying to make use of same API in 3 components, In order to avoid duplicate HTTP calls I can use shareReply() to cache the response and use it where ever I want from RxJs. So I did like below
api-service.ts
getUsers(): Observable<any> {
let headers = new HttpHeaders();
headers = headers.set('app-id', '63b691428f53f6370fc9eed6');
return this.http.get(this.url, { headers }).pipe(
map((resp) => {
return resp;
}),
shareReplay()
);
}
test1-component
data$!: Observable<any>;
constructor(private api: ApiService) {}
ngOnInit(): void {
this.loadTest1Data();
}
loadTest1Data() {
this.data$.subscribe({
next: (response) => {
console.log('Loading data for Component - 1', response);
},
error: (error) => {
console.log('Error While Loading data for Component - 1', error);
},
complete: () => {
console.log('Success');
},
});
}
test2-component (test3-component also use same code)
data$!: Observable<any>;
constructor(private api: ApiService) {}
ngOnInit(): void {
this.loadTest2Data();
}
loadTest2Data() {
this.data$.subscribe({
next: (response) => {
console.log('Loading data for Component - 2', response);
},
error: (error) => {
console.log('Error While Loading data for Component - 2', error);
},
complete: () => {
console.log('Success');
},
});
}
Error i got reproducing HERE - Stackblitz
Cannot read properties of undefined (reading 'subscribe')
Could someone tell me what went wrong and how to resolve it? or is there any other alternative approach is there? (apologies, I'm not allowed to use any third party state management tools)
Thanks in Advance for your valuable time
Your test components aren't defining data$ so this.data$.subscribe is doing the equivalent of undefined.subscribe, hence the error.
For the test components you can do
#Input() data$: Observable<any> = of();
and pass in via
<app-test1 [data$]="data$"></app-test1>
Note, it's more common to do
<app-test1 [data]="data$ | async"></app-test1>
so that the components receive the data directly and the AsyncPipe takes care of subscribing and unsubscribing.

Is there a difference in data/promise returned from axios get and post?

I'm working on a React application that makes use of an imported object with a get request to an api and a post request to a related API.
When creating a new instance of my service in the frontend in React, I am able to successfully use the '.then' & '.catch' functions to access the returned data ONLY from the get request.
When using the post request from the same object, when trying to access the response object, I get a (paraphrased) '.then' is not a function on undefined.
Only when I explicitly write out the post request in my form submit function (without consuming a service) and handling the object there am I able to check the response and subsequently set the state.
What is the appropriate/best practice way for using axios in React and why am I not able to access the response object when I create a new instance of a service?? Much appreciated!
Service:
import axios from 'axios';
class ProductServices {
getAllProducts(){
return axios.get('https://somecustomAPIURL')
}
postProduct(somePathConfig){
axios.request({
url: 'https://somecustomAPIURL' + somePathConfig,
method: 'post',
headers: {'some-custom-header': process.env.REACT_APP_API_POST_KEY}
})
}
}
export default ProductServices;
React Code instantiating and consuming the service (note, that getAllProducts works just fine, but trying to consume a response object in postProduct returns an '.then' is undefined)
constructor(){
super();
this.state = {
products: [],
productID: null,
showModal: false
}
this.ProductServices = new ProductServices();
}
getAllProducts = () => {
this.ProductServices.getAllProducts()
.then((response) => {
let items = response.data.data.items;
this.setState({
products: items,
productID: items[0].id
});
return response;
})
.catch((error) => {
console.log('Error!', error);
return error;
})
}
handleFormSubmit = (e) => {
e.preventDefault();
let productID = this.state.productID;
this.ProductServices.postProduct(productID)
.then((response) => {
this.setState({showModal: true}, () => console.log('Success!'));
return response;
})
.catch((err) => {
console.log('Error!', err);
})
}
You missed return before axios.request.
import axios from 'axios';
class ProductServices {
...
postProduct(somePathConfig){
return axios.request({
url: 'https://somecustomAPIURL' + somePathConfig,
method: 'post',
headers: {'some-custom-header': process.env.REACT_APP_API_POST_KEY}
})
}
...
Also, instead of axios.request, you can use axios.post like axios.get
return axios.post(url, body, { headers });
return axios.get(url, { headers });
return axios.put(url, body, { headers });
return axios.delete(url, { headers });
return axios.request(axiosConfigOptions);

Angular 7: Send response message from service

I make request from service file in my Angular project:
signIn(username: string, password: string): Observable<any> {
const formData = ...
this.http.post(`${this.uri}`, formData, httpOptions)
.subscribe(res => console.log(
if (statusCode === '0') {
this.message = 'test';
} else {
this.message2 = 'test2';
}
})));
return;
}
This function works very well. But I cannot shot my message in my HTML. When I type {{message}} in HTML, its undefined.
I declared message: String; but its not work.
I guess services are private and this problem is so.
How can I show my response in HTML? What is the best way?
UPDATED: This is my component:
message: String;
signIn(username, password): Observable<any> {
this.cookieService.deleteAll();
this.ls.signIn(username, password).subscribe(res =>
xml2js.parseString(res, function (err, result) {
const statusCode = ...
console.log(statusCode); // it getting statusCode
if (statusCode === '0') {
this.message = 'test'; //Potentially invalid reference access to a class field via 'this.' of a nested function
} else {
}
}));
return;
}
You can not access component fields in service. You need to pass response of service by some way and then only you can use that response and based on that assign value to message and display in your html.
I think you should use callback in which you'll wrap your http request's response and will use at outer layer of service.
signIn(username: string, password: string, data:any) {
const formData = ...
this.http.post(`${this.uri}`, formData, httpOptions)
.subscribe(response => {
data(response);
}, error => data(// do something here);
}
now use this as something like this(at component I think):
message: String;
this.restService.signIn(userName, password, response => {
if(response && response.hasOwnProperty('statusCode')) {
if (response['statusCode'] === '0') {
this.message = 'test';
} else {
this.message = 'test2';
}
}
});
now you can use message in html
{{message}}
NOTE
You should always use service layer for data transfer only(if it is rest/api service), business logic or data manipulation should be used at some intermediate service or component level.
At this way you can make generic rest service and use across application, you just need to pass request body, url and response callback object.
If you're going to write logic in service then you'll have to write separate service for each api call.
Angular templates will search variables only in component which we are declared in them. So do changes like below in your template
<p> {{service.message}} </p>
Here the service is which you are injected into your component.
If you are declare message:string in your service that's fine, by default variables are public and we can access them in templates. But with the help of service variable which we are injected them through constructor.
I hope this will solve your issue :)
I suppose your sample code is part of a service class : you cannot access service attributes like message or message2 from your HTML template.
You have to return HTTP observable to the controller and put the subscribe logic in your controller.
Service:
return this.http.post(`${this.uri}`, formData, httpOptions);
Controller:
message: String;
signIn(username, password): Observable {
this.cookieService.deleteAll();
this.ls.signIn(username, password).subscribe(res =>
const self = this;
xml2js.parseString(res, function (err, result) {
const statusCode = ...
console.log(statusCode); // it getting statusCode
if (statusCode === '0') {
self.message = 'test';
} else {
}
}));
return;
}

#Get decorator not working correctly in node.js

I am using #Decorators in my Restful Node application.
#Get('/:id')
getUser(#Response() res: any, #Params('id') id: string) {
this.getOneById(res, id)
}
// In Base Controller
async getOneById(#Response() res: any, id: number) {
const item = await this.getOne({ id })
if (item) {
res.send({
success: true,
data: item
})
} else {
this.errorHandler(res, 'No Data with provided id')
}
}
I have defined getOneById function in base controller and path it's id from Params decorator.
But id is wrong when I tried to log by console.log(id);
Anyone can help?
You should add async in decorate function

Angular 2 - Viewing a Single Record of Data

I am new to Angular so I am having trouble figuring out how to form my questions for what I am trying to accomplish, but here it goes.
I have a component that is fetching a single user record from a service. I then want to display those user details on my UI. In other parts of my code, they have always been multiple records so I have used *ngFor and looped over the array of data. However, since this is just a single result, I am not too sure how to accomplish this.
Component:
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { UserRecord } from '../shared/user-record.interface';
import { UserService } from '../shared/user.service';
#Component({
selector: 'app-view-record',
templateUrl: './view-record.component.html',
styleUrls: ['./view-record.component.css']
})
export class ViewRecordComponent implements OnInit {
private record: UserRecord[];
private errorMessage: any = '';
private loaded = false;
private RecordID: number; // User ID of who we are looking at
constructor(private _crudService: UserService,
private activatedRoute: ActivatedRoute) { }
ngOnInit() {
// Get the userID from the activated route
this.activatedRoute.params.subscribe((params: Params) => {
this.RecordID = params['id'];
});
// Call our service and pass the userID
this._crudService.getRecord(this.RecordID)
.then(res => {
this.record = this._crudService.record;
return this._crudService.getRecord(this.RecordID);
})
.then(res => {
console.log(this.record)
this.loaded = true;
})
.catch(err => { console.error(err); });
}
}
Service:
getRecord(userID: number) {
const headers: Headers = new Headers({
"Authorization": this._frameworkService.getSessionInfo().token
});
return new Promise((resolve, rejects) => {
this._http.post(this.baseUrl + '/fetchRecord', { "userID": userID }, { "headers": headers })
.map(res => res.json())
.subscribe((data) => {
if (data) {
this.record = data;
}
resolve(true);
});
});
}
Interface:
export interface UserRecord {
RecordID: number;
QID: string;
FavoriteColor?: string;
FavoriteNumber?: number;
FavoriteActor?: string;
MetaInsertUTC: string;
MetaUpdateUTC: string;
FirstName: string;
LastName: string;
NTID: string;
}
Service Result:
[
{
"RecordID":"55",
"QID":"Q00019204",
"FavoriteColor":"Blue",
"FavoriteNumber":"6",
"FavoriteActor":"Bob",
"MetaInsertUTC":"2017-06-29 18:47:01.750",
"MetaUpdateUTC":null,
"FirstName":"Jim",
"LastName":"Bobs",
"NTID":"bobby"
}
]
In my Component HTML, I have tried {{record.FirstName}} but receive the error of ViewRecordComponent.html:16 ERROR TypeError: Cannot read property 'FirstName' of undefined.
Since this isn't a set of data results, I don't see how *ngFor would be applicable in the use case.
I assumed that since my component is storing the data in the record object, I should be able to access that from the UI? The console.log shows all of the correct data points.
How would I reference the users FirstName in my component HTML? Hopefully I'm on the right path at least.
Your response seems to be an array with an object, so record.FirstName doesn't exist, but record[0].FirstName does.
And when it comes to the view, remember to use either the safe navigation operator or *ngIf so that you do not run into undefined issues like mentioned by DeborahK. Observable type error: cannot read property of undefined
Furthermore just some suggestion on how to handle http in Angular... I would do something like the following...
getRecord(userID: number) {
const headers: Headers = new Headers({
"Authorization": this._frameworkService.getSessionInfo().token
});
return this._http.post(this.baseUrl + '/fetchRecord', { "userID": userID }, { "headers": headers })
.toPromise()
.then(res => res.json()[0]) // get the object only
.catch(err => { console.error(err); });
}
and component:
this._crudService.getRecord(this.RecordID)
.then(res => {
this.record = res;
});
But that's totally up to you :)
Getting data from Http is asynchronous. This means that when the page is first displayed, the data is not yet there.
There are several ways to resolve this:
One option is to use the "?" (safe navigation) operator: {{record?.FirstName}} This better handles nulls. See this link for more information: https://angular.io/guide/template-syntax#the-safe-navigation-operator----and-null-property-paths
Another option is to use *ngIf around your HTML code. *ngIf='record'
So when your page is first displayed, it will not generate an error that record is not yet set. As soon as the data is retrieved, the binding will notice the change and update the UI appropriately.
Here is what one of my service methods look like:
getProducts(): Observable<IProduct[]> {
return this._http.get(this._productUrl)
.map((response: Response) => <IProduct[]> response.json())
.catch(this.handleError);
}
And here is the call to that service:
ngOnInit(): void {
this._productService.getProducts()
.subscribe(products => this.products = products,
error => this.errorMessage = <any>error);
}
Notice that the subscribe is in the component that calls the service, not in the service itself.

Categories

Resources