0

i have a problem when I try to access to objects inside array. Here is my code:

import { Component, OnInit } from '@angular/core';
import {FirebaseService} from '../../services/firebase.service';
import { AngularFire, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2';
import {Router, ActivatedRoute, Params} from '@angular/router';
import * as firebase from 'firebase';
import { Observable } from 'rxjs';
import { FlashMessagesService } from 'angular2-flash-messages';

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {

  listings:any;
  search:any;
  imageUrls: any = [];
  images:any;
  myimage:any;
  count:any;
  constructor(
    private firebaseService: FirebaseService,
    private router:Router,
    public af:AngularFire,
    private route:ActivatedRoute,    
    private flashMessage:FlashMessagesService) {
    
    this.firebaseService.getListings().subscribe(listings => {
      this.listings = listings;
      this.count = listings.length;
    });  
  }
  ngOnInit() {   

    this.firebaseService.getListings().subscribe(listings => { 


      this.listings = listings;
      for(var i = 0;i<this.listings.length;i++){
        this.getImageUrl(listings[i].$key);
      }

      console.log(this.imageUrls);
      console.log(this.imageUrls[1].ImageUrl);
    });  
  }
  searchProps(){    
    this.firebaseService.getListingsByTitle(this.search.toLowerCase()).subscribe(listings => { 
      this.listings = listings;
    });
  }

  getImageUrl(prodid){
    this.imageUrls = []; 
    this.firebaseService.getListingImages(prodid).subscribe(images => { 
      this.images = images[0];
      let image = images[0];
      let storageRef = firebase.storage().ref();
      let spaceRef = storageRef.child(image.path);
      storageRef.child(image.path).getDownloadURL().then((url) => {
        // Set image url
        this.imageUrls.push(new ImageUrl(image.$key,url));        
      }).catch((error) => {
        console.log(error);
      });        
      });
  }

}
export class ImageUrl {
  url: string;
  id:string;
  constructor(_id:string,_url: string) {
     this.url = _url
     this.id = _id;
  }
}

My console log is showing this but i can't access to this.imageUrls[0]: enter image description here

I want to access to this.imageUrls[0] and get the url but says "undefined" I don't know why I can't do that. Please if someone can help me with this I am so stacked here.

EDIT 13/06/2017

With the help from @JesúsPallares now is showing always the same image. Now I want for each listing the image. I paste here my front end code:

    <div class="col-md-4" *ngFor="let listing of listings  | orderby:'!$key'"  >
        <div class="card">
            <div class="card-image">
                <img class="img-responsive" [src]="imgSelected">

                <span class="card-title">{{listing.title}}</span>
            </div>
            
            <div class="card-content">
                <p>Cards for display in portfolio style material design by Google.</p>
            </div>
            
            <div class="card-action">
                <a [routerLink]="['/listing/'+listing.$key]">+ Info</a>
                <a [routerLink]="['/listing/'+listing.$key]">Contacto</a>
            </div>
        </div>
    </div>
Community
  • 1
  • 1
Francisco
  • 163
  • 1
  • 5
  • 18
  • 1
    `... this but i can't access to this.imageUrls[0]:` <= what happens (error compile time, error run time) and where are you trying to call this (template code in html, component, somewhere else)? Please review [ask] as well as [mcve] to help clarify your question. – Igor Jun 12 '17 at 13:45
  • maybe try console.log(this.imageUrls[1]); – Reza Abolfathi Jun 12 '17 at 13:49
  • @Igor Says undefined. I edited the post. Thx. – Francisco Jun 12 '17 at 13:53
  • @Rabolf says undefined – Francisco Jun 12 '17 at 13:54
  • 1
    This is duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323). You are calling through to `getImageUrl` which executes an async call and does further processing to add the image urls but the call to this method is synchronous and then assumes the image urls are immediately available. Read through this duplicate to better understand how you have to write code when dealing with asynchronous calls like http calls. – Igor Jun 12 '17 at 13:57
  • You are also clearing the imageUrls array every time the function is called. – HaveSpacesuit Jun 12 '17 at 13:59
  • it's weird if console.log(this.imageUrls); works and shows the array but console.log(this.imageUrls[1]); says undefined then maybe try foreach – Reza Abolfathi Jun 12 '17 at 14:14
  • Why are you subscribing in both constructor and `ngOnInit`? In general, keep such logic, especially asynchronous logic, out of the constructor. It is designed to initialize static variables, etc. –  Jun 12 '17 at 14:14
  • this.imageUrls.forEach(function(entry) { console.log(entry); }); – Reza Abolfathi Jun 12 '17 at 14:15
  • @mrsundquist Yes I did that. But dind't work. – Francisco Jun 12 '17 at 14:46
  • @Rabolf I try it like you say but I don't have luck. – Francisco Jun 12 '17 at 14:46
  • @torazaburo I'm reading and trying to understand that. Thanks for the help. – Francisco Jun 12 '17 at 14:47

