Ajax-style form submission

drwagner13drwagner13 Member
in Help edited December 2008
I would like to try to submit a form to foxycart without loading the cart in order to do a true "post" form submission. I need only post an alert to the client that their items were added to the cart, and if possible update the mini-cart.

Can someone please point me in the right direction or tell me if this is even possible?

Reason: The current foxycart implementation cannot handle more than about 25 items in a single form before IE balks at the GET submission.
«1
Comments
  • brettbrett FoxyCart Team
    I'll see if I can whip something up for you and post a tutorial on the wiki or something. Stay tuned, but feel free to bump this thread.
  • brettbrett FoxyCart Team
    Ok, I think I may have actually got something working.
    - Change your form.foxycart elements to form.foxycart_json.
    - Add the target="cart_iframe" to all your form.foxycart_json elements.
    - Add an iframe#cart_iframe to your page somewhere. Give it name="cart_iframe" too, just for good measure. You can make this display:none if you'd like (and you probably should, though you may want to wait until you're done testing).
    - Add the following script somewhere after your foxycart_includes.js file:
    <script type="text/javascript" charset="utf-8">
    	$j(document).ready(function(){
    		// Fix the form action for users with 3rd party cookies disabled
    		action = $j('form.foxycart_json').attr('action') + '?' + fc_AddSession();
    		$j('form.foxycart_json').attr('action', action);
    		
    		// Fake a callback onload
    		$j('#cart_iframe').load(function(){
    			fc_UpdateCart(FoxyDomain);
    		});
    	});
    </script>
    

    I haven't tested in anything but Firefox at this point, but it seems to work much better than I thought it would. The real issue here is that you simply _can't_ do cross-domain POSTs in any sort of AJAXy way. They're impossible. We're getting around it here by posting to an iframe (not AJAX), but adding an onload event to the iframe.

    You could add some helpful visual indicators for your visitors while they're waiting, like perhaps add an onclick function to change the form's submit button to disabled and change the text to "Please wait...", then change it back on the .load() function. Or you could do a page overlay like the default thickbox. Options are endless, but this basic functionality should address the problem.

    Definitely give it some cross-browser testing though, as I've only briefly tested it. Let me know if you have any issues.
  • drwagner13drwagner13 Member
    edited December 2008
    Brett, how great to try and help me out... very nice! However, after following your directions, I am getting "Request-URI Too Large" in the iframe when I try to submit the form. Before, I could do a submit with no target in the form element and that would take me to a generic cart, so I know that it is possible, somehow, to post a large form.

    If you'd like to have a look, here's my test page. (login tester, password c@ctus):

    http://shop.cssainc.org/test-long-list.html

    I made a shorter-list test page (http://shop.cssainc.org/test-short-list.html) with only 10 items (instead of the [arbitrary?] maximum 99), and the iframe reloads with the current page, but the items to do appear in the cart. It is likely I ahve some stupid syntax error, but it's a bit late tonite for me to figure this out. Your help is, as always, very much appreciated.
  • brettbrett FoxyCart Team
    edited December 2008
    Sorry for the delay. I've taken a look and I think the issue may (hopefully) be simple: You don't have a method set on your form, so the browser is defaulting to GET not POST. Add method="post" and that should hopefully help, because without it you're still going to run into the same limitations with get we're trying to avoid.

    You also don't have an action attribute on your form, so it's posting to itself rather than to the cart. You need to set the action attribute to the URL of your cart (https://yourdomain. foxycart . com/cart).

    And I forgot to mention that you need a hidden input with name="output" value="json" somewhere in your form as well.

    (The "check all" doesn't seem to work, but I'm assuming you're aware of that.)

    As far as the maximum number of products, I think I missed that earlier. You're trying to add more than 100 and they're just not showing up in the cart? Or are they getting cut off somewhere else?
  • Oh! the details. Well, let's jsut say that we are getting closer. Updating everything as per your instructions, I now see in the iFrame a message saying "You must specify a name to add a product to your shopping cart." If I change the method to "get", the item gets added (for a form with few items), so at least the method works in principle. But with the form I have set up with 99 items, we run into the-URL-is too-long problem using the get method, as before.

    As for the 99 item limit, this is documented in your WIKI. You can prefix multiple items in the form thusly name="1:name"... price="1:price"... name="2:name"...price="2:price"... in order to have multiple items added in a single post. But after number 99 the items are ignored. In other words, there is a 100 item limit (or is it 99?) for form items. I don't know if this is a Foxycart thing, or a general html thing. But if it is a foxycart thing, I must be the first person to run up against this barrier.

    I have two test pages set up, one with about 9 items in the form, and one with 99. You can see the problem I am having with the "POST" now if you look at these (same page and login as before).

    As always, I am grateful for your help... can you get me over this last little hump?
  • lukeluke FoxyCart Team
    99 is a FoxyCart limitation. We'll take a look at that and see if it's something we can change in a future release.
  • brettbrett FoxyCart Team
    Ok, so progress is good. It should work with a post. Can you set up a test page to play with? It's probably something really simple.
  • Oh, I thought since you were able to see my test page before you'd be able to find it again, but you've got a lot to keep track of, so my bad. Please steer yourself over to:

    http://shop.cssainc.org/seed-depot.html

    and login (username: tester, password, c@ctus) to see the two test pages (test short, test long). There is one with about 9 items and one with 99. Neither work, although is I do a get the 9-item page does work.

    You are right, it is probably something very simple. I eagerly await your input. You guys are great.

    (It would be ideal to lift the 99 limit on the number of items that can be added simultaneously to the cart. Seems like an arbitrary value that I could easily surpass with my current store!)
  • brettbrett FoxyCart Team
    Huh. I took a look and I'm not seeing anything obvious. I'm in the middle of something, but if you can get to it before I can, I'd suggest creating a dummy page with just a basic form (a single product), the jQuery and the iframe. Then start adding complexity (like the checkbox javascript).

    I'd also try starting at 1, not 0, and don't prefix the first set with the 1:.
    I've tested quickly and I don't think that's the issue, but it's worth a retest. If you can't get it working on with a basic form let me know. I have a working basic form, so I know it _should_ work. Just a matter of figuring out why it's not.

    As far as the 99 limit goes, we'll look into it, but we probably won't change anything on 040 since we don't like to touch live version except to fig security issues or bugs. You're definitely the first person to come up against it though ;)
  • OK, I have stripped out all non-foxycart javascript, fixed the item numbering as you instructed, and stripped down the form to one item, no checkbox, and a quantity input. Still no go.

    http://shop.cssainc.org/test-short-list.html (user tester, password:c@ctus)

    And I could have guessed I was the only noe to run up agains the 99 limit. But as we have learned, this limit is a fantasy, as you simply can't post that many items anyway, for other reasons that we are just about to solve.,,
  • lukeluke FoxyCart Team
    Not sure if this is it, but try posting to https://not http:// on your form action. Our server does a redirect when requests come in via http, so that might be confusing things up a bit.
  • brettbrett FoxyCart Team
    I just did a quick test and https seems to fix things. Seems like it's losing the post info on the redirect, which kind of makes sense. Nice catch Luke. I should have caught that. With get requests it's not an issue so I've never thought to look.
  • drwagner13drwagner13 Member
    edited December 2008
    Ah! The asymptotic approach. Now, after adding a single letter "s" (how wonderful), the submit now works on Firefox and Safari on my Mac (and I can add 99 items to the cart by god—but no more).

    BUT! my testers are having problems still with IE on Windows (woo!). Something about "not able to find the Foxycart, how do you want to proceed"...

    If we get this working I owe you guys a wiki page.
  • lukeluke FoxyCart Team
    Just committed some code changes to 0.4.0 that will allow up to 999 products to be added to the cart at one time. We don't normally make changes to live store versions, but this change doesn't appear to affect anything else so we figured it's pretty safe to roll out.
  • brettbrett FoxyCart Team
    IE6 is hard crashing when I try to login...
    And wow, IE7 is certainly behaving strangely... wow definitely weird... I'll see if I can figure that out.
  • Luke, that's great about the 999 items, although at this time you can't submit even 50 due to other limitations.

    Brett: any progress on the IE issues? Odd that it doesn't work. Looking forward to hearing back after the holiday!
  • brettbrett FoxyCart Team
    Ok, give that a try now. We changed the content type of the JSON response to text/plain, which seems to do the trick.
  • Thanks guys, I'm having some testers check this out. In the mean time, I added 295 items to the cart at once (hooray!), and the only problem is that it becomes really really (I mean really) slow to load the cart when there are many items in it. Emptying the cart is equally slow when there are many items in it.

    Why do you think this would be, since to retrieve the html for the page that generated the items in the first place was not slow at all. Is there something slowing down the cart retrieval when there are many items in the cart?

    Just thought you'd like to know, since this may be an internal problem you have not had to consider yet (but speed is nice, eh?)
  • brettbrett FoxyCart Team
    It might be something we have to optimize on our end, as this is considerably more information per transaction than we're used to handling, and the necessary database queries are probably fairly massive compared to an average 3-5 item cart.
  • I would think that your system should be optimized to handle any number of items in the cart. Why place arbitrary limits and expectations? Nowhere in your advertising does it say "Foxycart is only suitable for online shops that don't plan to sell more than 3–5 items at a time."

    For ordering many small items, this can easily be a big problem (imagine machine parts, screws, nails, bulk wholesale orders, and the like). The extensibility of this system is severely compromised. For us it already is.

    Have you ever tried to add more than 50 items to a cart? Try 250. Whew!
  • AdamWintleAdamWintle Member
    edited December 2008
    Hello drwagner13,

    How are you and your testers doing on this issue? Just so I'm on the same page, is this particular forum topic related to point 3B in your latest (more detailed) email?

    I don't think you've mentioned this, but would you want to use this for ordering a high amount of caucus seeds? Like say a packet of 2,000 seeds?
    drwagner13 wrote:
    drwagner13: I would think that your system should be optimized to handle any number of items in the cart. Why place arbitrary limits and expectations?"

    Remember FoxyCart is still relatively new and not even at a v0.5 stage yet - I'm sure their system will be optimized to handle massive orders in future releases; I might be wrong, but I don't think Brett and Luke purposefully built it with "arbitrary" limits, but instead got the basics out the door to be built on and expanded later.
    drwagner13 wrote:
    drwagner13: Nowhere in your advertising does it say "Foxycart is only suitable for online shops that don't plan to sell more than 3–5 items at a time."

    And although its at v0.4.0 its totally usable, I reckon its a solid system and very flexible in comparison to what's out there - from an advertising point of view it wouldn't make sense to mention this as a limitation as such but instead it could be seen as something to keep it lightweight and not bloated.
  • brettbrett FoxyCart Team
    I would think that your system should be optimized to handle any number of items in the cart. Why place arbitrary limits and expectations?
    First: Performance issues are never "arbitrary". There is no code on our end that says, "If $cart_products > 200 then $delay = 30s".

    Second:
    Without going into detail (and trying not to be offensive or condescending), you may want to look into how databases need to be structured in order to _avoid_ limitations. It'd be easy and fast if we said, arbitrarily, "An order can only have up to 10 different products with up to 3 options per product." We could build a single table in the database to handle a specific number of fields to contain all our information (and notice that the number of fields would be significantly higher than 30, since for each bit of info you need a name, price, category, weight, and etc., as well as name, price/weight/code modifiers, and etc.).

    So assuming we have one gigantic table, queries are easy and they only require accessing a single table. (Not really, but in this simplified example we'll pretend.) But one gigantic table would make it impossible to NOT set limitations, since the amount of data that could be stored per transaction is set in the database structure.

    So the correct way to build a database is to use multiple tables to store all the different bits. A table to the transaction, a table for the products in that transaction/cart, a table for product modifiers, and etc. This is how all modern (flexible) systems handle their data. Think about how much information you're requesting every time you load up your cart. It's a lot. Transaction -> products -> product options. With 250+ products in the cart, that's a LOT of queries, which increases server load and latency for _all_ of our users.

    If we were to do an arbitrary limit we'd likely impose it to prevent these types of massive carts, not because the system isn't built to handle it, but because it affects performance adversely for _all_ our users. We're in the process of doing some load testing for our own internal purposes, and we'll be tuning our systems to handle as much traffic as possible, but when dealing with such massive queries there's only so much we can do. We could obviously get into discussions about load balanced database servers with 16GB+ RAM, solid state hard drives, octal-core processors, and etc., and we'd be happy to discuss that with you in private if you'd like an enterprise grade plan, but it'd be _significantly_ more than $15/mo ;)

    I'd love to know if you've A/B tested FoxyCart against any other comparable systems with 250+ items in the cart. If you can find one that performs admirably at that volume we'd love to know.
  • OK, so back to this after a long delay. Things seem to be faster than they used to be. Good job guys!

    I have a working example of the entire system discussed abouce, which basicaly silently adds items to the cart (the mini cart is updated). You can see this here: http://shop.cssainc.org/test-long-list.html

    What I'd like to learn now is, after the items are added, how can I get the cart to pop up so the Submit button behaves like the rest of the site.

    I am assuming I just need to add something to the js...

    Ideally, in the cases where the items being added take a long time, it would be super cool if some sort of thing could happen on the screen indicating something's going on... hints there would be welcome as well.
  • OK, here's what I've accomplished to get the cart to load after the form submission. I've modified the script you gave me to this:

    $j(document).ready(function(){

    // Fix the form action for users with 3rd party cookies disabled

    action = $j('form.foxycart_json').attr('action') + '?' + fc_AddSession();

    $j('form.foxycart_json').attr('action', action);

    // Fake a callback onload

    $j('#cart_iframe').load(function(){
    fc_UpdateCart(FoxyDomain);
    $j('a.foxycart').click(); //this selection is working

    });
    });

    and included a link like this:

    <a class="foxycart" href="https://cssa.foxycart.com/cart?cart=view"; style="display: none">
    View your cart.
    </a>

    Thus, the jquery similates a click on a link which brings up the cart. Everyhting works pretty fast.

    Now I need to handle a few other details, like how to get fc_PreProcess() to run before the form submission, so my error checking works (an error is returned if no items are selected, that is if all quantities are zero).
  • OK, I think I'm finally ready to wrap this up.

    In order to get full functionality, so that the post through the iFrame ends up looking like a normal foxycart call, I did the following:

    First, the code above, with a minor addition, loads the very large form through an iframe:
    $j(document).ready(function(){
    
    	// Fix the form action for users with 3rd party cookies disabled
    
    	action = $j('form.foxycart_json').attr('action') + '?' + fc_AddSession();
    	$j('form.foxycart_json').attr('action', action);
    
    	// Fake a callback onload
    	
    	$j('#cart_iframe').load(function(){
    		fc_UpdateCart(FoxyDomain);
    		$j('a#fcCaller').click();  
    	});
    });
    

    What we have here is that when the iFrame receives new content, posted to it by the form, it does fc_UpdateCart(FoxyDomain); (which from my testing doesn't really seem to do anything, and may be unnecessary), and then I fake a click on a hidden link to pull up the foxycart. The link looks like this:

    <a class="foxycart" id="fcCaller" href="https://cssa.foxycart.com/cart?cart=view"; style="display: none">View your cart</a>

    Now, the above method does not do the form validation included in function fc_PreProcess. In order to get this to work, I had to bind an event to the Submit button. That code looks like this:
    $j(document).ready(function(){
    	
    	$j('#seedForm input[@type=submit]').click(function(event) {
    		event.preventDefault();	//prevent submit button from doing anything
    		
    		if (fc_PreProcess() != false)	{		//run fc_PreProcess function
    			$j('#seedForm').trigger("submit");	//trigger submit only if PreProcess checks out
    		}
    	});
    
    });
    

    First, we have to prevent the default behavior of the submit button. Then we run the fc_PreProcess function, which in my case ensures that something is selected on the page to add to the cart (if you submit a form where all items have a quantity of zero, foxycart returns and error). Then we trigger the form submission (luckily we didn't have to do this by faking a click on the button, as that would have started the script over.

    I hope I haven't gone overboard here. Seems like a lot of work to accomplish what I thought would be a simple task. However, what I'm left with works pretty good. Its a list of checkboxes or arbitrary length, and any number of items can be added at once! I've tested it up to 347 separate items. Foxycart has a limitation of 1000.

    See it here:

    http://shop.cssainc.org/seed-depot.html
  • Note that the above method does not respect the browser back button.
  • brettbrett FoxyCart Team
    Wow, that's so awesome. Thanks for taking the time to post. Yes, I don't think you've gone overboard. Due to the IE limitations on GET requests and the inability to do cross-domain POST requests, you really have to approach it like this.

    One quick thing about the browser back button: I'm not sure I ever got it working, but I think I played around with changing the URL via an anchor tag, and based on the anchor in the URL the "fake JSONP" iframe functionality would run (or not). Unfortunately, it's kind of a foggy memory atm, and I can't remember whether or not it did work, and if so, how.

    But it's a thought, if that's important to you. Thanks for posting. I've linked to it on a brand new wiki page:
    http://wiki.foxycart.com/docs:advanced:forum
  • brettbrett FoxyCart Team
    Btw:
    OK, so back to this after a long delay. Things seem to be faster than they used to be. Good job guys!

    Wow, I just tested your cart out, and you're right, it's _way_ faster than it used to be. We've made some optimizations since this thread was started, and while we knew they'd help, this is definitely the most dramatic improvement we've seen. Also, fwiw, we're moving to a new and _greatly_ improved server stack soon which should speed things up even more.
  • happycloudhappycloud Member
    edited July 2013
    @brett - I just implemented this - works great except I lost my adwords analytics tracking. It seems that it erases the referrer and changes it to the pager that submits the ajax call. Any suggestions?

    Additional details: What is happening in my analytics is this - I am seeing normal ecommerce tracking numbers as well as goals. However in my adwords campaign it shows $0 for all ads. So it's losing whatever referrer info it uses along the ajax submit
  • I'm thinking I need to pass gclid param to the ajax cart - it's only adwords info that is lost - seems standard referrers are there
Sign In or Register to comment.