4

What I want to do is to display a placeholder image before the real image fully loaded. And I found the answer here. I am using exactly the same code as the accepted answer. This answer works pretty good for normal situation.

However, my case is a little bit different. On my page, I have two tabs. I'm using ion-slide-box for the tab selection. And I load different content when user switch the tabs. Under each tab, it's a long list of items. Each item has a image, on which I implement this placeholder image display method. User is able to scroll down to see more items. So when user scroll down, I'll load more items.

Here is a peek of my code, it's simplified:

HTML:

<div class="tab-bar">
<div class="tab-option" ng-class="(slide == 0 ? 'active' : '') ng-click="setSlide(0)">
    Tab 1
</div>
<div class="tab-option" ng-class="(slide == 1 ? 'active' : '') ng-click="setSlide(1)">
    Tab 2
</div>

<ion-view>
<ion-content>
    <div class="list">
        <ion-slide-box on-slide-changed="slideHasChanged($index)" active-slide="slide">
            <ion-slide>
                <ion-list ng-repeat="item in items">
                    My content and Image Here
                    <img hires="{{item.realImageUrl}}" src="placeholderImage.jpg"/>
                </ion-list>
            </ion-slide>
            <ion-slide>
                <ion-list ng-repeat="item in items">
                    My content and Image Here
                    <img hires="{{item.realImageUrl}}" src="placeholderImage.jpg"/>
                </ion-list>
            </ion-slide>
        </ion-slide-box>
    </div>
</ion-content>

In my controller(this is simplified a lot, I don't want to bother with un-related code):

slideHasChanged = function (index) {
    getMoreItems(); //get more data from server here.
};

This is the directive:

app.directive('hires', function() {
    return {
        restrict: 'A',
        scope: { hires: '@' },
        link: function(scope, element, attrs) {
            console.log('link fired');
            element.one('load', function() {
                console.log('load fired');
                element.attr('src', scope.hires);
            });
        }
     };
});

The issue is, the placeholder image works good for the first time I come to this page and load the first batch of items. But whenever I need to scroll down, or switch tab, the placeholder image doesn't work anymore. The behavior is that, it's always showing placeholder image, the real image is not displayed after it's fully downloaded/loaded.

I wonder is it because this method only works when you load a page? And doesn't work because switching tab or scrolling down doesn't trigger page loading? If I want this to work for my situation, what change is needed on this method?

I put two debugging messages in my directives, I log out 'link fired' and 'load fired'. Turns out that the link function is fired correctly, it's just the element.one('load', function()) is not fired. Is it that the scope somehow doesn't match? Any thoughts?

I've been trying the code a lot. And actually sometimes it works, when I switch tab or scroll down. But most time doesn't work. This is confusing, I don't know why it works sometimes.

Community
  • 1
  • 1
Carrie
  • 480
  • 3
  • 10
  • 25
  • You'll get a lot more help if you post the relevant code and HTML. – Mike Feltman May 11 '16 at 19:58
  • @MikeFeltman I just updated my question, added some code. – Carrie May 11 '16 at 20:16
  • I think the curly braces around item.realImageUrl are unnecessary. That may not be related to the issue at all, but I'd try removing them just to check. Did you create the directive as well? – Mike Feltman May 11 '16 at 20:22
  • @MikeFeltman yes I created the directive. It's exactly the same as the answer in the link in my question. curly braces is the way to bind data in angular and can't be removed. – Carrie May 11 '16 at 20:23
  • 1
    `element.one('load'` i guess you don't have the same typo in your true code but i prefer to be sure -> `element.on('load'` – Walfrat May 12 '16 at 15:14
  • @Walfrat No it's not a typo, it is `one`, otherwise it'll keep triggering the code. – Carrie May 12 '16 at 15:15
  • Ah ok, didn't know about that, did you inspect the HTML for the src value ? WHen the thab is hidden, when it's displayed after tab click to see what is happening ? – Walfrat May 12 '16 at 15:16
  • @Walfrat I inspected it. The src is still placeholder image. but hires is the real image url. It's just not substituted. Means somehow the directive is not fired, I don't know why. – Carrie May 12 '16 at 15:26

3 Answers3

0

I think you are on the right track and have to probably try to tie into when the item actually becomes visible. There's a directive for this called InView available here: https://github.com/thenikso/angular-inview. I have a somewhat similar issue that I have this bookmarked for, but it's pretty far down my to-do list.

Mike Feltman
  • 5,160
  • 1
  • 17
  • 38
  • I'm new to angular. The github project you provided has too many unrelated information and it's hard for me to extract useful information. If you can provide the solution for my case based on the reference it would be great. – Carrie May 11 '16 at 21:10
0

Try this for your directive:

app.directive('hires', function() {
return function(scope, element, attrs) {
        attrs.$observe('hires', function(value) {
        element.attr({
            'src': value
        });
    });      
  };
});

Using the $observe here acts much like the ng-src would.

LesterMac
  • 346
  • 1
  • 6
0

So I finally got the right way to do it, just change the link function of directive to this:

link: function (scope, element, attrs) {
    if (scope.hires != element.attr('src')) {
        element.attr('src', scope.hires);
    }
}

Get rid of element.one. That's the reason it only works once.

Carrie
  • 480
  • 3
  • 10
  • 25