有条件地将“multiple”属性添加到 ui-select

Posted

技术标签:

【中文标题】有条件地将“multiple”属性添加到 ui-select【英文标题】:Conditionally add the "multiple" attribute to ui-select 【发布时间】:2015-10-30 13:46:31 【问题描述】:

我正在尝试根据使用ng-attr- 指令的某个属性的值将multiple 属性添加到ui-select 指令。不幸的是,这对我不起作用。我已经设置了一个 plunker 示例来展示正在发生的事情。

Plunker Example

【问题讨论】:

【参考方案1】:

编辑

在阅读了 Angular Repo 中提到的GitHub Issue 后,我终于明白了。

您需要设置一个具有更高priorityterminal 属性设置为true 的指令(在我们的指令编译后跳过所有其他指令的编译)。 然后在postLink 函数中,我们将编译整个元素本身。但在此之前,我们自己的指令需要被移除(无限循环!)。

对Add directives from directive in AngularJS的大手笔

指令代码

angular.module('app')
  .directive('multiSelectChecker', function ($compile) 
    return 
      restrict: 'A',
      replace: false, 
      terminal: true, //terminal means: compile this directive only
      priority: 50000, //priority means: the higher the priority, the "firster" the directive will be compiled
      compile: function compile(element, attrs) 
        element.removeAttr("multi-select-checker"); //remove the attribute to avoid indefinite loop
        element.removeAttr("data-multi-select-checker"); //also remove the same attribute with data- prefix in case users specify data-multi-select-checker in the html

        return 
          pre: function preLink(scope, iElement, iAttrs, controller)   ,
          post: function postLink(scope, iElement, iAttrs, controller)  
            if(scope.options.Multiple == true) 
              iElement[0].setAttribute('multiple',''); //set the multiple directive, doing it the JS way, not jqLite way.
            
            $compile(iElement)(scope);
          
        ;
      
    ;
  );

HTML 代码

  <ui-select ng-model="model.choice" multi-select-checker>
    <ui-select-match>$item.Title</ui-select-match>
    <ui-select-choices repeat="item.Id as item in options.SuggestedValues | filter:  Title: $select.search ">
      <div ng-bind="item.Title | highlight: $select.search"></div>
    </ui-select-choices>
  </ui-select>

工作计划:

http://plnkr.co/edit/N11hjOFaEkFUoIyeWqzc?p=preview


原始答案(同样有效,但代码重复)

我做了以下事情:

    创建了一个名为 multi-select-checker 的包装指令 在该指令中检查 options.Multiple 是真还是假 为每个案例返回两个不同的模板 URL。案例 1):返回 single-select.tpl.html 或案例 2):返回 mutli-select.tpl.html(其中包括 'multiple' 指令。

指令代码:

app.directive('multiSelectChecker', function() 
return 
    template: '<ng-include src="getTemplateUrl()"/>',
    controller: function($scope) 
      $scope.getTemplateUrl = function() 
        if($scope.options.Multiple == true) 
          console.log("multi-select");
          return "multi-select.tpl.html"
        
        else 
          console.log("single select");
          return "single-select.tpl.html"
        
      
    
  
)

在 HTML 中的用法:

<body ng-controller="DemoCtrl">
  <multi-select-checker>
  </multi-select-checker>
</body>

模板一:单选

<ui-select ng-model="model.choice">
    <ui-select-match>$item.Title</ui-select-match>
    <ui-select-choices repeat="item.Id as item in options.SuggestedValues | filter:  Title: $select.search ">
        <div ng-bind="item.Title | highlight: $select.search"></div>
    </ui-select-choices>
</ui-select>

模板 2:多选

<ui-select ng-model="model.choice" multiple>
    <ui-select-match>$item.Title</ui-select-match>
    <ui-select-choices repeat="item.Id as item in options.SuggestedValues | filter:  Title: $select.search ">
        <div ng-bind="item.Title | highlight: $select.search"></div>
    </ui-select-choices>
</ui-select>

如您所见,这两个模板只有一个指令不同:'multiple'。也许有更好的解决方案。

我什至不明白,为什么 ng-attr-multiple 方法不起作用。

此外,我已经意识到,有两个单独的输入字段通过 ng-attr-multiple 方法呈现。

而且单选案例似乎被打破了(通过删除多个指令) - 这也在你最初的 Plnkr 中。

工作代码

在此处查看正在运行的 Plnkr:http://plnkr.co/edit/T9e5tcAkcQLsDV3plfEl?p=preview

【讨论】:

这是一个正确的解决方案,但我想避免重复代码,这就是我首先尝试使用ng-attr 的原因。无论如何谢谢:) 您可以嵌入您的ui-select 的孩子 -> 这会减少您的重复代码。 我已经进一步调查:似乎 ng-attr-multiple 没有评估(它的内容仍然是“options.Multiple”。我检查了 ui-select 代码,它检查是否设置了 multipe 属性 - 对于 ng-attr-multiple="options.Multiple" 甚至设置 ng-attr-multiple="" 都将评估为 true (因为它只是检查如果多重属性被定义 LoC https://github.com/angular-ui/ui-select/blob/master/src/uiSelectDirective.js#L21 - 因此被呈现为多选。 更多关于您想要实现的目标的信息:github.com/angular/angular.js/issues/5524 关于您的最终解决方案,如果有人想从控制器传递一个变量(不使用 $scope),您需要创建一个隔离范围,然后编译 $parent。谢谢!【参考方案2】:

这是你想要达到的目标吗:

<body ng-controller="DemoCtrl">
    This works perfectly well:
    <ui-select ng-model="model.choice" multiple>
        <ui-select-match>$item.Title</ui-select-match>
        <ui-select-choices repeat="item.Id as item in options.SuggestedValues | filter:  Title: $select.search ">
            <div ng-bind="item.Title | highlight: $select.search"></div>
        </ui-select-choices>
    </ui-select>
    <br />
    <br />
    This does not work:
    <ui-select ng-model="model.choice2" multiple="options.Multiple">
        <ui-select-match>$item.Title</ui-select-match>
        <ui-select-choices repeat="item.Id as item in options.SuggestedValues | filter:  Title: $select.search ">
            <div ng-bind="item.Title | highlight: $select.search"></div>
        </ui-select-choices>
    </ui-select>
  </body>

【讨论】:

是的,但它不起作用。因为无论 options.Multiple 的值是什么,它总是被假定为一个多选选择。 是的,我现在明白了。似乎这是一个未解决的问题,请查看github.com/angular/angular.js/issues/7714 和 Narretz 的回答:“目前不支持绑定到多个。它被禁止,因为它会导致 select 指令出现问题。” 是的,我使用 ng-attr 指令让它工作,但它失败了。它确实添加了 multiple 属性,但它搞砸了 ui-select-match 嵌套指令:显然,它在添加 multiple 属性之前被编译,因此它的行为就像在单选 ui-select 的上下文中一样。任何想法如何解决这个问题? 对不起,伙计,我不知道如何解决这个问题。框架不支持。

以上是关于有条件地将“multiple”属性添加到 ui-select的主要内容,如果未能解决你的问题,请参考以下文章

如何有条件地将属性保存到 DFM?

如何有条件地将小部件添加到列表中?

可以使用内联语法有条件地将元素添加到数组中吗?

有条件地将 where 子句添加到 eloquent 查询

如何根据另一个组件的存在有条件地将类添加到 Magnolia 组件模板?

如何有条件地将前导零添加到一列数字?