【问题标题】:Angular Bootstrap-Select timing issue to refreshAngular Bootstrap-Select 刷新时间问题
【发布时间】:2015-04-04 20:15:48
【问题描述】:

我喜欢Bootstrap-Select,我目前正在通过另一个用户joaoneto/angular-bootstrap-select 发出的指令的帮助来使用它,它按预期工作,除非我尝试用<select> 填充<select> 元素或在我的情况是 dataService 包装器。我似乎遇到了一些时间问题,数据是在 selectpicker 显示/刷新之后出现的,然后我最终得到了一个空的 Bootstrap-Select 列表。虽然使用 Firebug,但我确实看到了现在隐藏的 @ 中的值列表987654329@。如果我然后进入控制台并手动执行$('.selectpicker').selectpicker('refresh'),它就会起作用。
我通过打补丁并在$timeout 中添加.selectpicker('refresh') 使其暂时工作,但您知道这并不理想,因为我们直接在ngController 中使用jQuery...哎哟!

因此,我认为该指令可能缺少观察者,或者至少缺少触发 ngModel 更改或更新的东西。

Html示例代码:

<div class="col-sm-5">
    <select name="language" class="form-control show-tick" 
        ng-model="vm.profile.language" 
        selectpicker data-live-search="true"
        ng-options="language.value as language.name for language in vm.languages">
    </select>
    <!-- also tried with an ng-repeat, which has the same effect -->
</div>

然后在我的 Angular 控制器中:

// get list of languages from DB
dataService
    .getLanguages()
    .then(function(data) {  
        vm.languages = data;

        // need a timeout patch to properly refresh the Bootstrap-Select selectpicker 
        // not so good to use this inside an ngController but it's the only working way I have found
        $timeout(function() {
            $('.selectpicker, select[selectpicker]').selectpicker('refresh');
        }, 1);
    }); 

这是 (joaoneto) 在GitHub for Angular-Bootstrap-Select 上发出的指令

function selectpickerDirective($parse, $timeout) {
  return {
    restrict: 'A',
    priority: 1000,
    link: function (scope, element, attrs) {
      function refresh(newVal) {
        scope.$applyAsync(function () {
          if (attrs.ngOptions && /track by/.test(attrs.ngOptions)) element.val(newVal);
          element.selectpicker('refresh');
        });
      }

      attrs.$observe('spTheme', function (val) {
        $timeout(function () {
          element.data('selectpicker').$button.removeClass(function (i, c) {
            return (c.match(/(^|\s)?btn-\S+/g) || []).join(' ');
          });
          element.selectpicker('setStyle', val);
        });
      });

      $timeout(function () {
        element.selectpicker($parse(attrs.selectpicker)());
        element.selectpicker('refresh');
      });

      if (attrs.ngModel) {
        scope.$watch(attrs.ngModel, refresh, true);
      }

      if (attrs.ngDisabled) {
        scope.$watch(attrs.ngDisabled, refresh, true);
      }

      scope.$on('$destroy', function () {
        $timeout(function () {
          element.selectpicker('destroy');
        });
      });
    }
  };
}

【问题讨论】:

  • AngularJS的版本是1.3.11

标签: angularjs angularjs-directive angularjs-ng-repeat bootstrap-select


【解决方案1】:

嗯,这是一个旧的......但我不得不使用它。这是我在指令的 link(..) 函数中添加的内容:

            scope.$watch(
            _ => element[0].innerHTML,
            (newVal, oldVal) => {
                if (newVal !== oldVal)
                {
                    element.selectpicker('refresh');
                }
            }
            )

【讨论】:

    【解决方案2】:

    angular-bootstrap-select 指令的一个问题是它只监视ngModel,而不是实际填充选择中选项的对象。例如,如果vm.profile.language 默认设置为'',并且vm.languages 具有'' 选项,则选择不会更新为新选项,因为ngModel 保持不变。我在 select 中添加了一个selectModel 属性,并稍微修改了 angular-bootstrap-select 代码。

    <div class="col-sm-5">
        <select name="language" class="form-control show-tick" 
            ng-model="vm.profile.language" 
            select-model="vm.languages"
            selectpicker data-live-search="true"
            ng-options="language.value as language.name for language in vm.languages">
        </select>
    </div>
    

    然后,在 angular-bootstrap-select 代码中,我添加了

    if (attrs.selectModel) {
        scope.$watch(attrs.selectModel, refresh, true);
    }
    

    现在,当vm.languages 更新时,选择也会更新。更好的方法可能是使用ngOptions 简单地检测应该监视哪个对象,但使用此方法也允许在选择中使用ngRepeat

    编辑:

    使用selectModel 的替代方法是自动检测来自ngOptions 的要观看的对象。

    if (attrs.ngOptions && / in /.test(attrs.ngOptions)) {
        scope.$watch(attrs.ngOptions.split(' in ')[1], refresh, true);
    }
    

    编辑 2:

    与其使用refresh 函数,不如再次调用element.selectpicker('refresh'); 可能会更好,因为您只想在ngModel 更改时实际更新select 的值。我遇到了一种情况,其中选项列表正在更新,并且选择的值发生了变化,但模型没有改变,因此它与选择器不匹配。这为我解决了这个问题:

    if (attrs.ngOptions && / in /.test(attrs.ngOptions)) {
        scope.$watch(attrs.ngOptions.split(' in ')[1], function() {
            scope.$applyAsync(function () {
                element.selectpicker('refresh');
            });
        }, true);
    }
    

    【讨论】:

    • 非常有趣的概念,这给了我使用刷新甚至不需要属性的想法。由于我们已经在 ngOptions 中直接拥有对象名称,因此您只需修改指令本身并添加如下内容即可:if (attrs.ngOptions &amp;&amp; / in /.test(attrs.ngOptions) { scope.$watch(attrs.ngOptions.split(' in ')[1], refresh, true); } ... 使用此选项或更好的方式编辑您的答案,我会接受你的回答...非常感谢:)
    • 这对我来说是一个很好的解决方案,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 2019-08-27
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多