1

带有 MetroUI CSS 的 Select2 与 AngularJS 配合得很好。但是,当我尝试在相关下拉列表中使用相同的内容时,我面临的问题是子下拉列表的视图不会相应地更新以更改父下拉列表。

这是一个堆栈片段,展示了我看到的问题。

(function () {
    "use strict";
    var app = angular.module("app", []);

    app.controller("AppCtrl", AppCtrl);

    function AppCtrl() {
        var vm = this;

        vm.ContextData = {
            selectParents: [{ "id": 1, "name": "item 1" },
                { "id": 2, "name": "item 2" },
                { "id": 3, "name": "item 3" },
                { "id": 4, "name": "item 4" }],
            selectChildren: [{ "id": 1, "parentId": 1, "name": "1 based on item1" },
                { "id": 2, "parentId": 1, "name": "2 based on item1" },
                { "id": 3, "parentId": 1, "name": "3 based on item1" },
                { "id": 4, "parentId": 1, "name": "4 based on item1" },
                { "id": 5, "parentId": 1, "name": "5 based on item1" },
                { "id": 6, "parentId": 1, "name": "6 based on item1" },
                { "id": 7, "parentId": 1, "name": "7 based on item1" },
                { "id": 8, "parentId": 2, "name": "8 based on item2" },
                { "id": 9, "parentId": 2, "name": "9 based on item2" },
                { "id": 10, "parentId": 2, "name": "10 based on item2" },
                { "id": 11, "parentId": 2, "name": "11 based on item2" },
                { "id": 12, "parentId": 2, "name": "12 based on item2" },
                { "id": 13, "parentId": 3, "name": "13 based on item3" },
                { "id": 14, "parentId": 3, "name": "14 based on item3" },
                { "id": 15, "parentId": 3, "name": "15 based on item3" },
                { "id": 16, "parentId": 3, "name": "16 based on item3" },
                { "id": 17, "parentId": 4, "name": "17 based on item4" },
                { "id": 18, "parentId": 4, "name": "18 based on item4" }]
        };            
    }

})();
<body ng-app="app" ng-controller="AppCtrl as vm">
    <div class="flex-grid">
        <div class="row">
            <div class="cell colspan2 margin10">
                <div class="input-control full-size" data-role="select" data-placeholder="Select a parent" data-allow-clear="true">
                    <select class="full-size" style="display:none" ng-model="vm.selectedParent" ng-options="item.name for item in vm.ContextData.selectParents">
                        <option value=""></option>                        
                    </select>
                </div>
            </div>
            <div class="cell colspan2 margin10">
                <div class="input-control full-size" data-role="select" data-placeholder="Select a child" data-allow-clear="true">
                    <select class="full-size" style="display:none" ng-model="vm.selectedChild" ng-options="item.name for item in vm.ContextData.selectChildren | filter:{parentId:vm.selectedParent.id}">
                        <option value=""></option>
                    </select>
                </div>
            </div>
        </div>
    </div>
    <div class="flex-grid margin10">
        <div class="row">
            <div class="cell colspan2">
                Selected Parent : 
            </div>
            <div class="cell colspan3">
                {{vm.selectedParent}}
            </div>
        </div>
        <div class="row">
            <div class="cell colspan2">
                selected Child : 
            </div>
            <div class="cell colspan3">
                {{vm.selectedChild}}
            </div>
        </div>
    </div>    
</body>

<link href="https://cdn.rawgit.com/olton/Metro-UI-CSS/master/build/css/metro-responsive.min.css" rel="stylesheet"/>
<link href="https://cdn.rawgit.com/olton/Metro-UI-CSS/master/build/css/metro.min.css" rel="stylesheet"/>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/js/select2.min.js"></script>
<script src="https://cdn.rawgit.com/olton/Metro-UI-CSS/master/build/js/metro.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>

重现步骤:

  1. 在父选择中选择“项目 1”(父选择的占位符是“选择父项”)
  2. 在“选定的父项”部分中,显示了选定父项的正确值。
  3. 子选择与正确的子选项绑定。
  4. 从子选择中选择任何选项。
  5. 在“选定子项”部分中显示选定子项的正确值。
  6. 在父选择中,选择“项目 4”。
  7. 在“选定的父项”部分中,显示了选定父项的正确值。
  8. 子选择已绑定,但选项未更新,它仍显示父项 1 的选项。
  9. 选择子选择中的任何项目,在“选定的孩子”部分显示孩子的正确值,但孩子下拉列表显示错误的项目!

因此我的问题是,即使子选择获得了绑定到它的正确选项,它的选项列表视图也不会刷新。

