0

I'm in process of developing simple extension for own use. It main goal is dynamically fulling forms based on pre-defined options.

When I'm trying to update the select element from my content script it doesn't really change selected option. Selection box itself is wrapped in nice ui using collection of spans:

    <!-- Data with AngularJs bindings -->
<div class="ddOutOfVision" id="drpType_msddHolder" style="height: 0px; overflow: hidden; position: absolute;">
    <select id="drpType" name="Type" class="mobile100 ng-pristine ng-invalid ng-invalid-required" ng-model="Order.ccToAdd.Type" ng-change="change()" required="" tabindex="-1">
        <option value="" selected="">Please select  type</option>                             
        <option data-image="../icons/V.png" value="001">V</option>
        <option data-image="../icons/M.png" value="002">M</option>
        <option data-image="../icons/A.png" value="003">A</option>
        <option data-image="../icons/D.png" value="004">D</option>
    </select>
</div>

<!-- UI -->
<div class="dd ddcommon borderRadiusTp" id="drpType_msdd" tabindex="0" style="width: 100%;">
    <div class="ddTitle borderRadiusTp">
        <span class="divider"/>
        <span class="ddArrow arrowoff"/>
        <span class="ddTitleText " id="drpType_title">
            <span class="ddlabel">Please select type</span>
            <span class="description" style="display: none;"/>
        </span>
    </div>
    <input id="drpType_titleText" type="text" autocomplete="off" class="text shadow borderRadius" style="display: none;" />
    <div class="ddChild ddchild_ border shadow" id="drpType_child" style="z-index: 9999; position: absolute; visibility: visible; height: 168px; top: 33px; display: block;">
        <ul>
            <li class="enabled _msddli_ selected">
                <span class="ddlabel">Please select  type</span>
                <div class="clear"/>
            </li>
            <li class="enabled _msddli_">
                <img src="../icons/V.png" class="fnone" />
                <span class="ddlabel">V</span>
                <div class="clear"/>
            </li>
            <li class="enabled _msddli_">
                <img src="../icons/M.png" class="fnone" />
                <span class="ddlabel">M</span>
                <div class="clear"/>
            </li>
            <li class="enabled _msddli_">
                <img src="../icons/A.png" class="fnone" />
                <span class="ddlabel">A</span>
                <div class="clear"/>
            </li>
            <li class="enabled _msddli_">
                <img src="../icons/D.png" class="fnone" />
                <span class="ddlabel">D</span>
                <div class="clear"/>
            </li>
        </ul>
    </div>
</div>

What I've try (and it doesn't actually change selected element):

jQuery

$("#drpType").val("001");
$("#drpType").val("001").change();
$("#drpType").val("001").trigger('input');
$("#drpType").val("001").trigger('input').change()

Native javascript:

document.forms[0].elements[0].selectedIndex = 1;
document.forms[0].elements[0].options[2].selected = true

Modern DOM selector:

document.querySelector('#drpType [value="001"]').selected = true

And even click() instead of select \ value...

Additional notes:

  1. content script loaded at "run_at": "document_end"
  2. site is build using angularjs and those elements created dynamically after document is ready, so for testing purposes I've just implemented a wait to be sure that elements are already present in DOM. It's dirty hack, but this is not a object for this discussion.

    setTimeout(function () { /* my code here */ }, 8000);

UPDATE I finally get changed the value of underlying data option and connected UI option by jQuery, and only in Chrome developer mode, by code below:

$("#drpType option[value='001']").prop("selected", true).trigger('input').change()        

But this works only from developer console and not from context script. Does someone know why?

UPDATE Meanwhile above solution for changing value works for both Chrome console and Tampermonkey user script, it doesn't works for my extension...

Aleksey Dr.
  • 532
  • 1
  • 4
  • 11

1 Answers1

2

Finally I've managed to solve this task. In content script:

document.querySelector("#drpType option[value='001']").selected = true;
document.querySelector("#drpType").dispatchEvent(new Event('change', {bubbles: true}));

Details: Because context script is running in isolated environment we need to manually trigger events, so external web-page could also trigger all subscribers. jQuery update and trigger calls for some reason do not trigger global DOM event's, and for this case I have to manually create and trigger update event.

More complex approach for event was mentioned in this answer: https://stackoverflow.com/a/2856602/1187217

If you need it to simulate the real event in full, or if you set the event via the html attribute or addEventListener/attachEvent, you need to do a bit of feature detection to correctly fire the event:

if ("createEvent" in document) {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("change", true, true);
    element.dispatchEvent(evt);
}
else
    element.fireEvent("onchange");
wOxxOm
  • 65,848
  • 11
  • 132
  • 136
Aleksey Dr.
  • 532
  • 1
  • 4
  • 11