ionic-framework: RC4 ion-img doesn't correctly work with virtualScroll

Ionic version: (check one with “x”) [ ] 1.x [x ] 2.x

I’m submitting a … (check one with “x”) [x ] bug report [ ] feature request [ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/

Current behavior: When you use virtualScroll and ion-img, after scrolling down (when buffer ends) ion-img stops loading images

_034

Please look at code inspector:

2016-12-16 10-23-17

url http://base247.lin2/thumbs/c6/files_56_222bf7a3335ce7c20553f0f374eb0266b871af41.jpg_mobileListImage_1412346660_3.jpg

is correct (for my local machine) and image is available.

Expected behavior: ion-img must load images

Steps to reproduce:

Related code:

<ion-content>
    <ion-refresher (ionRefresh)="dataService.refresh($event)">
    <ion-refresher-content
        pullingText="Потяните для обновления"
        refreshingText="Загрузка">
    </ion-refresher-content>
</ion-refresher>
    <ion-list [hidden]="(works|filterWorks:filter.price.mode:filter.price.from:filter.price.to:filter.price.currency_id:filter.location.mode:filter.added.mode:sort.orderBy:commonData).length==0" [virtualScroll]="works|filterWorks:filter.price.mode:filter.price.from:filter.price.to:filter.price.currency_id:filter.location.mode:filter.added.mode:sort.orderBy:commonData" approxItemHeight="80px" >
    <ion-item-sliding *virtualItem="let work">
        <button ion-item (click)="goWork(work)" [ngClass]="{'work-list-item-selected':selectedWorks.works[work.id]}">
            <ion-thumbnail item-left>
                                    <ion-img [src]="work.image|defaultImage"></ion-img>
                            </ion-thumbnail>
                        <h3>{{commonData.authors[work.author_id]?.title}}</h3>
            <h5>{{work.title}}</h5>
            <p class="work-list-price">{{work.price | price : work.price_currency_id : commonData.currencyExchangeRate : true}}</p>
            <p>{{work.year ? work.year+',':''}} {{work.techniques | techniques : commonData.techniques : commonData.mainLanguageId}}</p>
        </button>
        <ion-item-options side="left">
            <button ion-button icon-only color="primary" (click)="selectedWorks.toggle(work)">
                <ion-icon name="{{selectedWorks.works[work.id] ? 'checkmark-circle':'radio-button-off'}}"></ion-icon>
            </button>
        </ion-item-options>
        <ion-item-options side="right">
            <button ion-button icon-left color="primary" (click)="sendWorkByEmail(work)">
                <ion-icon name="mail"></ion-icon>
                Email
            </button>
        </ion-item-options>
    </ion-item-sliding>
</ion-list>
</ion-content>

Other information:

Bug appeared in RC4, in RC3 all was OK.

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

Cordova CLI: 6.3.1 
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.13
Ionic App Lib Version: 2.1.7
Ionic App Scripts Version: 0.0.45
ios-deploy version: Not installed
ios-sim version: Not installed
OS: Linux 4.4
Node Version: v4.2.6
Xcode version: Not installed

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 32
  • Comments: 90 (5 by maintainers)

Most upvoted comments

I also had this issue. The bug is the calculation of the img::top and img::bottom in ion-img. This will be used to set the flag canRequest and canRender in Content::updateImgs for ion-img while scrolling. My first workaround was to extend ion-img for virtual lists.

import {Component, ElementRef, Renderer, Optional} from "@angular/core";
import {Img, Platform, DomController, Content} from "ionic-angular";

@Component({
  selector: 'virtual-ion-img',
  template: '<img>'
})
export class VirtualIonImg extends Img {
  constructor(private __elementRef: ElementRef,
              __renderer: Renderer,
              __plt: Platform,
              @Optional() private __content: Content,
              __dom: DomController) {
    super(__elementRef, __renderer, __plt, __content, __dom);
  }

  get top(){
    this._rect = (<HTMLElement>this.__elementRef.nativeElement).getBoundingClientRect();
    return this._rect.top + this.__content.scrollTop - this.__content._cTop;
  }
  get bottom(){
    this._rect = (<HTMLElement>this.__elementRef.nativeElement).getBoundingClientRect();
    return this._rect.bottom + this.__content.scrollTop - this.__content._cTop;
  }
}

Another option is to fix the calculation in Content::imgsUpdate by override this function in your page.

import {updateImgs} from "ionic-angular/components/content/content";
import {Component, ViewChild} from "@angular/core";
import {Content} from "ionic-angular";

@Component({
  templateUrl: 'virtual-list.html',
})
export class VirtualListPage {
  @ViewChild(Content) _content: Content;
  ngAfterViewInit(){
    if(this._content) {
      this._content.imgsUpdate = () => {
        if (this._content._scroll.initialized && this._content._imgs.length && this._content.isImgsUpdatable()) {
          // reset cached bounds
          this._content._imgs.forEach((img:Img)=>img._rect = null);
          // use global position to calculate if an img is in the viewable area
          updateImgs(this._content._imgs, this._content._cTop * -1, this._content.contentHeight, this._content.directionY, 1400, 400);
        }
      };
    }
  }
}

@alainib

for the first workaround

you have to create a new file e.g. src/components/virtual-ion-img.ts this new component than has to register in src/app/app.module.ts

import {VirtualIonImg} from "../components/virtual-ion-img";
...
@NgModule({
	declarations: [
		//... all other pages and components,
		VirtualIonImg
	],
//... all other stuff e.g.: imports, providers
	entryComponents: [
		//... other pages and components,
		VirtualIonImg
	]
})

Than you can use the tag <virtual-ion-img [src]="url"></virtual-ion-img> in place of <ion-img> like described in http://ionicframework.com/docs/api/components/virtual-scroll/VirtualScroll/#images-within-virtual-scroll

for the second workaround

Just edit the typescript page file which has an virtual scroll inside and add the imports, the ViewChild stuff and the method ngAfterViewInit.

@kabus202 I edited my comment and add the missing import statement. The function updateImgs is defined in the ionic angular content package and has to be imported.

ok,

I added to my broken page: import { Component, ViewChild } from ‘@angular/core’; import { updateImgs } from ‘ionic-angular/components/content/content’; import { Img } from ‘ionic-angular/components/img/img-interface’; import { Content } from ‘ionic-angular’;

/* 2017-08-16 - add this to class body
    start FIX#9660 ion-img doesn't correctly work with virtualScroll
    https://github.com/ionic-team/ionic/issues/9660#issuecomment-304840427
*/
@ViewChild(Content) _content: Content;
ngAfterViewInit() {
    if (this._content) {
        this._content.imgsUpdate = () => {
            if (this._content._scroll.initialized && this._content._imgs.length && this._content.isImgsUpdatable()) {
                // reset cached bounds
                this._content._imgs.forEach((img: Img) => (<any>img)._rect = null);
                // use global position to calculate if an img is in the viewable area
                updateImgs(this._content._imgs, this._content._cTop * -1, this._content.contentHeight, this._content.directionY, 1400, 400);
            }
        };
    }
}
/*
end FIX#9660
*/

and thats it - problem disappear. My broken page:

<ion-content padding> <ion-grid [virtualScroll]="__items" [bufferRatio]="2" approxItemHeight="80px" approxItemWidth="100%" [virtualTrackBy]="ItemComparer"> <div *virtualItem="let item"> <ion-row align-items-center justify-content-center> <ion-col col-auto> <ion-item> <ion-thumbnail item-start> <ion-img [src]="'my-personalized-url?item='+item?.item"></ion-img> </ion-thumbnail> </ion-item> </ion-col> </ion-row> </ion-grid>

The doc says that one should use ion-img for performance reasons, see: https://ionicframework.com/docs/api/components/virtual-scroll/VirtualScroll/

Therefore, going for img instead of ion-img cannot be a permanent solution and I hope that this long standing bug will be fixed soon.

@manucorporat Any progress on this issue, yet?

Still not working in v4 beta.

I don’t know what is the priority for ionic team, but virtualScroll is one of the most important components that real world apps use.

@RafaelKr @fdambrosio I think it’s better not to hope for any fixes on components before v4 is released. Unfortunately for us working with ionic3, we have to deal with buggy components or to fix them by ourselves. Feel free to fix & create PR 😉

Ciao folks, ion-img work fine only if the tag is in the visible content., every List, segment an so on …doesn’t work . My temporary fix:

  1. open node_modules/ ionic-angular/component/img/img.js
  2. change the function ngAferContentInit with:

Img.prototype.ngAfterContentInit = function () { var _this = this; this._img = this._elementRef.nativeElement.firstChild;

    if(!this._img.hasAttribute("src")){


        this._img.src=this._elementRef.nativeElement.getAttribute("src");

    }

    this._unreg = this._platform.addEventListener(this._img, 'load', function () {
        _this._hasLoaded = true;
        _this.update();
    }, { passive: true });
};

I hope in quickly fix by Ionic team:)

