0

I have a problem with Masonry plugin.

I try to load new content inside of a div container #myparts.

Ajax works but div containers .part overlapping each other and I dont know why.

I have tried many solutions from the Internet but they don't work. Masonry should reload .parts again after AJAX but it doesn't work.

Here is my Code:

<body>
<!--

 data-user: is user-ID
 data-article: is article-ID

-->

<div id="wrapper">
<div id="myparts" data-user="1">
    <div class="part" data-article="1"></div>
    <div class="part" data-article="2"></div>
    <div class="part" data-article="3"></div>
    <div class="part" data-article="4"></div>
</div>
<div id="button"></div>
</div>
</body>

My jQuery code:

 // My Ajax
 $(document).on("click", "#wrapper > #button", function () {

 var $grid = $("#wrapper > #myparts").masonry({columnWidth: 22, itemSelector: '.part', isFitWidth: true}); // Masonry plugin

 var user_d = $("#wrapper > #myparts").data("bid");
 var article_id = $("#wrapper > #myparts > .part").last().data("article");

 $("#pleasewait").fadeIn(); // open progressbar.

 $.ajax({
  url: "ajax/new-content.php",
  method: "POST",
  data: {user: user_d, article: article_id},
  dataType: "html",
  cache: false,
  success: function (data) {
  if (data !== '') {
   $("#wrapper > #myparts").append(data); // Ajax work.
  } else {
    $("#wrapper > #myparts > #button").remove(); // Remove button if no more content in database
  $grid.masonry();
  }
 },
 complete: function () {
  $("#pleasewait").fadeOut(500); // close progressbar.
 }
 });
 });
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Juergen
  • 65
  • 7
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – CBroe Mar 29 '17 at 13:42
  • You are calling masonry before your _asynchronous_ AJAX request has finished. You need to call it inside the success callback function. – CBroe Mar 29 '17 at 13:43
  • Thank you, your solution is work but if i push the button just once. If i push it again it do not work. Have you an idea why? – Juergen Mar 29 '17 at 13:50
  • FireBug give this message: ReferenceError: reinitializeMasonry is not defined – Juergen Mar 29 '17 at 13:51
  • Use instead `var $grid = $("#wrapper > #myparts").masonry({columnWidth: 22, itemSelector: '.part', isFitWidth: true});` then just `$grid.masonry();`, isn't necessary to reinitialize with the options everytime. – Sebastián Palma Mar 29 '17 at 14:01
  • still not work :-( – Juergen Mar 29 '17 at 14:08
  • @Juergen check this [gist](https://gist.github.com/vnhnhm/190d6cfc79b1d79d7dafd6ce50fd393d) to get an idea. – Sebastián Palma Mar 29 '17 at 14:11
  • Thank you! But it not work. – Juergen Mar 29 '17 at 15:35
  • Have you checked that the bid data attribute isn't present in the `myparts` div?, you're getting `undefined` with `var user_d = $("#wrapper > #myparts").data("bid");`, it should be `.data("user");`. – Sebastián Palma Mar 29 '17 at 15:37

1 Answers1

0

Try initializing your masonry outside your button click function, this way it doesn't depend on that (unless is what you want to ).

And look for your user_d variable, who's supposed to be getting the data attribute from the #wrapper > #myparts element, but you're passing it the bid data attribute.

See this version using your code:

<div id="wrapper">
    <div id="myparts" data-user="1">
        <div class="part" data-article="1">
          <img src="https://loremflickr.com/320/240" alt="">
        </div>
        <div class="part" data-article="2">
          <img src="https://loremflickr.com/320/240" alt="">
        </div>
        <div class="part" data-article="3">
          <img src="https://loremflickr.com/320/240" alt="">
        </div>
        <div class="part" data-article="4">
          <img src="https://loremflickr.com/320/240" alt="">
        </div>
    </div>
    <div id="button" style="margin-top: 250px; border: 1px solid black; width: 150px;">I'm a button</div>
  </div>

I suppose you have certain elements inside every part div (the button is just styled to be down the content).

<script>
    var $grid = $("#wrapper > #myparts").masonry({
      columnWidth: 320,
      itemSelector: '.part',
      isFitWidth: true
    }); // Masonry plugin

    $('#button').click(function () {
      let user_d = $("#wrapper > #myparts").data("user"),
          article_id = $("#wrapper > #myparts > .part").last().data("article");

      $("#pleasewait").fadeIn(); // open progressbar.

      $.ajax({
        url: "ajax/new-content.php",
        method: "POST",
        data: {
          user: user_d,
          article: article_id
        },
        dataType: "html",
        cache: false,
        success: function (data) {
          if (data !== '') {
            console.log(data);
            let $items = $(data);
            $grid.append( $items ).masonry( 'appended', $items );
          } else {
            // Remove button if no more content in database
            $("#wrapper > #myparts > #button").remove();
            $grid.masonry();
          }
        },
        complete: function () {
          $("#pleasewait").fadeOut(500); // close progressbar.
        }
      });
    });
  </script>

In your script, initialize your grid masonry outside your click event, then make the AJAX request, passing the properly data:

 let user_d = $("#wrapper > #myparts").data("user"),
      article_id = $("#wrapper > #myparts > .part").last().data("article");

Then in your success callback do the append of the items, "converting" every of them to its jQuery version, this is:

if (data !== '') {
  console.log(data);
  let $items = $(data);
  $grid.append( $items ).masonry( 'appended', $items );
}
...

My ajax/new-content.php file just checks if the data was sent, and return the div, to be appended:

<?php

if (isset($_POST['user']) && isset($_POST['article'])) {
  echo '<div class="part" data-article="5"><img src="http://loremflickr.com/320/240" alt=""></div>';
}

Here's a demo pen in Codepen.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59