[我尝试了 select2.val(") 但子下拉列表的选项视图仍然没有刷新。]

另一个问题是:如果我清除父选择中的选择,它不会清除子选择中的选择。

4

2 回答 2

0

这里的问题涉及一旦打开下拉菜单,Select2 如何缓存选项,因为它会将它认为正确的数据对象保存到<option>即使 AngularJS 稍后实际上会更改选项。结果,Select2 仍然会显示缓存的数据,而 AngularJS 会识别出选项已更改,您最终会看到像这样的奇怪边缘情况。

目前还没有针对此问题的已知修复,除了强制 AngularJS 以某种方式不重用依赖下拉列表中的选项。

于 2016-01-03T23:11:43.397 回答
0

请参阅此codepen.io以使依赖下拉列表正常工作。

解决的关键点是:

  1. 给孩子一个 ID 下拉菜单
  2. 然后向父下拉菜单提供一个 ng-change 事件
  3. 在父下拉列表的 ng-change 事件中,通过其 ID 搜索子下拉列表
  4. 然后在子下拉列表中调用 select2 函数以清空所选值和 html
  5. 不要忘记在子下拉菜单上触发更改事件。

所以在 ng-change 事件中会是这样的(childSelect2 是子下拉列表的 ID):

var ele = angular.element('#childSelect2');            
ele.html("").val("").trigger("change");

另请注意,在单击父下拉列表中的十字标记时,我们正在清除子下拉列表,因为我们正在调用任何更改ele.html("").val("").trigger("change");

这是可以预料的,因为如果父项中没有选择,那么在子项中进行选择就没有意义。但是有了这个,我们还需要清除子下拉菜单的 ng-model,因此在 ng-change 函数中将子下拉菜单的模型设置为 null(vm.selectedChild 是子下拉菜单的 ng-model)

vm.selectedChild = null;

尽管为了产生任何效果,我发现将子模型设置为 null 应该在调用之前进行,ele.html("").val("").trigger("change");因此我将其设为 ng-change 事件中的第一条语句。[我不知道为什么这个放置顺序很重要,但它只有在这个改变之后才起作用:)]

希望答案可以帮助其他人并节省他们的时间。

快速参考:HTML 代码:

<body ng-app="app" ng-controller="AppCtrl as vm">
    <div class="flex-grid">
        <div class="row">
            <div class="cell colspan2 margin10">
                <div class="input-control full-size" data-role="select" data-placeholder="Select a parent" data-allow-clear="true">
                    <select class="full-size" style="display:none" ng-model="vm.selectedParent" ng-options="item.name for item in vm.ContextData.selectParents" ng-change="vm.SetSelect2()">
                        <option value=""></option>                        
                    </select>
                </div>
            </div>
            <div class="cell colspan2 margin10">
                <div class="input-control full-size" data-role="select" data-placeholder="Select a child" data-allow-clear="true">
                    <select class="full-size" style="display:none" ng-model="vm.selectedChild" ng-options="item.name for item in vm.ContextData.selectChildren | filter:{parentId:vm.selectedParent.id}" id="childSelect2">
                        <option value=""></option>
                    </select>
                </div>
            </div>
        </div>
    </div>
    <div class="flex-grid margin10">
        <div class="row">
            <div class="cell colspan2">
                Selected Parent : 
            </div>
            <div class="cell colspan3">
                {{vm.selectedParent}}
            </div>
        </div>
        <div class="row">
            <div class="cell colspan2">
                selected Child : 
            </div>
            <div class="cell colspan3">
                {{vm.selectedChild}}
            </div>
        </div>
    </div>    
</body>

JS 代码(角度模块和控制器):

(function () {
    "use strict";
    var app = angular.module("app", []);

    app.controller("AppCtrl", AppCtrl);

    function AppCtrl() {
        var vm = this;

        vm.ContextData = {
            selectParents: [{ "id": 1, "name": "item 1" },
                { "id": 2, "name": "item 2" },
                { "id": 3, "name": "item 3" },
                { "id": 4, "name": "item 4" }],
            selectChildren: [{ "id": 1, "parentId": 1, "name": "1 based on item1" },
                { "id": 2, "parentId": 1, "name": "2 based on item1" },
                { "id": 3, "parentId": 1, "name": "3 based on item1" },
                { "id": 4, "parentId": 1, "name": "4 based on item1" },
                { "id": 5, "parentId": 1, "name": "5 based on item1" },
                { "id": 6, "parentId": 1, "name": "6 based on item1" },
                { "id": 7, "parentId": 1, "name": "7 based on item1" },
                { "id": 8, "parentId": 2, "name": "8 based on item2" },
                { "id": 9, "parentId": 2, "name": "9 based on item2" },
                { "id": 10, "parentId": 2, "name": "10 based on item2" },
                { "id": 11, "parentId": 2, "name": "11 based on item2" },
                { "id": 12, "parentId": 2, "name": "12 based on item2" },
                { "id": 13, "parentId": 3, "name": "13 based on item3" },
                { "id": 14, "parentId": 3, "name": "14 based on item3" },
                { "id": 15, "parentId": 3, "name": "15 based on item3" },
                { "id": 16, "parentId": 3, "name": "16 based on item3" },
                { "id": 17, "parentId": 4, "name": "17 based on item4" },
                { "id": 18, "parentId": 4, "name": "18 based on item4" }]
        };

        vm.SetSelect2 = function () {
            ////debugger;
            vm.selectedChild = null;
            var ele = angular.element('#childSelect2');
            //ele.html("");
            //ele.val("").trigger("change");  

            ele.html("").val("").trigger("change");
        }
    }

})();
于 2016-01-04T17:49:41.340 回答