@HugoHeneault I haven’t really worked with ion-img at all. I probably should have, but haven’t. I can take a look but I don’t have a reference on what is broken.

@nicolus the entry in the changelog is from a PR I submitted myself that fixes a regression issue in virtual scroll. I understand your frustration, but that PR fixed a particular issue with VS that made it unusable when the underlying data set was getting updated often, it was not a complete rewrite of the component that solved all issues.

I too agree that VS needs a lot more attention but it has two main issues that probably make its maintenance unviable:

  1. Virtual scroll is a hard problem to solve in the first place. Very few frameworks/libraries have solved it successfully and with certain restrictions. Ionic VS tries to solve everything, variable item size, multi column, headers/footers per item, images, resizing etc. The existing implementation has gone through various refactoring cycles fixing bugs here and there many which are unrelated with the component it self (look at point 2 for more info)
  2. Ionic virtual scroll interacts with many ionic components. Ion-img for images, infinite scroll for loading more data, content for scrolling etc. It is also supposed to render both ionic elements ion-item, ion-card etc as well as custom angular elements.

This complexity is too much for a PR to handle and it requires a complete redesign about what virtual scroll does (which means it has to align with ionic team’s goals), how it does it and what interactions with other components it should have.

Moving to ionic v4 I think many of these will change (for one it will probably be able to render only other web components and not angular components inside it) like iron-list of polymer does today so not sure if putting in the effort in fixing the current implementation has any real value for people that will continue using ionic framework after its v4 release in their projects. I too am looking for options out of this rabbit hole as without virtual scroll we cannot compete with native applications in rendering a realistic amount of data.

