Why is the AJAX call doing this?

Soldato
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
Hi,

Bit of background:
I’ve recently had an order in ‘limbo’ due to stock shortages. Then I got to thinking that OcUK doesn’t show you any sort of stock levels when viewing your basket (so you’d know if they had enough of the items in stock to cover your order).
So I wrote a bookmarklet to get around this.

You run the bookmarklet on the View Cart/Basket page.

My query is, why does the ajax call change the behaviour of the "Update Basket" button from doing what it's supposed to, to being a link to the last item?

Here's the code:
Code:
javascript:(function(){
  $('#shoppingBkt th:contains("Qty")').html('Qty / Stock');
  $('#shoppingBkt a').each(
    function(idx, item) {
      var url = $(item).attr('href');

      if (url != null) {
        $.ajax({
          url: url,
          async: true, 
        }).done(function(data) { 
          var dataRetrieved = $('span.stock',$(data)).last().text();
          if (dataRetrieved == 'Pre-order' || dataRetrieved == 'Out of Stock') {
            dataRetrieved = '0';
          };
          $('#shoppingBkt tr').eq(idx+1).children('td').eq(2).html($('#shoppingBkt tr').eq(idx+1).children('td').eq(2).html() + ' / ' + dataRetrieved);
        });
      }
    }
  );
})();

Thanks.
 
Soldato
Joined
28 Oct 2006
Posts
12,456
Location
Sufferlandria
I would guess that you're using the 'idx' variable wrong.
You set the index for each 'a' item but then you try to use that index later to select a 'tr' item.
 
Soldato
OP
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
I'll take another look later, but off the top of my head, maybe your each selector isn't specific enough..

Quite possibly, this is the first time I've used AJAX and frankly I'm not entirely sure what I'm doing! I found a snippet on the web that I reused, which I may have done wrong!

I would guess that you're using the 'idx' variable wrong.
You set the index for each 'a' item but then you try to use that index later to select a 'tr' item.

Possibly, but when I add a couple of alerts the idx values are what I would expect. Changing them means it doesn't display what it's supposed to.
 
Associate
Joined
10 Nov 2013
Posts
1,808
Only had a quick look, but I would agree with what 'touch' has said - it looks like the use of idx+1 would mean that it's selecting the row AFTER the one you're iterating through? Have you just tried using idx for your tr selector?
 
Soldato
OP
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
Only had a quick look, but I would agree with what 'touch' has said - it looks like the use of idx+1 would mean that it's selecting the row AFTER the one you're iterating through? Have you just tried using idx for your tr selector?

yeah, it needs to be +1 as the first row of the table is the header row and I want to change the row with an item in, making that row 1 (since idx starts at 0 it needs a +1).
 
Associate
Joined
10 Nov 2013
Posts
1,808
I've just ran your code on the view basket page, and then had a look in the HTTP request/response when you click update basket...

When you click update, it makes a post to addtocart.php (which it did before) but the input values of the quantity text boxes are not being sent in the request (which is why the basket is not getting updated). The server is then redirecting you to the product page by setting the 'Location' value in the HTTP response - when your code isn't executed it normally redirects you to viewcart.php, not the product page.

Can't see why that change in behaviour is happening, but hopefully it might help a little.

Edit: And I agree with that 'touch' just posted, I would probably try to rewrite it by looping through each 'tr' rather than each 'a' tag and then using .append() instead - just to make things a bit cleaner.
 
Soldato
Joined
28 Oct 2006
Posts
12,456
Location
Sufferlandria
Edit: And I agree with that 'touch' just posted, I would probably try to rewrite it by looping through each 'tr' rather than each 'a' tag and then using .append() instead - just to make things a bit cleaner.

I have edited my post now because i think i might have spotted the problem.

What i originally said was:
Your use of idx variable works because there is only one 'a' element per 'tr' but it's not good practice to do that and you should use the index of a tr when selecting a tr.

Also, in the last line where you replace the html content of the cell, it would be easier to use .append()
 
Soldato
OP
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
I've just ran your code on the view basket page, and then had a look in the HTTP request/response when you click update basket...

When you click update, it makes a post to addtocart.php (which it did before) but the input values of the quantity text boxes are not being sent in the request (which is why the basket is not getting updated). The server is then redirecting you to the product page by setting the 'Location' value in the HTTP response - when your code isn't executed it normally redirects you to viewcart.php, not the product page.

