1

I have several dropdown select menus where a selection of the first changes the options of the second and a selection on the second changes the options of the third, and so on.

I would like to remotely simulate a change (i.e. without the user clicking in the select menu) in the dropdown menu which will activate the Javascript to set the next dropdown's options. Just setting the value of the select menu - document.getElementById('...').value='....' - does not stimulate the Javascript events on the dropdowns.

Note: I do not have access to the Javascript controlling the select menus nor do I know which trigger it looks for on the select menus (I am assuming "onselect").

I am using Javascript and the jQuery library. I need the solution to, of course, work cross browser.

Here is the whole js code (seems to be in prototype) that sets the listeners for the dropdowns:

/**************************** CONFIGURABLE PRODUCT **************************/
Product.Config = Class.create();
Product.Config.prototype = {
    initialize: function(config){
        this.config     = config;
        this.taxConfig  = this.config.taxConfig;
        this.settings   = $$('.super-attribute-select');
        this.state      = new Hash();
        this.priceTemplate = new Template(this.config.template);
        this.prices     = config.prices;

        this.settings.each(function(element){
            Event.observe(element, 'change', this.configure.bind(this))
        }.bind(this));

        // fill state
        this.settings.each(function(element){
            var attributeId = element.id.replace(/[a-z]*/, '');
            if(attributeId && this.config.attributes[attributeId]) {
                element.config = this.config.attributes[attributeId];
                element.attributeId = attributeId;
                this.state[attributeId] = false;
            }
        }.bind(this))

        // Init settings dropdown
        var childSettings = [];
        for(var i=this.settings.length-1;i>=0;i--){
            var prevSetting = this.settings[i-1] ? this.settings[i-1] : false;
            var nextSetting = this.settings[i+1] ? this.settings[i+1] : false;
            if(i==0){
                this.fillSelect(this.settings[i])
            }
            else {
                this.settings[i].disabled=true;
            }
            $(this.settings[i]).childSettings = childSettings.clone();
            $(this.settings[i]).prevSetting   = prevSetting;
            $(this.settings[i]).nextSetting   = nextSetting;
            childSettings.push(this.settings[i]);
        }

        // Set default values - from config and overwrite them by url values
        if (config.defaultValues) {
            this.values = config.defaultValues;
        }

        var separatorIndex = window.location.href.indexOf('#');
        if (separatorIndex != -1) {
            var paramsStr = window.location.href.substr(separatorIndex+1);
            var urlValues = paramsStr.toQueryParams();
            if (!this.values) {
                this.values = {};
            }
            for (var i in urlValues) {
                this.values[i] = urlValues[i];
            }
        }

        this.configureForValues();
        document.observe("dom:loaded", this.configureForValues.bind(this));
    },

    configureForValues: function () {
        if (this.values) {
            this.settings.each(function(element){
                var attributeId = element.attributeId;
                element.value = (typeof(this.values[attributeId]) == 'undefined')? '' : this.values[attributeId];
                this.configureElement(element);
            }.bind(this));
        }
    },

    configure: function(event){
        var element = Event.element(event);
        this.configureElement(element);
    },

    configureElement : function(element) {
        this.reloadOptionLabels(element);
        if(element.value){
            this.state[element.config.id] = element.value;
            if(element.nextSetting){
                element.nextSetting.disabled = false;
                this.fillSelect(element.nextSetting);
                this.resetChildren(element.nextSetting);
            }
        }
        else {
            this.resetChildren(element);
        }
        this.reloadPrice();
//      Calculator.updatePrice();
    },

    reloadOptionLabels: function(element){
        var selectedPrice;
        if(element.options[element.selectedIndex].config){
            selectedPrice = parseFloat(element.options[element.selectedIndex].config.price)
        }
        else{
            selectedPrice = 0;
        }
        for(var i=0;i<element.options.length;i++){
            if(element.options[i].config){
                element.options[i].text = this.getOptionLabel(element.options[i].config, element.options[i].config.price-selectedPrice);
            }
        }
    },

    resetChildren : function(element){
        if(element.childSettings) {
            for(var i=0;i<element.childSettings.length;i++){
                element.childSettings[i].selectedIndex = 0;
                element.childSettings[i].disabled = true;
                if(element.config){
                    this.state[element.config.id] = false;
                }
            }
        }
    },

    fillSelect: function(element){
        var attributeId = element.id.replace(/[a-z]*/, '');
        var options = this.getAttributeOptions(attributeId);
        this.clearSelect(element);
        element.options[0] = new Option(this.config.chooseText, '');

        var prevConfig = false;
        if(element.prevSetting){
            prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];
        }

        if(options) {
            var index = 1;
            for(var i=0;i<options.length;i++){
                var allowedProducts = [];
                if(prevConfig) {
                    for(var j=0;j<options[i].products.length;j++){
                        if(prevConfig.config.allowedProducts
                            && prevConfig.config.allowedProducts.indexOf(options[i].products[j])>-1){
                            allowedProducts.push(options[i].products[j]);
                        }
                    }
                } else {
                    allowedProducts = options[i].products.clone();
                }

                if(allowedProducts.size()>0){
                    options[i].allowedProducts = allowedProducts;
                    element.options[index] = new Option(this.getOptionLabel(options[i], options[i].price), options[i].id);
                    element.options[index].config = options[i];
                    index++;
                }
            }
        }
    },

    getOptionLabel: function(option, price){
        var price = parseFloat(price);
        if (this.taxConfig.includeTax) {
            var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
            var excl = price - tax;
            var incl = excl*(1+(this.taxConfig.currentTax/100));
        } else {
            var tax = price * (this.taxConfig.currentTax / 100);
            var excl = price;
            var incl = excl + tax;
        }

        if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
            price = incl;
        } else {
            price = excl;
        }

        var str = option.label;
        if(price){
            if (this.taxConfig.showBothPrices) {
                str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) + ' ' + this.taxConfig.inclTaxTitle + ')';
            } else {
                str+= ' ' + this.formatPrice(price, true);
            }
        }
        return str;
    },

    formatPrice: function(price, showSign){
        var str = '';
        price = parseFloat(price);
        if(showSign){
            if(price<0){
                str+= '-';
                price = -price;
            }
            else{
                str+= '+';
            }
        }

        var roundedPrice = (Math.round(price*100)/100).toString();

        if (this.prices && this.prices[roundedPrice]) {
            str+= this.prices[roundedPrice];
        }
        else {
            str+= this.priceTemplate.evaluate({price:price.toFixed(2)});
        }
        return str;
    },

    clearSelect: function(element){
        for(var i=element.options.length-1;i>=0;i--){
            element.remove(i);
        }
    },

    getAttributeOptions: function(attributeId){
        if(this.config.attributes[attributeId]){
            return this.config.attributes[attributeId].options;
        }
    },

    reloadPrice: function(){
        var price    = 0;
        var oldPrice = 0;
        for(var i=this.settings.length-1;i>=0;i--){
            var selected = this.settings[i].options[this.settings[i].selectedIndex];
            if(selected.config){
                price    += parseFloat(selected.config.price);
                oldPrice += parseFloat(selected.config.oldPrice);
            }
        }

        optionsPrice.changePrice('config', {'price': price, 'oldPrice': oldPrice});
        optionsPrice.reload();

        return price;

        if($('product-price-'+this.config.productId)){
            $('product-price-'+this.config.productId).innerHTML = price;
        }
        this.reloadOldPrice();
    },

    reloadOldPrice: function(){
        if ($('old-price-'+this.config.productId)) {

            var price = parseFloat(this.config.oldPrice);
            for(var i=this.settings.length-1;i>=0;i--){
                var selected = this.settings[i].options[this.settings[i].selectedIndex];
                if(selected.config){
                    var parsedOldPrice = parseFloat(selected.config.oldPrice);
                    price += isNaN(parsedOldPrice) ? 0 : parsedOldPrice;
                }
            }
            if (price < 0)
                price = 0;
            price = this.formatPrice(price);

            if($('old-price-'+this.config.productId)){
                $('old-price-'+this.config.productId).innerHTML = price;
            }

        }
    }
}

