I am learning a tutorial and an assignment on how to bind id's to http request. This is what i am currently trying to do. I want to bind the id captured in my url and when i trigger the function, it submits the id captured from the url to my service. I am have been able to capture the url but the function to send the captured id to the service is where i am having the issues. The id in the function parameter is Unused.
//Food Component
export class FoodComponent implements OnInit {
private food_id;
constructor(private httpService: HttpService, private route: ActivatedRoute) {
}
ngOnInit() {
this.route.params.subscribe(params => {
if (params['id']) {
this.food_id = params['id'];
}
})
}
//food model
foodModel = {
type: "",
location: ""
};
sendFood() {
this.httpService.send(this.food_id)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food.value);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
Try this,
import { foodModel } from './foodModel';
export class FoodComponent implements OnInit {
private model: foodModel; /// Make a new variable of foodModel.
ngOnInit() {
this.model = new foodModel(); // Initialize the Model
this.route.params.subscribe(params => {
if (params['id']) {
this.model.id = params['id']; ///set the parameter id to model.id
}
})
}
/// Removed the parameter food_id
sendFood() {
this.httpService.send(this.foodModel)
.subscribe(data => {
console.log(data);
})
}
//service
send(food: any) {
const body = JSON.stringify(food);
const headers = new Headers();
return this.http.post('http://localhost:8000/api/luncheons/v1/location/' + food.id + '/type', body, {
headers: headers
})
.map((data: Response) => data.json());
}
}
// Make a class file foodModel.ts and import foodModel in your component.
export class foodModel {
type: any;
location: any;
id: number = 0; /// new variable added
};
Related
export class HttpClientService {
private baseURL: string;
tokenRepository: LocalTokenRepository;
instance: AxiosInstance;
constructor(baseURL: string, tokenRepository: LocalTokenRepository) {
this.tokenRepository = tokenRepository;
this.baseURL = baseURL;
this.instance = axios.create({
baseURL: this.baseURL,
headers: { Authorization: this.tokenRepository.get() }
});
this.handleInterceptor();
}
private handleInterceptor = () => {
this.instance.interceptors.response.use(
this.handleResponse,
this.handleError
);
};
private handleResponse = ({ data }: AxiosResponse) => data;
protected handleError = (error: any) => Promise.reject(error);
}
export class AuthService {
private httpClient: HttpClientService;
private tokenRepository: LocalTokenRepository;
constructor(
httpClient: HttpClientService
// tokenRepository: LocalTokenRepository
) {
this.httpClient = httpClient;
this.tokenRepository = this.httpClient.tokenRepository;
}
async signup(email: string, password: string) {
const accessTOKEN = (await this.httpClient.instance.post(
'data',
{ email, password },
{ params: '' }
)) as string;
this.tokenRepository.save(accessTOKEN);
}
async singin(email: string, password: string): Promise<any> {
console.log(email, password, 'signIn?');
// return await this.httpClient.instance.get('products', { params: '' });
}
signout() {
this.tokenRepository.remove();
}
}
export const apiContext = createContext<APIType | null>(null);
const tokenRepository = new LocalTokenRepository();
const httpClient = new HttpClientService('baseurl', tokenRepository);
const productService = new ProductService(httpClient);
const authService = new AuthService(httpClient);
export const ApiProvider = ({ children }: { children: React.ReactNode }) => {
return (
<apiContext.Provider value={{ productService, authService }}>
{children}
</apiContext.Provider>
);
};
I made network logic like this. Make the network logic by class and inject dependency by context API. Is there any advantages of making network logic by class?
I don't recognize between network class logic and use axios right away.
What is the best way to handle api logic in react? and What kind of method people use the most?
I am trying to show response from an observable on console that comes from a service in my angular project. But it appears to be undefined. When I try with a loop, the error in console says it is not iterable while the observable is supposed to return an array. Why could this be happening?
Component
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService, private messageService: MessageService) { }
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(data => this.heroes = data);
}
ngOnInit() {
this.getHeroes();
// for(let hero of this.heroes){
// console.log(hero);
// }
console.log(this.heroes);
}
}
Service
#Injectable({
providedIn: 'root'
})
export class HeroService {
private heroesUrl = 'api/heroes';
constructor(
private messageService: MessageService,
private http: HttpClient
) { }
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
getHeroes(): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(_ => this.log('fetched heroes')),
catchError(this.handleError<Hero[]>('getHeroes', []))
);
}
private log(message: string) {
this.messageService.add(`HeroService: ${message}`);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
this.log(`${operation} failed: ${error.message}`);
return of(result as T);
};
}
}
That is happening because the request is asynchronous, that means the execution of the program continues while the request is resolved.
In other you should use the result of the request when it is resolved. In your example that would be after you are assigning the returned value of the request to heroes property.
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(data => {
this.heroes = data; // <- after this point you have the result
console.log(this.heroes);
});
}
Array not passing from service to component:
In the test() function on the service.ts page, google calendar data is successfully being read and pushed to an array called response. All the data logs.
When lesson-summary.component.ts calls on the test() function, the response array data does not show up in the lesson-summary.component.html
Thanks for any help!
google-calendar.service.ts
import { Injectable, Directive } from "#angular/core";
import * as moment from "moment-timezone";
declare var gapi: any;
#Injectable({
providedIn: "root"
})
export class GoogleCalendarService {
private response = [];
constructor() { }
test() {
gapi.load("client", () => {
gapi.client.init({
apiKey: "API string here",
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]
}).then(() => {
var month = moment().month();
const firstOfMonth = moment().startOf("month").format("YYYY-MM-DD hh:mm");
const lastOfMonth = moment().endOf("month").format("YYYY-MM-DD hh:mm");
var firstOfMonthUTC = moment.tz(firstOfMonth, "America/Toronto").format();
var lastOfMonthUTC = moment.tz(lastOfMonth, "America/Toronto").format();
return gapi.client.calendar.events.list({
calendarId: "calendar id here",
timeMax: lastOfMonthUTC,
timeMin: firstOfMonthUTC,
singleEvents: true
});
})//end of .then
.then((data) => {
this.response.push.apply(this.response, data.result.items);
console.log(data.result.items, "data.result.items");
return this.response;
});//end of .then
});//end of .load
}//end of test
}//end of export
lesson-summary.component.ts
import { Component, OnInit } from "#angular/core";
import { Observable } from "rxjs";
import { GoogleCalendarService } from "../google-calendar.service";
declare var gapi: any;
#Component({
selector: "app-lesson-summary",
templateUrl: "./lesson-summary.component.html",
styleUrls: ["./lesson-summary.component.css"]
})
export class LessonSummaryComponent implements OnInit {
private response;
constructor(
private calendarService: GoogleCalendarService) {
this.response = this.calendarService.test();
}
ngOnInit() {
}
}
lesson-summary.component.html
<ul>
<li *ngFor = "let item of response">
{{ item.summary }}
</li>
</ul>
That's because you're mixing promises and sync functions in an incorrect way, so the test() function will not return anything.
Try adding a promise to your test():
test() {
return new Promise(resolve => { // <-- now test func return promise
gapi.load("client", () => {
gapi.client.init({
apiKey: "API string here",
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]
}).then(() => {
// code...
}).then((data) => {
// code...
resolve(this.response); // <-- when we have the response, we are resolving the promise
});
});
});
}
And then use this promise in the component:
this.calendarService.test().then(data => this.response = data);
Learn more about promises on MDN
How can i add authentication token to the file upload service? When i login in my application, i am able to retrieve the token from the backend but i am having a hard time as to how to add it the to file service. When i try to upload a file, it get an error saying "token_not_provided". As it is in my service, i have added the authentication token in my header so whenever i make a request, the server is aware of the user at hand. But with the file submission, i have no idea of how to append the authentication token to the file service
#Component({
providers:[AuthenticationService]
})
#Injectable()
export class FileUploadService {
public progress$;
public progressObserver;
public progress : number;
public token: string;
public headers:string;
constructor (private auth:AuthenticationService) {
this.progress$ = Observable.create(observer => {
this.progressObserver = observer
}).share();
}
makeFileRequest (url: string, params: string[], files: File[]) {
return Observable.create(observer => {
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(JSON.parse(xhr.response));
observer.complete();
} else {
observer.error(xhr.response);
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.setRequestHeader(this.headers, this.auth.token);//modified
xhr.send(formData);
});
}
}
//service
updateFood(food:any) {
const body = JSON.stringify(food);
const headers = new Headers({ 'Authorization': 'Bearer ' + this.authenticationService.token });
return this.http.put('http://localhost:9000/, body, {headers: headers})
.map((data:Response) => data.json());
}
Somewhere between your xhr.open and xhr.close you can append headers
xhr.setRequestHeader(header, value);
See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader for more detailed documentation
I want to develop a file configuration of json and it is called with http get the constructor and return the value I want the config file to another component. But when return gives me value undefined.
My Config.json
[ {"urlServer": "http://localhost:56877"}]
My Config.Service
export class configService
{
url: string;
constructor(public _http: Http)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try {
return this._http.get('/app/config.json',
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <configModel>res.json();
this.url = data.urlServer;
JSON.stringify(this.url);
});
}
catch (ex) {
logger.registarErros('configService', ex);
}
}
returnConfig()
{
return this.url;
}
Now my other Component
constructor(public _http: Http, public config: configService)
{
this.token = sessionStorage.getItem('token');
this.username = sessionStorage.getItem('username');
}
login(username: String, password: String)
{
let injector = Injector.resolveAndCreate([loggerService]);
let logger = injector.get(loggerService);
try
{
alert(this.config.url);
return this._http.post('http://localhost:56877/api/Login/EfectuaLogin', JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return Observable.of('authObservable');
});
}
catch (ex) {
logger.registarErros('authentication', ex);
}
}
I no longer know how to solve the problem, I need your help, I'm not very experienced with Angular 2.
Thanks very much.
The problem here is that the config is load asynchronously. You could use something like that leveraging the flatMap operator:
#Injectable()
export class ConfigService {
urlServer:string;
constructor(public _http: Http) {
}
getConfig() {
if (this.urlServer) {
return Observable.of(this.urlServer);
}
return this._http.get('/app/config.json', {
headers: contentHeaders
})
.map((res: any) => {
let data = <configModel>res.json();
return data.urlServer;
}).do(urlServer => {
this.urlServer = urlServer;
});
}
}
and in your component:
login(username: String, password: String) {
return this.configService.getConfig().flatMap(urlServer => {
this._http.post('http://localhost:56877/api/Login/EfectuaLogin',
JSON.stringify({ username, password }),
{
headers: contentHeaders
})
.map((res: any) =>
{
let data = <authLoginModel>res.json();
this.token = data.token;
this.username = data.nome;
sessionStorage.setItem('token', this.token);
sessionStorage.setItem('username', this.username);
return data; // or something else
});
}
});
}
Another approach would be boostrap asynchronously after having loaded the configuration:
var app = platform(BROWSER_PROVIDERS)
.application([BROWSER_APP_PROVIDERS, appProviders]);
service.getConfig().flatMap((url) => {
var configProvider = new Provider('urlServer', { useValue: urlServer});
return app.bootstrap(appComponentType, [ configProvider ]);
}).toPromise();
See this question for the second approach:
angular2 bootstrap with data from ajax call(s)
You can go further by mixing the last approach with a CustomRequestOptions:
import {BaseRequestOptions, RequestOptions, RequestOptionsArgs} from 'angular2/http';
export class CustomRequestOptions extends BaseRequestOptions {
merge(options?:RequestOptionsArgs):RequestOptions {
options.url = 'http://10.7.18.21:8080/api' + options.url;
return super.merge(options);
}
}
See this question:
Angular 2 - global variable for all components