Masonry in Ionic

Hello all,

I was wondering if there were a way to do masonry with cards in ionic2. I found an Angular2 library called angular2-masonry but I can’t get it to work.

If it’s possible to do so. Please give me a hint.

Thanks.

1 Like

looking for the same…

Hey there, I’m coming around with a solution, which works for me

  1. install masonry lib from http://masonry.desandro.com/ by running npm / bower
    npm install masonry-layout

  2. Include masonry.pkgd.min.js to your index.html because there is no d.ts available atm

  3. Inititialze masonry by calling

    declare var Masonry: any; //outer scope

    ionViewDidEnter() {
    setTimeout(() => {
    var elem = document.querySelector(’.grid’);
    var msnry = new Masonry(elem, {
    // options
    itemSelector: ‘.grid-item’,
    fitWidth: true
    });
    }, 100);
    }

  4. Be patient to run the code after dom elements are displayed, eg ionViewDidEnter, to be save, surround it by timeouthandler

  5. add grid-selectors to your template/list-template:

    <div class="grid">
     		<ion-card class="grid-item" *ngFor="let item of feed$ | async">
     			<img src="yourimageteaserurl.jpg">
     			<ion-card-content>
     				<ion-item>
     					<ion-avatar item-left>
     						<img src="yourimageurl.jpg">
     					</ion-avatar>
     					<ion-card-title>
     						{{item?.title}}
     					</ion-card-title>
     				</ion-item>
     			</ion-card-content>
     		</ion-card>
     	</div>
    
  6. add css-styles

    .grid {
    margin: 0 auto;
    }

     .grid-item { width: 170px;margin:5px; }
     .grid-item--width2 { width: 400px; ;margin-bottom:2px;}
    

For any further help, look at mansonry documentation.

1 Like

Hi @mica. Good guide. Where/what file are you declaring this?

declare var Masonry: any; //outer scope

Thanks!

I’ve used packery extensively for a v1 project (packery is similar to masonry and offers drag and drop/resize and is by the same genius author).

In general I’ve found using timeouts and the magic 100-300 ms timeouts to be a hit and miss, with it heavily dependent on the speed of the device.

It gets worse if the images are dynamic. I finally had to litter my code with all sorts of timeouts, sometimes in succession to get it right - no science involved, purely based on what works.

I thought it would be easier in v2, but I faced exactly the same issues - packery and angular just don’t seem to play well when it comes to detecting DOM changes. Its possible I know too little about this subject, but I never got it right.

My app runs on desktops, iOS and Android devices - and I’ve always found inconsistencies.

If someone has done extensive testing using either packery or masonry on multiple devices (including the old slow ones, running android 4.4) , I’d love for them to share their approach. I’ve linked to mine above.

Unfortunately, this seems to be the only library that offers all of:

  1. bin-packing
  2. drag and drop
  3. resize

I’ve played with ngDragula too for a v2 port. It works better with Angular but doesn’t seem to have bin packing.

Hi @pliablepixels

Can you share the code to instantiate the Packery?

I am struggling with it in home.ts (tab starter template)

Regards

Tom

Sure. And for what it’s worth, its working absolutely super in v2 so far. search for packery and pckry. I am also using imagesLoaded to trigger packery layout.

1 Like

Hi

thank you for that!

I am surprised to see you need Draggabilly to drag the stuff around. I would say Packery does it already (as per demo). Anyway, will try it in my code. Meanwhile I managed to get it to work - but no dragging, with a bit different declaration style (will post the repo later).

Small comment on the code: why aren’t you using fat-arrow in this part? I would expect scope issues to come out of it.
(line 249, https://github.com/pliablepixels/nvrNinja-ng/blob/master/src/pages/montage/montage.ts)

imagesLoaded(elem, function () {
       // all images loaded
        instance.utils.debug("images loaded done, instantiating packery");
        instance.packery = new Packery(elem, {
          // options
          itemSelector: '.grid-item',
          percentPosition: true,  
        });

Regards,

Tom

Packery does not provide drag and drop. That is what draggabilly does.
With respect to fat arrow, yes I should. The reason I don’t face a scope issue is I am capturing this in instance before (which is not necessary if I use fat arrow).

1 Like

Actually, I just remembered - my imagesLoaded is inside a timeout. So fat arrow was not working as it was 2 levels of depth, which is why I resorted to saving instance (which I need even if I convert to fat arrow). Just tried.

Ok. I will try the dragabilly and if I get it to work, post the results here

1 Like

Sounds good. And if you do use imagesLoaded and get it to work well with fat arrows inside a timeout please do post that as well. I’m not an expert coder and just do what I can get to work, so always looking for better ways!

Hi

this is how I did it. No imagesLoaded/interval needed? I used the (load) event on IMG.

Working in Ionic View. Public app ID 82a329bb (tab Contacts).

Regards

Tom

Thank you for the code. The problem I had, and the genesis of the timeout were the following:

a) Since packery doesn’t have a concept of Angular zones, changes it made were often missed out by Angular (in other words, not reflected). This was especially pronounced when you did a re-org of the packery grid from within packery (say move or resize)

b) A view whilst sliding in (normal ionic transition) caused problems with packery which would conclude it got a reference to the grid when in fact the grid was not yet fully in view, causing layout problems.

I suppose @ViewChild might be a good solution to b) - I’ll have to try it out, but did you see problems with a) at all ? This part, particularly was my bane

@pliablepixels Hi and welcome in the Ionic community. This discussion is interesting, however it seems to forget Ionic is built around strict CSS guidelines (Material / Apple) to build both things at the same time. Personally I love Masonry idea, but using it on top of any Ionic app will risk to have very strange results… I prefer crafting SCSS for both kind of devices, smartphones and tablets in my app, because of a better control to what happens inside later.

Hope it helps,

Francois

Hello!. Thanks for the welcome. It’s been a fun ride for the past year an half in this forum. Not sure what SCSS has to do with this. We are talking about bin packing images that packery does very well. If you mean recreating what masonry or packery does with pure flexbox styling its a huge amount of work. Both packery and masonry work very well across multiple devices and form factors. The issues being discussed here deal with DOM operations out of Angular zones which is a common issue for any 3rd party non angular (nothing to do with ionic styling) JS library that touches the DOM.

@pliablepixels It’s more or less what I mean yes, recreating masonry for Ionic, which involves a ton of work like you said rightly. For your second question, touching out 3rd party libraries out of Ionic, for me humbly (I’m a front dev too, not too bad), this is a non-subject because of 2 reasons:

  1. nothings prevents you to incorporate custom libs inside your project, it’s free
  2. the outcome of customizing for instance flexbox or masonry inside a ionic project, is enough to put a good / decent front end developer on the topic for a week, for instance. Me, don’t have time to do that.

Hope it helps,

I eventually settled some a pure masonry layout, with media queries to increase the number of columns as you move from mobile to tablet sizes.

Tutorial : https://audacitus.com/site/2018/01/27/creating-a-responsive-pintrest-layout-for-mobile-tablets-using-gemionic-ui-freebie-included/