Can't see why that change in behaviour is happening, but hopefully it might help a little.

Edit: And I agree with that 'touch' just posted, I would probably try to rewrite it by looping through each 'tr' rather than each 'a' tag and then using .append() instead - just to make things a bit cleaner.

Hmm, thanks for that. Not sure what to do about it, but the extra info is nice.
As for looping through the tr tags instead of the a tags, my problem there was extracting the URL from it as I don't believe "$(item).attr('href');" will then work.
 
Soldato
OP
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
OK, I've updated it to:
Code:
javascript:(function(){
  $('#shoppingBkt th:contains("Qty")').html('Qty / Stock');
  $('#shoppingBkt tr').each(
    function(idx, item) {
      var url = $(item).find('a').attr('href');

      if (url != null) {
        $.ajax({
          url: url,
          async: true, 
        }).done(function(data) { 
          var dataRetrieved = $('span.stock',$(data)).last().text();
          if (dataRetrieved == 'Pre-order' || dataRetrieved == 'Out of Stock') {
            dataRetrieved = '0';
          };
          $('#shoppingBkt tr').eq(idx).children('td').eq(2).append(' / ').append(dataRetrieved);
        });
      }
    }
  );
})();

And it's improved it a little. It now does update the quantity, but still re-directs to the wrong page. It seems the input values from the quantity text boxes are now being passed through!
On a side note it now also seems to work for all "Outstanding Orders" if you log in to your account, previously it only did the top order.

EDIT: I've also noticed that removing the line:
Code:
$('#shoppingBkt tr').eq(idx).children('td').eq(2).append(' / ').append(dataRetrieved);
so that the script doesn't change anything, still gets the same issue.
 
Last edited:
Associate
Joined
7 Apr 2012
Posts
2,101
Location
Tampa Bay
For whatever reason in the developers infinite wisdom your problem is not caused by the script directly, addtocart.php will redirect to the last page viewed it seems (you can replicate by simply viewing basket, middle clicking on product link and then updating your basket total - it will cause it to redirect to the product page).

Here's a crude fix that will call a request to viewcart.php after the stocks are all returned which "fixes" the issue:

Code:
javascript:(function(){
	var toComplete = $('#shoppingBkt tr a[href]').length;
	var hasCompleted = 0;
	$('#shoppingBkt th:contains("Qty")').html('Qty / Stock');
	$('#shoppingBkt tr').each(
		function(idx, item) {
			var url = $(item).find('a').attr('href');

			if (url != null) {
				$.ajax({
					url: url,
					async: true, 
				}).done(function(data) {
					hasCompleted++;
					var dataRetrieved = $('span.stock',$(data)).last().text();
					if (dataRetrieved == 'Pre-order' || dataRetrieved == 'Out of Stock') {
						dataRetrieved = '0';
					};
					$('#shoppingBkt tr').eq(idx).children('td').eq(2).append(' / ').append(dataRetrieved);

					if (hasCompleted >= toComplete)
					{
						$.ajax({
							url: '/viewcart.php',
							async: true, 
						});
					};
				});
			}
		}
	);
})();
 
Soldato
OP
Joined
29 Aug 2010
Posts
7,907
Location
Cornwall
^^ awesome thanks!
That explains it!

So it's not my fault, it's theirs! I like that :)

EDIT:
I went with a slightly simpler fix that I think does the same job...

Code:
javascript:(function(){
  $('#shoppingBkt th:contains("Qty")').html('Qty / Stock');
  $('#shoppingBkt tr').each(
    function(idx, item) {
      var url = $(item).find('a').attr('href');

      if (url != null) {
        $.ajax({
          url: url,
          async: true, 
        }).done(function(data) { 
          var dataRetrieved = $('span.stock',$(data)).last().text();
          if (dataRetrieved == 'Pre-order' || dataRetrieved == 'Out of Stock') {
            dataRetrieved = '0';
          };
          $('#shoppingBkt tr').eq(idx).children('td').eq(2).append(' / ').append(dataRetrieved);
        });
      }
    }
  );
  $.ajax({
    url: '/viewcart.php',
    async: true, 
  });
})();
 
Last edited:
Back
Top Bottom