Can't load image after async call in ionic 2

I’m trying to make a product grid, but I can’t load its image after I make the asynchronous call to get the products from the server.

<ion-content padding>
<ion-grid>
    <ion-row *ngFor="let i of rows">
        <ion-col *ngFor="let product of products | slice:(i*2):(i+1)*2" width-50>
            <ion-row>
                <ion-img width="150" height="150" src="assets/img/eastereggs/placeholder.png"></ion-img>
            </ion-row>
            <ion-row>
                {{product.displayName}}
            </ion-row>
            <ion-row>
                <ion-col>
                preço:{{product.price}} 
                </ion-col>
                <ion-col class="quantity">
                    <div class="add-product" [hidden]="product.quantity!=0">
                        <ion-icon name="add" item-right></ion-icon> 
                    </div>
                    <div class="set-quantity" [hidden]="product.quantity==0">
                        <ion-icon name="arrow-dropleft" item-right></ion-icon> 
                        {{product.quantity}}
                        <ion-icon name="arrow-dropright" item-right></ion-icon> 
                    </div>
                </ion-col>
            </ion-row>
        </ion-col>
    </ion-row>
</ion-grid>

However, if load it without making waiting for the asynchronous call

<ion-row *ngFor="let i of [1,2,3]">
        <ion-col *ngFor="let product of [1,2,3,4,5,6] | slice:(i*2):(i+1)*2" width-50>
            <ion-row>
                <ion-img width="150" height="150" src="assets/img/eastereggs/placeholder.png"></ion-img>
            </ion-row>
            <ion-row>
                name
            </ion-row>
            <ion-row>
                <ion-col>
                price 
                </ion-col>
                <ion-col class="quantity">
                    <div class="add-product" [hidden]="product.quantity!=0">
                        <ion-icon name="add" item-right></ion-icon> 
                    </div>
                    <div class="set-quantity" [hidden]="product.quantity==0">
                        <ion-icon name="arrow-dropleft" item-right></ion-icon> 
                        0
                        <ion-icon name="arrow-dropright" item-right></ion-icon> 
                    </div>
                </ion-col>
            </ion-row>
        </ion-col>
    </ion-row>

Finally, to get the products I create the following promise

public getProducts(subcategoryId) {

    let qs = new URLSearchParams();
    qs.append('subcategoryId', subcategoryId);

    let requestOptions = new RequestOptions();
    requestOptions.search = qs;


    // don't have the data yet
    return new Promise(resolve => {
        this.http.get(path, requestOptions)
        .map(res => res.json())
        .subscribe(data => {
            resolve(data);
        });
    });
}

This data is then treated in another part, where I create the product array, that I don’t think it’s relevant, but I can post here if anyone thinks that’s where the problem might be.

I’ve been looking for similar posts for a while, but most people were using the wrong path, but I don’t think it’s that, since I’ve already established that it works without the async call.

I’m confused, because I don’t see any image that depends on the product. The only one I see is a static “placeholder.png”. In any event, a few things:

  • Don’t use <ion-img> outside of a virtual scroll context
  • I’m not a fan of making pipes do this sort of work, and would shift it to the controller
  • You are instantiating a Promise for no reason and eating errors silently.
  • You are also combining an operation that creates/transforms a future into one that consumes it. I think that’s an antipattern. I would move the subscription to the page and everything else into a service provider. I would also just return the Observable you get from Http, but if you insist on using a Promise, create it with Observable.toPromise() instead.
1 Like

That’s is exactly my problem, the image isn’t related to the product (yet), but this problem occurs.

I’m new at this, so my questions might seem obvious to you, but here it goes:

It’s a scrollable view, do I need to set it somewhere?

I don’t know what a pipe is, so I’m not sure what you’re talking about. Just to make it clear, the getProducts (in the question) is in a productProvider.ts that I call from the controller product.ts (also a getProducts).

getProducts(subcategoryId){
        this.productProvider.getProducts(subcategoryId)
        .then(
        data => {
            for(let index in data){
                let name = data[index].name;
                let displayName;
                if(name.length > 30)
                    displayName = name.substring(0,27) + "...";
                else
                    displayName = name
                let product = {displayName: displayName, name:data[index].name, image:null, price:"---", quantity:0, productId:data[index].name, link:data[index].link};
                this.products.push(product);
          }
          this.rows = Array.from(Array(Math.ceil(this.products.length)).keys())
        });
    }

I think I explained the reason just above. Does it make sense now, or is it still senseless? Also, what do you mean about eating errors silently? Is it because I’m not checking what I got? If so, that is in the TODO list, I just didn’t get to it yet, still, it’s a good remark, thanks!

I think I covered the provider part, but I’ll look into the Observable part, because I have no idea about what it is. I have no attachment to promises, it’s just what I learned when I looked into http requests. If Observable is the way to go, I’ll change it.

Finally, thank you for this thoroughly analysis!

That’s not the same as virtual scroll, and if you’re not using virtual scroll, then just switch to <img>.

That’s strange, because you are using some sort of slice pipe in here:

*ngFor="let product of products | slice:(i*2):(i+1)*2"

No. You never want to be whiting new Promise, no matter how many times you see it being suggested. Obviously, that’s a bit of an exaggeration, but you really should treat it as gospel for now.

It’s an artifact of the way you’re making the Promise, and will go away once you eliminate that. The way you are writing it now, you only ever call resolve, so any network errors just get ignored.