Laravel JSON / Intermittent head scratch

Soldato
Joined
13 Jun 2009
Posts
4,233
Location
My own head
Converting website over to Laravel, and have a weird error that is driving me mad.

Got a controller, firing out reviews (randomised to page). This should be producing JSON as standard in laravel which it is, however this javascript intermittently fails!

PHP:
	<script type="text/javascript">
	jQuery.ajax({
    url: 'review/random/3',
    dataType: 'json',
	method: 'GET',
    success: function(data){reviews_data(data)}
});

function reviews_data(data)
{
    reviews = data;
	console.log (reviews);
	reviews.forEach (function(review) {
		document.getElementById("reviews").innerHTML+= '<div class="col-sm-4 portfolio-item" id="review">	<div class="review" data-stars="1,2,3,4,5">	<p class="reviewContent">' + review.reviewtext + '</p>	<p class="reviewName">' + review.name + '</p>	<div class="rating-score">	<div class="rating-5">' + review.reviewrating + '</div>	</div>	</div>	</div>';		
	});
};
</script>

The error is reviews.forEach is not a function

I've looked at the JSON and it's intermittently not providing indexes? Maybe 1/10 it'll produce a working JSON that won't crash the JS code.

Working JSON (from Chrome Console via a console.log)
PHP:
Object {1: Object, 2: Object, 3: Object}
1: Object
created_at: "2015-12-24 15:59:42"
id: 2
name: "Review two"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 3
reviewtext: "This is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
2: Object
created_at: "2015-12-24 15:59:42"
id: 4
name: "Review four"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 3
reviewtext: "This is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
3: Object
created_at: "2015-12-24 15:59:42"
id: 5
name: "Review Five"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 5
reviewtext: "This is some text for the reviewThis is some text for the reviewThis is some text for the reviewThis is some text for the reviewThis is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
__proto__: Object

Failing JSON feed

PHP:
[Object, Object, Object]
0: Object
created_at: "2015-12-24 15:59:42"
id: 1
name: "Review one"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 5
reviewtext: "This is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
1: Object
created_at: "2015-12-24 15:59:42"
id: 2
name: "Review two"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 3
reviewtext: "This is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
2: Object
created_at: "2015-12-24 15:59:42"
id: 4
name: "Review four"
published: 1
published_at: "0000-00-00 00:00:00"
reviewrating: 3
reviewtext: "This is some text for the review"
updated_at: "2015-12-24 15:59:42"
__proto__: Object
length: 3
__proto__: Array[0]

Cookies and kudos if you can crack the puzzle!
 
Soldato
OP
Joined
13 Jun 2009
Posts
4,233
Location
My own head
Rather than relying on the prototypical method forEach why don't you use an indexed for loop?
PHP:
for(var i = 0; i < reviews.length; i ++) {
// do something
}

Also if you're already using jQuery you may as well use its helper methods, eg. $.each for looping through arrays and for adding markup use $.('#reviews').append(html)

Mind walking me through a bit more?

I've looked at jQuery.each but no real information on how to achieve the same result... i.e. for each JSON object, output the key data > here <
 
Soldato
OP
Joined
13 Jun 2009
Posts
4,233
Location
My own head
Cheers for that, really helped. Still some cleanup to do but got it working now with >1 objects, just need to put some handling for 0/1 but won't be an issue in production as there are plenty in the db. Also I'll skip assigning variables and just output them direct into the document.

Code:
function reviews_data(data)
{
    reviews = data;
    var reviewCount = 1;
    for(var i = 0; i < reviews.length; i ++) {

        console.log(reviews[i].id);
        console.log(reviews[i].name);
        var reviewID = reviews[i].id;
        var reviewName = reviews[i].name;
        var reviewText = reviews[i].reviewtext;
        var reviewRating = reviews[i].reviewrating;

        document.getElementById("reviews").innerHTML+= '<div class="col-sm-4 portfolio-item" id="review_' + reviewCount +'"> <div class="review" data-stars="1,2,3,4,5"> <p class="reviewContent">' + reviewText + '</p>	<p class="reviewName">' + reviewName + '</p> <input id="review-rating' + reviewCount +'" class="rating" data-stars="' + reviewRating + '" data-step="1" value="5" disabled="true" data-size="xs" /></div></div></div>';

        $('#review-rating' + reviewCount).rating('refresh', {
            showClear:true,
            disabled:true,
            showCaption:false,
            showClear:false
        });
        
        reviewCount++;
    }

Hopefully isn't too terrible!
 
Last edited:
Soldato
OP
Joined
13 Jun 2009
Posts
4,233
Location
My own head
My first port of call would be to check the code in your Laravel controller - this needs to provide a consistently-formatted response every time.

Yeah shortly after posting above, I did more digging and come to the conclusion that laravel 5.0 has a bug. Talked in their slack and no one can solve it! Gave them all the code, and all I'm doing is using proprietary laravel functions/methods to do this.

When using random row retrieval, it sends back named / unnamed objects in what seems like a pluck out of a hat.

I can bypass it by doing something like getting the 3 latest reviews, but it would have been nice to randomly show some reviews each time someone visits.

I've left it alone for now whilst I get the rest of the site done, really liking laravel overall though! First time getting deep into an MVC framework myself hands on. Nevertheless, the javascript you provided is a bit cleaner, so not all lost :D.
 
Back
Top Bottom