2

I am trying to fetch data from an external api and I use async and await. I want to wait for user input from an onClick function and then to pass the url to an async function and to get the data in json format form that url. OnClick function is working:

onClick(){
   this.data=(<HTMLInputElement>document.getElementById('data')).value;
    
   return this.url='https://api.url.info/feed/'+this.data
}

When I use console.log(data2) undefined an the next error: Failed to load resource: the server responded with a status of 404 (Not Found)

async getData(){
    var data2=this.url;
    const response=await fetch(this.url);
    this.data=await response.json();
}

ngOnInit(){
    this.getData();
}

HTML

<input type="text" id="data"  value=""/>
<button type="button" (click)="onClick()" id="btn">Search</button>

6
  • I'm not familiar with angular but the general approach is to call the fetching function inside the event handler. That event handler is already the way to wait for user input. About async/await specifically: A promise can only resolve once, so it can't represent an event handler that can fire multiple times. Commented Nov 25, 2020 at 9:31
  • 2
    Hi Santal, I'd definitely recommend you to read the angular documentation angular.io/docs as accessing DOM elements by using document is not the way to go. Angular is here especially for that, to simplify your life and abstract this away. Same for the HTTP layer. Angular HttpClient which lets you do HTTP requests instead of doing fetch yourself. Commented Nov 25, 2020 at 9:32
  • @maxime1992 is correct. If you share with us your HTML template, we can give you an example with the correct Angular way of doing both tasks. Commented Nov 25, 2020 at 9:42
  • I edit my post and now i have the html template Commented Nov 25, 2020 at 9:44
  • I still don't see the HTML element with the id equal to "data" which is what you are trying to access. Commented Nov 25, 2020 at 9:45

2 Answers 2

3

Below I made a working solution following the Angular best practices, the code is commented to help you understand it better.

Demo

Template

<input #yourData id="data" type="text" id="input"  value="" />
<button type="button" (click)="onClick()" id="btn">Search</button>

Component

import { Component, OnInit, ViewChild, ElementRef } from "@angular/core";
import { HttpClient } from "@angular/common/http";

@Component({ ... })
export class YourComponent implements OnInit {
  data: any; // The api response is going to be stored here
  baseUrl: string = 'https://api.url.info/feed/';

  // You need to import the HttpClientModule in your module (in the AppModule is ideal)
  // Make sure to import it only once.
  constructor(private http: HttpClient) { }

  // One of the proper ways to access
  // Documentation: https://angular.io/api/core/ViewChild
  @ViewChild("yourData", { static: true })
  yourTemplateElement: ElementRef<HTMLInputElement>;

  // Use ngOnInit if the static option is set to true, use ngAfterViewInit otherwise
  async ngOnInit() {
    this.data = await this.getData(this.baseUrl);
  }

  getData(url: string): any {
    // Use the http client service to make http calls.
    // By default it returns an observable but since you want to use
    // the async/await keywords, we need to convert it into a promise
    return this.http.get(url).toPromise();
  }

  async onClick() {
    const urlSegment = this.yourTemplateElement.nativeElement.value;
    this.data = await this.getData(this.baseUrl + urlSegment);
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

I used this demo and is working,i have one more question (if you want to help me):i got the api response in a json format and i want to use reduce function to get a specific value from the response and i get this error :TypeError: this.reduce is not a function .
I will do my best to help but more information might be required. The this keyword in this case will refer to the class instance (in your case, your component) and since you don't have such a method, that error is thrown. I'm deducing that you are trying to use the arrays reduce method, correct? So it should be something like this.data.reduce(...) but since you want to get a specific value from the list, maybe the array find method would be more appropriate.
1

In your onClick method, call the getData() method and don't call this.getData() in ngOnInit. Your code should look like:

onClick(){
    this.data=(<HTMLInputElement>document.getElementById('data')).value;
    const url='https://api.url.info/feed/'+this.data;
    this.getData(url);
  }
async getData(url){
    const response=await fetch(url);
     this.data=await response.json();
  }

3 Comments

Your example is a bit confusing because you are passing the URL to getData as well as assigning it to this.url and you are accessing both the parameter and this.url in getData. I'd recommend to clean this up a bit to make it less confusing.
You were right to point out. I have update the answer.
While this may work I'd strongly advise you against doing things like that when working with Angular. You are going in the opposite direction of good practices. Refer to my initial comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.