0

I have a blog which advertises x3 articles randomly at the bottom of each post. Sometimes, this feature fails to display all 3 (1 missing).

I can't see where the problem lies.

JQuery

$.get("https://www.citychurchchristchurch.co.nz/blog.php", function(data) {
    var $quotes = $(data).find(".container-articles-5"),
      count = $quotes.length,
      $random = function() {
        return $quotes.eq(Math.floor(Math.random() * count));
      };
    $(".blog-ad-1").append($random);
});

HTML (where ads are displayed)

<aside class="blog-ad-4">
    <div class="blog-ad-5">
      <div class="blog-ad-3">
        <div class="blog-ad-1"></div>
      </div>
      <div class="blog-ad-3">
        <div class="blog-ad-1"></div>
      </div>
      <div class="blog-ad-3">
        <div class="blog-ad-1"></div>
      </div>
    </div>
</aside>

All 3 ads should display. View live demo here (near the bottom): https://www.citychurchchristchurch.co.nz/blog/eo-cycling-20181030

Bainn
  • 85
  • 8
  • if you try to `console.log(count = $quotes.length)` it will sometimes return 2 elements and sometimes return 3 elements .. so the problem is not in your code which you provided .. the problem with the returned `data` from the php page .. which you're not provide – Mohamed-Yousef Feb 01 '19 at 01:33
  • Also .. If you get your data from database .. Then you can use `ORDER BY RAND() LIMIT 3` in query then use append directly in javascript .. you can take a look at [query to display four random data from database](https://stackoverflow.com/questions/13643640/query-to-display-four-random-data-from-database) – Mohamed-Yousef Feb 01 '19 at 01:45

3 Answers3

1

It's just a guess but I would try the following:

$.get("https://www.citychurchchristchurch.co.nz/blog.php", function(data) {
  var $quotes = $(data).find(".container-articles-5"),
  count = $quotes.length,
  $random = function() {
    var articleNumber = Math.floor(Math.random() * count);
    console.log(articleNumber);
    return $quotes.eq(articleNumber);
  }
  $(".blog-ad-1").append($random);
});

This way you can check if displaying the ad fails always on the same generated articleNumber (e.g. 0).

KHansen
  • 784
  • 5
  • 21
  • Thank you @KHansen for your response. I gave this a try, but it didn't work. I'm not fluent enough to solve myself. Thank you for taking the time to submit your response. – Bainn Feb 01 '19 at 02:36
1

The problem is that Math.floor(Math.random() * count) can return the same value on two different calls -- there's nothing that ensures that they're unique. But a DOM element can only be in one place at a time, so if you append the same quote twice, it will only appear in the second place.

You could clone the DIV before appending it, but then you'll see duplicate quotes.

A better solution would be to shuffle $quotes randomly and then append them in order.

$.get("https://www.citychurchchristchurch.co.nz/blog.php", function(data) {
    var $quotes = $(data).find(".container-articles-5").get(),
      count = $quotes.length,
      $random = function(i) {
        return $quotes.eq(i));
      };
    shuffle($quotes);
    $(".blog-ad-1").append($random);
});

See How to randomize (shuffle) a JavaScript array? for how to implement the shuffle() function.

Notice that I used .get() to convert the jQuery collection to a JavaScript array of elements, since the code in that question is designed to work with an array.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thank you for the detailed answer. I gave it a try, but couldn't quite get it to work. I feel it was 99.9% there (fault on my behalf). Thank you for taking the time. – Bainn Feb 01 '19 at 02:35
  • This is almost the same as the answer you accepted. I wonder why his works and mine doesn't. – Barmar Feb 01 '19 at 02:52
1

I would do a shuffle on the quote elements and generate unique ordering indices to ensure all elements are always consistently appended.

Because when you do:

var count = 3;
var $random = function() {
  return $quotes.eq(Math.floor(Math.random() * count));
};

$(".blog-ad-1").append($random);

You're essentially doing the following for as many times as there are elements of .blog-ad-1 (presumably 3). And Math.random() won't always give you all 3 indices as expected:

var count = 3;

$(".blog-ad-1").append(function() {
    $quotes.eq(Math.floor(Math.random() * count));
});

So you could end up with:

index = Math.floor(Math.random() * 3); // 0
index = Math.floor(Math.random() * 3); // 1
index = Math.floor(Math.random() * 3); // 0

With the last randomization returning another zero (instead of 2), combined with a jQuery.append(), what that actually does is it removes the first element (indexed 0) and appends it to current container; hence the missing element.

Possible solution:

function shuffle(items) {
  for (var i = items.length - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    var temp = items[i];

    items[i] = items[j];
    items[j] = temp;
  }

  return items;
}

$.get("https://www.citychurchchristchurch.co.nz/blog.php", function(data) {
  var $quotes = $(data).find(".container-articles-5");
  var $adContainers = $(".blog-ad-1");

  shuffle($quotes).each(function (index) {
    $adContainers.eq(index).append(this);
  });
});
Yom T.
  • 8,760
  • 2
  • 32
  • 49