6

On a product page, a customer can select from different variants. In a "select" element, all the variants are stored. This element is hidden with display none. So, users can select variants using all fancy things like swatches and other fun stuff but under the hood its just a "select" element which keeps track of which variant is being used. Its value is variant id.
I am attaching an image to be more clear on what's going on.

visual description of question

Goal: Get the variant id on change of variant.

Problem: I am unable to detect the change event on this select element.

Limitations: I am not allowed to touch the HTML of this code. I can only append a javascript file at run time on this page in <head> tag and I need to detect the change event in that script.

$(document).ready(function(){

 $('body').on('change', "select[name='id']",  function(){

   console.log('here');

 });


});

I can get its value just fine with below code at any time I want.

console.log($("select[name='id']").val());

Any ideas that why change event won't be detected?

awebartisan
  • 1,424
  • 16
  • 27
  • Have you tried using the select id instead? So, `#ProductSelect` – Jean Paul Sep 20 '18 at 21:01
  • **id** keeps changing... the only attribute that remains same is `name="id"`. Its a convention followed by Shopify themes. – awebartisan Sep 20 '18 at 21:03
  • "The fancy things" probably set the select's value by using the `.val` method which doesn't trigger `change` event. – Ram Sep 20 '18 at 21:03
  • Yes. I thought of same. If they are changing the value, they have to manually trigger the change event. `trigger('change')` like so. and most probably they are not doing it. In that case, is it the end of it? – awebartisan Sep 20 '18 at 21:05
  • OK, so which field changes the value? – Jean Paul Sep 20 '18 at 21:07
  • It could be anything, a radio button, another select box, or some buttons that can be seen in above picture. they are responsible for changing its value. and its value does change. If I get the value manually value changes. – awebartisan Sep 20 '18 at 21:09
  • Most open-source select-related libraries trigger special events. If the script uses one of these libraries you should refer to it's documentations for knowing what APIs you should use in order to listen to the library events. – Ram Sep 20 '18 at 21:15
  • @undefined sadly there is no documentation of this. – awebartisan Sep 20 '18 at 21:16
  • You can inspect the page and find the loaded libraries. To name a few, Chosen.js and selectize.js are pretty popular libraries. – Ram Sep 20 '18 at 21:18
  • @undefined this is the page url, https://bit2byt.myshopify.com/products/beoplay-a9-wireless-speaker , I am also looking , but sometimes we can miss obvious things that others could see , please have a look if you can. – awebartisan Sep 20 '18 at 21:23
  • 1
    The site uses shopify. I think this is the main file: http://cdn.shopify.com/s/files/1/1715/0827/t/5/assets/theme.js?4725181574117956215. A huge bundle of several libraries. Why don't you listen to click event of the buttons instead? Then you can get the corresponding value of the select event. – Ram Sep 20 '18 at 21:41
  • Correction: ... select element. – Ram Sep 20 '18 at 21:47

3 Answers3

4

As per the jQuery documentation change() is not fired when val() is set programmatically

Note: Changing the value of an input element using JavaScript, using .val() for example, won't fire the event.

You need to do it manually when you set val()

$("select[name='id']").val(354).trigger('change');

Edit[0]: After your comments on what you were trying to do I took a quick look at the js.

I found that the template fires a custom event variantChange

$("#ProductSection--product-template").on("variantChange", function(evt){alert($("select[name='id']").val());});

Good Luck;

Steve0
  • 2,233
  • 2
  • 13
  • 22
  • Hmm, that's the bummer. My script is not responsible for changing the value. and the script which is responsible, possibly not triggering the change event. So, is it hopeless?? – awebartisan Sep 20 '18 at 21:11
  • 1
    @awebartisan, I was wrong and have updated my answer. If you do not have control over the triggering event its a hole you want to avoid. – Steve0 Sep 20 '18 at 21:13
  • @awebartisan, I looked quickly at the page you referenced, and located the custom event that is being triggered. – Steve0 Sep 20 '18 at 22:18
  • I couldn't rely on the above solution because these templates names and ids keep changing with themes. Only form element "name attribute" and select "name" attribute stay the same because these are part of convention. Thank you for all the efforts :) Really appreciate it. – awebartisan Sep 21 '18 at 06:36
3

Since the goal was to get the current value of variant id, here is how I got to that.

Getting the value is not a problem, so when page loads, store the initial value in localStorage then listen to change event on form. Thankfully, change event is triggering on Form element.

        $('body').on('change', 'form[action^="/cart/add"]', function () {

            console.log($('select[name="id"]').val());

        });

Compare the value with previous value and see if its changed. If yes, then do my thing. If not, wait for another change event on form. Yeah, I hope it will work for the long run.

Thank you all !!

awebartisan
  • 1,424
  • 16
  • 27
2

I think that should know what triggers this, I mean if change when you change the select of the sizes then inside this you get the value that you need, for example:

$(document).on("change","#select1",function(){
  var valuneed = $("#select2").val();
  console.log(valuneed);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="select1">
<option value="11">size a</option>
<option value="21">size b</option>
</select>

<select id="select2">
<option value="21">value a</option>
<option value="22">value b</option>
</select>

And if the update of the second select takes a seconds (is the usual) then you just add a settimeout

If there is more than just on trigger, then you:

$(document).on("change","#select1, #selector2, #selector3",function(){

Let me know if this is what you need.