So the workaround fixes the issue for Ionic 3.8 too. Why not using it @manucorporat @adamdbradley This is still something really bad for any VS use… @masimplo Would you check it? After your awesome work for https://github.com/ionic-team/ionic/pull/12917 you definitively have skills to dive in VS… 🙉

@WangRongda Did you submit a PR that should have been accepted that fixes this?

It’s been six months, why hasn’t it been fixed?

@jgw96 any status update?

We also ran into this issue with our non-virtualScroll grid. We reproduced the issue in a plunker. Seems to work fine in a finite (non-virtualScroll) list. Whenever we add ion-infinite-scroll to the list the ion-images show issues with loading and unloading.

So ‘normal’ lists seem to work just fine. Lists with virtualScroll or infiniteScroll seem to have issues.

@HugoHeneault : It’s open source software that I pay $29 a month through my pro subscription (I mean sure the framework itself is free, but it’s not like they’re a non-profit organization, they give the framework for free on order to make money on subscriptions), so I don’t expect to have to fix it myself for free.

I can understand that it’s a hard issue to fix, that ionic 4 is still beta, that it’s a low priority issue… All those are perfectly valid reasons, but “it’s OSS fix it yourself lol” is not.

it’s no good that it’s not working with Ionic 4

You have to wait for ionic v4.

