Passing API data from one page to another


#1

am currently building a recipe app, I have a list of recipes pulling from an API. For this to work I do a http get request as below. I want to pull the {{id}} from the JSON and place it in the url where (id) is.

loadDetails(id) {
  if (this.details) {
    return Promise.resolve(this.details);
  }

  return new Promise(resolve => {
    this.http.get('http://api.yummly.com/v1/api/recipe/' + (id) + '?_app_id=397aed16&_app_key=69e2565adcec7a6609b18bef31261e62')
      .map(res => res.json())
      .subscribe(data => {
        console.log(data);
        this.details = data;
        resolve(this.details);
      });
  });
}

By doing this I get this error in console the (id) is undefined

my .ts file that I am trying to load the recipes on is as below

  id: any;

  loadRecipes(){
    this.apiAuthentication.loadDetails(this.id)
    .then(data => {
      this.api = data;
    });
  } 

Any help would be great


#2

I’m not sure if you have already attempted to pass the data from one page to another, some more code would be needed as I’m not sure how this whole thing structured.

To send the params: this.nav.push(view, data);

To read the data: https://ionicframework.com/docs/v2/api/navigation/NavParams/


#3

Why is id in parenthesis? When using concatenation, you don’t need parenthesis. The app is looking in a variable that doesn’t exist for the value so it’s getting undefined. If Id has the right value, getting rid of the parenthesis should work.


#4

He can add as many parentheses as he wants, though pointless, it shouldn’t break anything at all.


#5

Very true… was just waking up and thinking I’ve never seen it before but of course he could do (Id + 1) or something. My bad


#6

Thanks for the reply, I have attempted to use this but kinda failed to be honest. I took away the parenthesis and I still have an undefined value. I understand the value that gets put into the URL is this.id, but I cant work out how to check if I have this ID or not. Further assistance would be great.


#7

Please provide some more of your code from both components :slight_smile:


#8

So I have a listing page which lists out recipes in certain categories which the html is (this is just a normal http get request which pulls from a provider)

<ion-content>
	<ion-list>
		<ion-item *ngFor="let item of api" [navPush] = "detailsPage">
			<div class="thumb">
				<img src="{{item.smallImageUrls}}">
			</div>
			<div class="text">
				<div class="inner">
					<div class="title">
						<h1>{{item.recipeName}}</h1>
					</div>
					<div class="rating">
						<rating [(ngModel)]="item.rating"></rating>
					</div>
					<div class="time">
						<p>{{item.totalTimeInSeconds | HoursMinutesSeconds}} minutes</p>
					</div>
					<div class="ingredients">
						<p>{{item.ingredients.length}} Ingredients</p>
					</div>

					<div class="course">
						<p>{{item.attributes.course}} </p>
					</div>
				</div>
			</div>
	  	</ion-item>
	</ion-list>
</ion-content>

and .ts file is

export class Category1Page {
  private rate = 2.5;
  public api: any;
  detailsPage = DetailsPage;

  constructor(public navCtrl: NavController, public navParams: NavParams, public apiAuthentication: ApiAuthentication) {
  	this.loadRecipes();
  }

  loadRecipes(){
    this.apiAuthentication.loadCategory1()
    .then(data => {
      this.api = data;
    });
  } 
}

I then has a details page which is the recipe in its singular form (listing out ingredients, method… etc) which I currently test with a single recipe until this issue is solved.

html is

<ion-content>
	<ion-list>
		<ion-item>
			<div class="thumb">
				<img src="{{api?.images[0].hostedLargeUrl}}">
				<h1>{{api?.name}}</h1>
			</div>
			<div class="action-bar">
				<div class="like" (click)="toggle()">
				  	<ion-icon *ngIf="!visible" name="ios-heart-outline"></ion-icon>
				  	<ion-icon *ngIf="visible" name="ios-heart"></ion-icon>
					<span>Like</span>
					<span class="count">{{counter}}</span>
				</div>
				<div class="time">
				  	<ion-icon name="ios-time-outline"></ion-icon>
					<span>{{api?.totalTime}}</span>
				</div>
				<div class="share">
				  	<ion-icon name="share"></ion-icon>
					<span>Share</span>
				</div>
			</div>
			<div class="ingredients"> 
				<h1>Ingredients</h1>
				<div class="shopping-list">
					<ion-icon name="ios-cart"></ion-icon>
					<h1>Add to shopping list</h1>
				</div>
				<ul>
					<li *ngFor="let item of api?.ingredientLines">{{item}}</li>
				</ul>
			</div>
			<div class="method">
				<h1>View Method</h1>
				<button class="button button-block button-positive" (click)="launch(api?.source.sourceRecipeUrl)">Click to see cooking steps!
				</button>
            </div>
            <div class="reviews">
            	<h1>Reviews</h1>
            </div>
            <div class="related">
            	<h1>Related</h1>
            </div>
            <div class="map">
            	<h1>Nearest Supermarket</h1>
            </div>
		</ion-item>
	</ion-list>
</ion-content>

and .ts file is

export class DetailsPage {
  private rate = 2.5;
  public api: any;
  public cordova: any;
  visible = false;
  id: any;
  public counter : number = 0;

  constructor(public navCtrl: NavController, public navParams: NavParams, public apiAuthentication: ApiAuthentication, private platform: Platform) {
    this.loadRecipes();
  }

  toggle() {
    this.visible = !this.visible;

    if (!this.visible) {
      this.counter -= 1;
    } else {
      this.counter += 1
    }
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad DetailsPage');
  }

  launch(url) {
    this.platform.ready().then(() => {
        // cordova.InAppBrowser.open(url, "_system", "location=true");
    });
  }

  loadRecipes(){
    this.apiAuthentication.loadDetails(this.id)
    .then(data => {
      this.api = data;
    });
  } 
}

That is all my code in relation to this pretty much, obviously the url im trying to get is the one I asked in the initial question.

Thankyou for the help :slight_smile:


#9

I must be missing something really obvious, but I don’t see anywhere that ever sets the id property of DetailsPage.


#10

so this ID is coming from the JSON

is realised i could do this.id = "test" which would then replaced the undefined, but I want to put the id from the JSON above

  loadRecipes(){
    this.id = "test";
    this.apiAuthentication.loadDetails(this.id)
    .then(data => {
      this.api = data;
    });
  }

#11

The fundamental principle of asynchronous programming in JavaScript is that when you create a future (either Promise or Observable) you also provide some chain code in the form of a then or subscribe block.

Only within that chain block can you rely on the value resolved from the future. You can stash it in an object property, but absolutely anywhere that object property is referenced (both in templates and backing code) outside of the chain block must be able to cope with the situation that it hasn’t been set yet. So if you’re going to kick off further HTTP requests (such as by calling loadRecipes) you must do it from within a then or subscribe that is providing the id. You cannot rely on the object property being set anywhere else.