31

I am trying to use some ajax and the jQuery Masonry plugin to add some items - but for some reason the new items aren't getting the masonry applied ?

I'm using

jQuery.ajax({
    type: "POST",
    url: ajax_url,
    data: ajax_data,
    cache: false,
    success: function (html) {
        if (html.length > 0) {
            jQuery("#content").append(html).masonry( 'appended', html, true );
        }
    });
});

However the items that are appended subsequently don't have the class="masonry-brick" applied which means that they stuff up completely the positioning ?

Andy
  • 15,873
  • 12
  • 40
  • 52

13 Answers13

42

It appears that the masonry function expects a jQuery object as its second parameter and not a raw HTML string. You should be able to fix this by wrapping the success callback parameter like so:

jQuery.ajax({
    type: "POST",
    url: ajax_url,
    data: ajax_data,
    cache: false,
    success: function (html) {
        if (html.length > 0) {
            var el = jQuery(html);
            jQuery("#content").append(el).masonry( 'appended', el, true );
        }
    });
});
ryanlahue
  • 1,141
  • 1
  • 6
  • 6
27
var mediaItemContainer = $( '#container' );
mediaItemContainer.masonry( {
    columnWidth:  '210px',
    itemSelector: '.item'
} );
$( mediaItemContainer ).prepend( '<div class="item">foo</div>' );
$( mediaItemContainer ).masonry( 'reloadItems' );
$( mediaItemContainer ).masonry( 'layout' );

Solution

subone
  • 293
  • 3
  • 4
23

Had a similar problem and instead used the following line (converted for your code). Sorry, I don't recall where I found it.

In your code replace this:

jQuery("#content").append(el).masonry( 'appended', el, true );

With this:

jQuery("#content").append(el).masonry( 'reload' );

http://masonry.desandro.com/methods.html

Rajasekhar
  • 509
  • 1
  • 4
  • 14
frankp
  • 319
  • 2
  • 4
  • 2
    Works for me too, looks like you can't reapply masonry, you have to call reload instead. I used this: `if(!$('#results').hasClass('masonry')) { $('#results').masonry({ itemSelector: '.product' }); } else { $('#results').masonry('reload'); }` – Kris Aug 14 '12 at 11:40
  • 14
    -1 `reload` masonary is not really a solution but only a workaround. Which can have huge performance overheads. Imagine trying to add one more image to a masonary gird of more than 200 images and reloading the whole grid. – PUG Sep 11 '12 at 23:05
  • This was really usefull. Thank you. – Ionut Hulub Apr 19 '13 at 23:38
  • 'reload' doesn't seem to be a valid method anymore. I think you need to use 'reloadItems' instead. – Mike Garcia Jul 31 '13 at 07:00
  • Funny the actual one that works is the one that he said to replace. That is the one that works. http://masonry.desandro.com/methods.html – Panama Jack Jan 28 '14 at 06:00
  • If you have more than 60 image items to be loaded you should NOT use "reload". Use "appended" instead since it computes the layout only for newly loaded items. If appended is not working for you, you need to check your CSS/JS. – ksiomelo Feb 18 '14 at 10:14
  • console error message: "no such method 'reload' for masonry instance" – Cichy Jan 26 '15 at 18:39
5
success: function (response) {
  if(response.length > 0) {
     var el = js(response); 
     setTimeout(function () {
       js("#masonry").append(el).masonry( 'appended', el).masonry('layout');
     }, 500);
  }
}   

works fine for me.

kdgilang
  • 333
  • 4
  • 6
3

Following has worked for me. I have an ajax which returns set of html items (returns a partial view, from the ajax) when I click a load more button in my web page. Below is the partial view, which is dynamically generated.

foreach (var item in Model.SocialFeedList)
{
        <div class="grid-item">
            <div class="grid-inner">
                <div class="img-holder" style="background-image:url(imageURLHere)">
                </div>
                <div class="content-area">
                    <h3><a target="_blank" href="SomeLink">TitleOfTheLink</a></h3>
                    <p>SomeDescription</p>
                    <h5 class="date"><span>Published</span>: 2016/07/13</h5>
                </div>
            </div>
        </div>
}

In the success callback ajax method, I have done the below,where "response" is the set of html items I get from the above html. Where "divFeedList" is the root element where I show the set of html elements.

jQuery("divFeedList").append(response).masonry('reloadItems', response, true).masonry();

Please let me know if the answer is unclear.

cham
  • 609
  • 3
  • 9
  • 19
