更改由AngularJs从Chrome内容脚本动态创建的包装选择的值

时间:2016-05-19 23:02:10

标签: javascript angularjs google-chrome-extension

我正在开发自己使用的简单扩展。它的主要目标是基于预定义的选项动态填充表单。

当我尝试从内容脚本更新select元素时,它并没有真正更改所选选项。选择框本身使用跨度集合包装在漂亮的UI中:

    <!-- 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>

我尝试过(实际上并没有改变所选元素):

的jQuery

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

原生 javascript

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

现代DOM选择器

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

甚至点击()而不是选择\值...

附加说明:

  1. 在“run_at”处加载的内容脚本:“document_end”
  2. 使用angularjs构建网站,并在文档准备好后动态创建这些元素,因此出于测试目的,我已经 只是实现了等待,以确保元素已经存在 在DOM中。这是一个肮脏的黑客,但这不是一个对象 讨论

    setTimeout(function(){/ *我的代码在这里* /},8000);

  3. 更新 我最终通过jQuery更改了底层数据选项和连接的UI选项的值,并且仅在Chrome开发人员模式中,通过以下代码:

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

    仅适用于开发者控制台,而不适用于上下文脚本。有人知道为什么吗?

    更新 同时上面的改变价值的解决方案适用于Chrome控制台和Tampermonkey用户脚本,它不适用于我的扩展...

1 个答案:

答案 0 :(得分:2)

最后,我设法解决了这个问题。在内容脚本中:

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

详细说明: 由于上下文脚本在隔离环境中运行,我们需要手动触发事件,因此外部Web页面也可以触发所有订阅者。 jQuery更新和触发器调用由于某种原因不会触发全局DOM事件,并且在这种情况下我必须手动创建并触发更新事件。

在这个答案中提到了更复杂的事件方法:https://stackoverflow.com/a/2856602/1187217

  

如果你需要它来完整地模拟真实事件,或者你设置了   通过html属性或addEventListener / attachEvent事件,你需要   进行一些功能检测以正确触发事件:

if ("createEvent" in document) {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("change", true, true);
    element.dispatchEvent(evt);
}
else
    element.fireEvent("onchange");