1 Answers1

0

You must make the 'getImagUrl' function synchronous. For example, you can do this by using Subject:

import {Subject} from 'rxjs';

imgSelected: any;

ngOnInit() {   
    this.firebaseService.getListings().subscribe(listings => { 
      this.listings = listings;
      for(var i = 0;i<this.listings.length;i++){
        this.getImageUrl(listings[i].$key).subscribe(isObtained => {
          if (isObtained) {
            this.imgSelected = this.imageUrls[0].url;
          }
        });
      }
    });
 }

getImageUrl(prodid): Subject<boolean> {
    let subject: Subject<boolean> = new Subject<boolean>();
    this.imageUrls = []; 
    this.firebaseService.getListingImages(prodid).subscribe(images => { 
      this.images = images[0];
      let image = images[0];
      let storageRef = firebase.storage().ref();
      let spaceRef = storageRef.child(image.path);
      storageRef.child(image.path).getDownloadURL().then((url) => {
        // Set image url
        this.imageUrls.push(new ImageUrl(image.$key,url));
        subject.next(true);
        subject.complete();
      }).catch((error) => {
        subject.next(false);
        subject.complete();
        console.log(error);
      });        
    });
    return subject;
}

One image label:

<img class="img-responsive" [src]="imgSelected">

Using ngFor:

<img *ngFor="let img of imageUrls" class="img-responsive" [src]="img.url">

ngOnInit update:

ngOnInit() {
    this.firebaseService.getListings().subscribe(listings => {
      let listingsLength = listings.length;
      let count: number = 0;
      let subject: Subject<any> = new Subject<any>();
      subject.subscribe(finish => {
        listings.forEach(list => {
          list.url = this.imageUrls.find(img => img.id === list.$key).url;
        });
        this.listings = listings;
      });
      for (let i = 0; i < listingsLength; i++) {
        count++;
        this.getImageUrl(listings[i].$key).subscribe(isObtained => {
          if (count === listingsLength) {
            subject.next('complete');
            subject.complete();
          }
        });
      }
    });
 }

HTML Code:

<div class="col-md-4" *ngFor="let listing of listings  | orderby:'!$key'"  >
    <div class="card">
        <div class="card-image">
            <img class="img-responsive" [src]="listing.url">

            <span class="card-title">{{listing.title}}</span>
        </div>

        <div class="card-content">
            <p>Cards for display in portfolio style material design by Google.</p>
        </div>

        <div class="card-action">
            <a [routerLink]="['/listing/'+listing.$key]">+ Info</a>
            <a [routerLink]="['/listing/'+listing.$key]">Contacto</a>
        </div>
    </div>
</div>
  • HI, thanx for the reply. I try what you say but I can´t access says: TypeError: Cannot read property 'ImageUrl' of undefined. So I do this: ` console.log(this.imageUrls[0].url); this.listings[0].src = this.imageUrls[0].url; ` and I get the first image url. If I do console.log show four times the url on my chrome console. – Francisco Jun 13 '17 at 04:34
  • Sorry for the error, I have just corrected in ngOnInit how to access the object correctly. Look again at the contents of the subscription to 'getImageUrl'. =) – Jesús Pallares Jun 13 '17 at 14:52
  • I want to do this: on my front end (later I will change 0 for $index) but says: ORIGINAL EXCEPTION: Cannot read property 'url' of undefined. I don't know why. You have idea? – Francisco Jun 13 '17 at 17:36
  • Ah okay. I just edited the answer with the solution. Hope this can help you. – Jesús Pallares Jun 13 '17 at 18:16
  • Now is showing always the same image. How I do this dynamic for each listing? I edit my post with full front end code. Please check it :). Thanks for this help. – Francisco Jun 13 '17 at 18:23
  • Try with ngFor on img label. – Jesús Pallares Jun 13 '17 at 18:33
  • Try this latest update in ngOnInit. You should also use the img with ngFor tag. Hope this can help you. – Jesús Pallares Jun 14 '17 at 08:26
  • Ok that put all images on each listing. Don't detect who is for each listing. Hmm – Francisco Jun 14 '17 at 14:24
  • Try last updated, HTML and ngOnInit code. I add the url attribute to each listing element. – Jesús Pallares Jun 14 '17 at 14:56