all the select menus have the class "super-attribute-select"

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
YWSW
  • 453
  • 8
  • 18
  • 1
    show the html generated, also are these elements dynamically added by script? – charlietfl Jan 13 '13 at 17:15
  • the html code generate is basic (). There is no js in the HTML. Also, the elements are added dynamically by the js (client side not server side). – YWSW Jan 13 '13 at 17:43
  • looks like code is using another javascript library to manage listeners... use that library to trigger change...also possible functions are asynchronous so may need to set timer to see if select exists before triggering change – charlietfl Jan 13 '13 at 17:52
  • I see... I found this code in the same function "configure: function(event){ var element = Event.element(event); this.configureElement(element); }," – YWSW Jan 13 '13 at 18:02
  • code shown is still dependent on other library, not sure what it is or how to use it to trigger events...what other scripts are loaded in page that this code might reference? – charlietfl Jan 13 '13 at 18:26
  • could it be the prototype library? – YWSW Jan 13 '13 at 18:28
  • look in network tab of browser console at all scripts loaded. Could be proprietary library also. Example `Class.create();` is dependent on other code and use of `$$` or `$` isn't defined in code shown – charlietfl Jan 13 '13 at 18:31

2 Answers2

1

For this

<select name="blah">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
</select>

You would

$('select[name="blah"]').val(3).trigger('change');

Don't know if you're looking for .trigger('select'); or trigger('onselect'); but I've never used those.

Demo

Popnoodles
  • 28,090
  • 2
  • 45
  • 53
  • tried it - does not seem to activate the selects javascript. does .trigger('change') affect an onselect listener? – YWSW Jan 13 '13 at 17:12
  • append `.trigger('onselect')` - we can't see your JS so impossible to be accurate. Does the value in the drop down change? – Popnoodles Jan 13 '13 at 17:14
  • the value i the first dropdown changes only it does not activate the js... the dropdowns in question are those used in magento for a configurable product. – YWSW Jan 13 '13 at 17:20
  • Are you executing your script after the other script has run? – Popnoodles Jan 13 '13 at 17:21
  • that is the plan - I have not written it yet. – YWSW Jan 13 '13 at 17:22
  • all I am doing now is trying to remotely simulate a change in the select – YWSW Jan 13 '13 at 17:22
  • how would I determine which event handler the magento js is using? (their js file is too large to look through) – YWSW Jan 13 '13 at 17:29
  • From what you posted, 'change'. You haven't given enough data in the outset for this to be a simple answer. – Popnoodles Jan 13 '13 at 17:57
  • For my case, `$('select[name="blah"]').val(3).trigger('onchange');` works, which can trigger the associated `onchange` function. – Guoyang Qin Mar 05 '20 at 07:32
0

Somethinkg like this may work:

$('select option[value=yourValue]').click();

Or:

$('select').find('option[value=yourValue]').attr('selected', 'selected').end().trigger('onselect');
Thomas Kekeisen
  • 4,355
  • 4
  • 35
  • 54