如何使用 ng-options 构建自定义选项和多级 optgroup?

How use ng-options to build custom option and multi-level optgroup?

我是 Angular 的新手,我正在尝试制作一个基本原型来销售公司使用 AngularJS。我已经掌握了所有的基础知识,但是为了满足营销人员希望在某些下拉列表中显示选项的方式,我 运行 遇到了麻烦。他们想要这样的视觉效果(没有项目符号),其中粗体项是 optgroup 元素:

HTML 看起来像这样:

        <fieldset id="fs_frameColor">
            <label class="col-xs-4" for="frameColor">Frame Color *</label>                
            <select class="col-xs-8" id="frameColor"
                    ng-model="vm.frameColor"
                    ng-change="vm.frameColorUpdated()"
                    ng-options="color.label for color in vm.frameColors">
            </select>
        </fieldset>            

我希望我可以让 frameColors 数组充满包含标签和值属性的对象,但另外还有类似类型和级别的东西 属性 这样如果类型是可选的,我可以输出一个常规的<option> 元素。如果类型是选项组,我可以输出常规 <optgroup>

我知道到目前为止一切都很简单。例如,您可以在 ng-options 指令中引入一个分组依据,该指令将根据分组依据自动创建 optgroup 元素。然而,由于营销希望这些出现的方式,嵌套是多层的。

由于多级性质,这就是为什么我希望能够在我的数组中的对象上使用类型和级别属性,例如,“TwoTone" 上面的项目有类型:"OptionGroup" 所以我可以输出一个 <optgroup/> 元素然后 level:1 所以它会像往常一样缩进。然后它的子“WhtExt”项目将具有类型:"OptionGroup",但是 level:2 所以我可以输出一个 <optgroup/> 元素及其正常的粗体文本, 但该文本要缩进几个空格。该组的子选项元素将具有类似于 type:"Option" 和 level:3 的内容,因此 <option/> 元素将输出带有足够缩进的文本,以使它们显示为子元素 " WhtExt" 父选项组。此处未显示,但如果他们希望子选项元素显示在“TwoTone”选项组之前的“WhtExt”子选项组下,则该对象在数据数组的类型为:"Option" 和 level:2.

我已经通过指令成功地做到了这一点,但前提是我将 <select><option/><option/><optgroup><optgroup><option/><option/></optgroup><optgroup><option/><option/></optgroup></optgroup></select> 代码直接嵌入我的 html 并将所需的指令添加到特定的子元素。但是,从长远来看,这些数据将来自某些 API,因此我正在尝试确定一种方法来使用与数组数据中的属性值相关联的 ng-options 来完成所有这些自定义多层组。

由于这是一个原型,输入数据是流动的,我正试图想出一个结构来为 angular 指令(或其他一些 angular机制)输出如上所示的结果。这是我绑定到的硬编码数据的示例。

            vm.frameColors = [
            {
                value: "BZ",
                label: "Bronze",
                type: "Option",
                level: "0"
            },
            {
                value: "W",
                label: "White",
                type: "Option",
                level: "0"
            },
            {
                value: "B",
                label: "Beige",
                type: "Option",
                level: "0"
            },
            {
                value: "TwoTone",
                label: "TwoTone",
                type: "OptionGroup",
                level: "0"
            },
            {
                value: "WhtExt",
                label: "WhtExt",
                type: "OptionGroup",
                level: "1"
            },
            {
                value: "WB",
                label: "W Ext/Brz Int",
                type: "Option",
                level: "2"
            },
            {
                value: "WDO",
                label: "W Ext/Drk Oak Int",
                type: "Option",
                level: "2"
            },
            {
                value: "BrzExt",
                label: "BrzExt",
                type: "OptionGroup",
                level: "1"
            },
            {
                value: "BW",
                label: "Brz Ext/Wht Int",
                type: "Option",
                level: "2"
            },
            {
                value: "BDO",
                label: "Brz Ext/Drk Oak Int",
                type: "Option",
                level: "2"
            },
        ];

如有任何帮助,我们将不胜感激。

-迈克

对于我的项目,我有一个类似的任务(甚至我必须有多选选项),我创建了一个指令,我的下拉列表实际上是一个 div 具有几个级别的元素,类似于这个伪结构:

<ul>
   <li> option1</li>
   <li> option2</li>
   <li class="group"> optiongroup1
       <ul>
        <li> suboptionoption1</li>
        <li> suboptionoption2</li>
        <li> suboptionoption3</li>
      </ul>
   </li>
</ul>

然后自定义列表和组。但是您拥有的数据结构需要更改为可迭代的json,其中包含用于子选项的子项。

@DianaR 我终于通过将逻辑拆分到视图 html 和 angular 指令中得到了我想要的东西。这是视图 html 现在的样子,我正在处理 gridStyle 对象数组而不是以前的 frameColor 数组,但都一样:

        <fieldset id="fs_gridStyle">
            <label class="col-xs-4" for="gridStyle">Grid Style *</label>
            <select class="col-xs-8" id="gridStyle"
                    ng-model="vm.gridStyle"
                    ng-change="vm.gridStyleUpdated()"
                    full-select datarepo="vm.gridStyles">
            </select>
        </fieldset>

指令如下所示:

app.directive('fullSelect', function ($compile) {
    return {
        restrict: 'A',
        scope: { datarepo: "=datarepo" },
        replace: true,
        link: function (scope, element, attrs) {
            angular.forEach(scope.datarepo, function (value, key) {
                var opt;
                var display = "";
                for (var idx = 0; idx < value.level; idx++) {
                    display += "&nbsp;&nbsp;";
                }
                display += value.label;
                if (value.type === "Option") {
                    opt = angular.element('<option value="' + value.value + '">' + display + '</option>');
                }
                else {
                    opt = angular.element('<optgroup label="' + display + '"></optgroup>');
                }
                element.append($compile(opt)(scope));
            });
        }
    }
});

现在我只需要确保它正常运行,但到目前为止它看起来还不错。它给了我想要的最终结果,其中我的传入对象数组包含值、标签和杂项信息,例如级别 属性 以指示该项目应在下拉列表中缩进的位置等。我现在可以拥有任意数量的根据需要缩进的下拉列表中嵌入的选项和 optgroup 子项。您不能嵌套多个 optgroup 元素,但我使用级别 属性 直观地处理它,这会在文本中添加空格。