3

I added the following code after the append command and everything was fine:

$grid.imagesLoaded().progress( function() {
    $grid.masonry('layout');
});

The reason:

Unloaded images can throw off Masonry layouts and cause item elements to overlap. imagesLoaded resolves this issue. imagesLoaded is a separate script you can download at imagesloaded.desandro.com.

source

Chris Kon
  • 96
  • 7
1

You are missing Masonry layout call. According to the docs you need to refresh the layout, executing .masonry() after every change (for instance .masonry('appended')):

$grid.masonry()
  .append(elem)
  .masonry('appended', elem)
  // layout
  .masonry();

(source: http://masonry.desandro.com/methods.html)

poxip
  • 873
  • 8
  • 25
1

I had the same problem with my ajax listing, i could solve it by calling reloadItems & layouts functions after ajax respond :

var mediaItemContainer = $( '#container' );
mediaItemContainer.masonry( {
    columnWidth:  '210px',
    itemSelector: '.item'
} );
$( mediaItemContainer ).prepend( '<div class="item">foo</div>' );
$( mediaItemContainer ).masonry( 'reloadItems' );
$( mediaItemContainer ).masonry( 'layout' );
0

This solution works for me:-

  jQuery.ajax({
    type: "POST",
    url: ajax_url,
    data: ajax_data,
    dataType: 'json',
    cache: false,
    success: function(response) {
      if (response.length > 0) {
        var $container = $('#container');
        var msnry = $container.data('masonry');
        var elems = [];
        var fragment = document.createDocumentFragment();
        for (var x in response) {
          var elem = $(response[x]).get(0);
          fragment.appendChild(elem);
          elems.push(elem);
        }
        $container.appendChild(fragment);
        msnry.appended(elems);
      }
    }
  });
Mudaser Ali
  • 3,331
  • 2
  • 21
  • 21
0

Just for future people who find this issue and the above solutions don't work for them: I found an issue with my selector and the element I added not having the same case, i.e. itemSelector was .Card but I was appending <div class="card">.

Hope this helps.

Sam
  • 4,024
  • 6
  • 45
  • 74
0

it is clearly explained here https://masonry.desandro.com/methods.html#prepended

jQuery.ajax({
    type: "POST",
    url: ajax_url,
    data: ajax_data,
    cache: false,
    success: function (html) {
        if (html.length > 0) {
            jQuery("#content").append(html).masonry( 'appended', html, true );
        }
    });
});

in your success function, you need your response "html" to be wrapped in a jquery object and then append using html() or append().

var $content = $( html );
jQuery("#content").append($content).masonry( 'appended', $content );

the final code should be

jQuery.ajax({
    type: "POST",
    url: ajax_url,
    data: ajax_data,
    cache: false,
    success: function (html) {
        if (html.length > 0) {
            var $content = $( html );
            jQuery("#content").append($content).masonry( 'appended', $content );
        }
    });
});
Aamer Shahzad
  • 1,839
  • 1
  • 19
  • 22
-1

For Masonry v3.2.2 (latest at the time of this post), this is what works:

Assuming newHtml is a string like this:

<li>item 1</li><!--split-->
<li>item 2</li><!--split-->
<li>item 3</li>

You process it like this:

$.get(apiUrl, function(newHtml) {
    var textArr = newHtml.split("<!--split-->");
    var elArr = [];
    $.each(textArr, function(i,v) {
        if (v) {
            elArr.push($(v)[0]);
        }
    });
    $(this).append(elArr);
    $container.waitForImages( function() {
        $container.masonry('appended', elArr);
    });
}

Took me 2 hours to find out this!

Tacaza
  • 469
  • 1
  • 4
  • 12
  • This is a really bad answer/example because of the extra unrelated stuff around it, furthermore it doesn't even do anything different to what the OP wrote except use `waitForImages` - which you don't even mention is an external library. – Sam P Jan 19 '16 at 15:15
-2

I found a solution that works fine for me. it reloads every half second the layout of an instance of masonry.

//initialization of a masonry object:

var msnry = new Masonry("#container",{
itemSelector: '#post',
gutter: 15
}); 

//thread that makes the magic happens:

setInterval(function(){
msnry.reloadItems();
msnry.layout();
},500);

this way, you can append things using ajax, and voilá, there is the masonry layout.

  • 1
    This is the worst idea you could have using Masonry. It may and will lead to performance issues. – zessx Dec 11 '15 at 08:22