It would be stupid to believe that it will be fixed in Ionic 4. We will have new bugs, but the team will focus on Ionic 5, then 6, leaving a lot of bugs for each new version. On the side of React, there is a risk of breaking changes in each version, but at least we know what to expect. Very disappointed by Ionic… It’s unworthy to let bugs drag for so long and let users fix them.

+1

@HugoHeneault, @manucorporat, @adamdbradley : I fully agree that this workaround should be merged in Ionic (I’d do a pull request but as I’m not the author of the workaround I don’t feel confortable making it myself), maybe it’s not perfect, but it’s still infinitely better than without the patch.

I think the issue is that the Ionic team don’t realize that virtualscroll is not working. There’s an entry that says “virtual-scroll: flickering issue fixes” in the 3.8 changelog, why would you go and fix some flickering issues for a feature that you know doesn’t work at all ?

@vahidvdn Totally agree with you, I’ll finish my current app using Ionic, but I’ve decided that for my next app I’ll use another framework (React Native probably or Native script). The Ionic team is doing great work, but the framework is having performance issues. In my current app, I ended up with a static list of maximum 50 items with images (due to the virtual scroll bug) and when I press the Back button there is a lag (I simple use popView, the default behaviour). This lag is not present for example when my lists have 15-20 items. Moreover, in iOS when the device is in battery save mode (and the CPU probably is slowing down things) the performance is even worse, almost not usable.

+1

You can still use ng2 lazy loader. There are two or more. I’m using this one https://github.com/tjoskar/ng2-lazyload-image

Ionic is an open source software guys, if you want things to get fixed quickly you can create a patch and submit a PR 👍

@mopi1402 If you are an Angular developer, I suggest Nativescript instead of react-native. Here you can find why Nativescript is better than react.

I had same issue of showing image in <ion-img> inside [virtualScroll] how do i fix them.

try using this way

<ion-img [src]="image.url" [alt]="image.alt">

I hope for a quick fix on this one. Are there any news? Is this investigated by the team?

<ion-content padding> <ion-grid [virtualScroll]="__items" [bufferRatio]="2" approxItemHeight="80px" approxItemWidth="100%" [virtualTrackBy]="ItemComparer"> <div *virtualItem="let item"> <ion-row align-items-center justify-content-center> <ion-col col-auto> <ion-item> <ion-thumbnail item-start> <ion-img [src]="'my-personalized-url?item='+item?.item"></ion-img> </ion-thumbnail> </ion-item> </ion-col> </ion-row> </ion-grid>

@diegomachado1 Are you sure your images are in their right position? Please slow down your network connection, then test again. When some images don’t get loaded, previous images come to their places and conflict with each other.

@dspachos few months ago I also thought oh it’s virtual scroll it must be top priority to make it work like a charm so I chose ionic instead of nativescript, but now it’s sad to hear that it’s still broken and we cant get lag free performance with huge lists of data.

@vahidvdn it’s not the solution but ionic team themselves said it’s best option right now till virtual scroll is fixed 😃

I replaced ion-img with img and it works fine within the virtual scroll use img instead of ion-img

ion-img within a virtual scroll is supposed to load the img in a web worker that’s why it is in the title.

This bug and some more (images not responsive and only 5x5 on chrome/android, images not loading on first start before any scrolling…) broke a production app which heavily relies on showing articles with lazy loaded images. Nice that we get no documentation whatsoever on such changes. Not that this is anything news.

I have exactly the same behavior as @pavimus

After the virtual scroll buffer, image does not appear, css class is “img-unloaded” (see screenshot below)

ionimg

with ionic 2 final. Please, could you communicate on this problem?

Same here. Was this fixed?

@jgw96 I emailed you a sample

Hello all! Thanks for using Ionic! Could someone post a repo that i can use to reproduce this issue?