Shailu4u / ng-masonry-grid

Angular 6+ masonry grid with CSS 3 animations on scroll.
50 stars 15 forks source link

Images stacked over each other when fetched with a promise #16

Open MariusStuparu opened 6 years ago

MariusStuparu commented 6 years ago

Hello,

I am fetching my images data with a get promise in Angular 6, like this:

this.getModule.gallery( this.id )
        .then( ( gallery: Gallery ) => {
          this.gallery = gallery;
        } );

And in the template:

<ng-masonry-grid [masonryOptions]="gridOptions"
                       [useAnimation]="false"
                       class="imagesGrid"
                       *ngIf="gallery.images">
        <ng-masonry-grid-item *ngFor="let image of gallery.images; let i = index;"
                              id="{{'masonry-item-'+i}}"
                              class="photo gridItem">
          <a (click)="lightbox(image)"><img [src]="image.large" [alt]="image.title" /></a>
</ng-masonry-grid-item>

But on first load (I'm guessing before cache is created) the layout is messed up, all rows ar stacked on top of eachother. For example, first row has:

{
margin-bottom: 10px;
position: absolute;
left: 0px;
top: 0px;
}

Row 2:

{
margin-bottom: 10px;
position: absolute;
left: 0px;
top: 10px;
}

Row 3:

{
margin-bottom: 10px;
position: absolute;
left: 0px;
top: 20px;
}

After refresh, the second row item gets this css:

{
margin-bottom: 10px;
position: absolute;
left: 0px;
top: 210.25px;
}
zbayoff commented 6 years ago

You can use the useImagesLoaded property in the ng-masonry-grid template like so: <ng-masonry-grid [useImagesLoaded]="true" >

This property will allow the grid to resize and calculate each feed-item height after the images have loaded. What's happening is your images aren't fully loaded when your grid-items are rendered and thus, the heights are not correct and so they overlap.

jepperaskdk commented 4 years ago

I'm seeing something similar. The initial load works fine - images appear with effect, but if I fetch e.g. 20-30 more elements and append, they will first stack in top-left before being positioned, creating a flickering effect.

My fix is to set visibility: hidden; on the ng-masonry-grid-item and then use layoutComplete to manually set the visibility. Like this:

<ng-masonry-grid (layoutComplete)="layoutComplete($event)" (onNgMasonryInit)="onNgMasonryInit($event)" [masonryOptions]="{ transitionDuration: '1.0s', gutter: 20, animationEffect: 'effect-4' }"  [useImagesLoaded]="true">
    <ng-masonry-grid-item id="{{'masonry-item-'+i}}" *ngFor="let post of posts; let i = index;" style="visibility: hidden;">
    </ng-masonry-grid-item>
</ng-masonry-grid>
layoutComplete($event: MasonryGridItem[]) {
    $event.forEach((item: MasonryGridItem) => {
        item.element.style.visibility = "visible";
    });
}