Search code examples
javascriptjquerymagentoprototypejs

Triggering change on input


I have written some code that changes an input quantity on a magento 1.9 ecommerce website.

jQuery("input.qty").val("10");

The problem is the javascript that triggers the total to update doesn't fire. I have found the code responsible and it looks like this:

(function() {
  var qtyFields = $('super-product-list').select('input.qty');
  qtyFields.each(function(el) {
    el.observe("change", updateGroupedPrice);

  });

  Event.observe(window, "load", updateGroupedPrice);

  function updateGroupedPrice() {
    //do stuff
  }
})();

I think this is using prototype.js but I tried to isolate it in a codepen but couldn't get it working.

I have tried to trigger the change event like so:

jQuery("input.qty").trigger("change")

But it does not work. I also ran through a load of other events but in the dev tools it shows the code listening on "change".

Does anyone know why I can't trigger the change?


Solution

  • Since the page is using Prototype.js, you ought to keep using that to trigger your change. If you introduce jQuery into this, you're a) loading another complete duplicate of what Prototype already does, and b) asking for a lot of trouble isolating the fact that $() is a method in both libraries.

    Your jQuery is a little fishy to me, too. You're setting the value of one picker (I imagine) and yet you are addressing it with a classname, so potentially there is more than one select.qty in the page, and all of them will change to value 10, firing off (potentially) multiple callback functions.

    The Prototype code you see here is setting up a "listener" for changes on what you would address in jQuery as$(#super-product-list input.qty) inputs.

    jQuery always treats $() as returning an array of objects, and thus all of its methods act on the array, even if it only contains one member. Prototype has two different methods for accessing elements in the DOM: $('some_id'), which always returns one element (or none, if no match), and $$('some css selector'), which always returns an array (of zero or more matching elements). You would write (or use native) callback methods differently, depending on which accessor you used to gather the element(s).

    If you want to change one of these inputs, you will need to isolate it before you set its value.

    Let's say there are three select pickers with the classname qty in your #super-product-list element. You want to change the third one to 10:

    $('super-product-list').select('input.qty').last().setValue('10');
    

    Or, much smarter than this, you add an ID to the third one, and then your code is much shorter:

    $('quantity_3').setValue('10');
    

    In either case, this will send the "change" event from your select, and the updateGroupedPrice method will observe that and do whatever you have coded it to do.

    You won't need to (and should not ever) trigger the change event -- that's a "native" event, and the browser owns it. jQuery's trigger() (which is fire() in Prototype, is used exclusively for "synthetic events", like you see in Bootstrap: show.bs.modal, hide.bs.modal, etc. You can spot these by the punctuation in their names; usually dots or colons to namespace the events and avoid collisions with other code.

    Finally, if you really, really, really wanted to change every single #super-product-list select.qty element on the whole page to '10', you would do this in Prototype.js:

    $$('#super-product-list select.qty').invoke('setValue', 10);