jQuery Masonry and Ajax Append Items?
Asked Answered
T

13

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 ?

Tasty answered 4/1, 2012 at 4:54 Comment(1)
can you show us the definition of masonry? I mean, the first time you call to masonryAngling
P
24

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

Protect answered 22/5, 2012 at 19:3 Comment(6)
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'); }Karoline
-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.Sterling
'reload' doesn't seem to be a valid method anymore. I think you need to use 'reloadItems' instead.Heaveho
Funny the actual one that works is the one that he said to replace. That is the one that works. masonry.desandro.com/methods.htmlStitching
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.Renzo
console error message: "no such method 'reload' for masonry instance"Barthold
L
43

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 );
        }
    });
});
Legislate answered 4/1, 2012 at 7:26 Comment(7)
thanks for the response! hmm tried that and it still doesn't seem to work. not sure why it doesn't accept a raw html string ?Tasty
Worked for me too! Can't believe this was the problem.Handoff
This method works great. It's out of the docs masonry.desandro.com/methods.htmlStitching
Any idea how this would be done with one was not using jQuery?Charlotte
"masonry function expects a jQuery object as its second parameter and not a raw HTML string" - this was really really helpful.Saran
jQuery("#content").append(el).masonry( 'appended', el, true ).masonry('layout')is working for meBillowy
Worked for me too! amazing.Butta
V
28
var mediaItemContainer = $( '#container' );
mediaItemContainer.masonry( {
    columnWidth:  '210px',
    itemSelector: '.item'
} );
$( mediaItemContainer ).prepend( '<div class="item">foo</div>' );
$( mediaItemContainer ).masonry( 'reloadItems' );
$( mediaItemContainer ).masonry( 'layout' );

Solution

Vinson answered 23/3, 2014 at 18:53 Comment(2)
masonry( 'layout' ) is key! Thanks!Ketubim
this saved me...that masonry( 'layout' ) did itShadoof
P
24

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

Protect answered 22/5, 2012 at 19:3 Comment(6)
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'); }Karoline
-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.Sterling
'reload' doesn't seem to be a valid method anymore. I think you need to use 'reloadItems' instead.Heaveho
Funny the actual one that works is the one that he said to replace. That is the one that works. masonry.desandro.com/methods.htmlStitching
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.Renzo
console error message: "no such method 'reload' for masonry instance"Barthold
B
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.

Boru answered 30/5, 2016 at 8:19 Comment(0)
P
4

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.

Phrenology answered 13/7, 2016 at 7:11 Comment(0)
S
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

Spadix answered 9/3, 2017 at 23:45 Comment(0)
B
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)

Behold answered 21/1, 2016 at 18:42 Comment(0)
I
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' );
Iman answered 26/4, 2016 at 11:17 Comment(0)
N
1

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 );
        }
    });
});
Newcomen answered 30/5, 2017 at 12:21 Comment(0)
C
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);
      }
    }
  });
Compelling answered 1/7, 2013 at 8:46 Comment(0)
E
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.

Episternum answered 16/1, 2014 at 0:56 Comment(0)
E
-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!

Exhilarate answered 21/3, 2015 at 11:13 Comment(1)
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.Passmore
B
-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.

Back answered 12/3, 2015 at 18:22 Comment(1)
This is the worst idea you could have using Masonry. It may and will lead to performance issues.Bjork

© 2022 - 2024 — McMap. All rights reserved.