2

我正在尝试为 bootstrap-select 创建一个指令:

http://silviomoreto.github.io/bootstrap-select/(它允许创建漂亮的选择)

根据以下教程,将 jquery 插件转换为 angular 指令应该是一项简单的任务:http ://www.youtube.com/watch?v=9Bu73oQQSio 但事实上它不是目前我被困在我的第一步,我无法让最基本的功能正常工作。我尝试了不同的方法:

<select multiple selectpicker>
  <option selectpickeroption ng-repeat="MyModel in MyModels">
    {{ MyModel.MyProperty }}
  </option>
</select>

<selectpicker multiple="multiple">
    <option ng-repeat="MyModel in MyModels">
        {{ MyModel.MyProperty }}
    </option>
</selectpicker>

和...一起

Application.directive('selectpicker', [function () {
    return {
        restrict: 'A',
        compile: function() {
            return function(scope, element, attributes, controller) {
                element.selectpicker(); // launch `.selectpicker()` plugin
                // Lunching selectpicker at current point is way to early,
                // at this point all <option ng-repeat="MyModel in MyModels">..</option>
                // contain the following text `{{ MyModel.MyProperty }}`
            };
        }
    };
}]);

但是它们都不起作用,它只是不想集成到 Angular 中。有没有一种简单的方法可以以最小的努力将这个简单的插件包装成角度?因为我花了半天时间试图让它发挥作用

:(

4

2 回答 2

2

这是一个时间问题 - 您的selectpicker指令在<option>创建元素之前运行。

要解决这个问题,您需要延迟调用,element.selectpicker()直到<option>元素创建完成。

回复评论:

@Lu4 #1:你是对的,通常在 Angular 中可以避免使用$timeout. 我已经更新了要使用的答案$watch(如果您使用的是 Angular 1.2+,那么您可能想要使用$watchCollection)。

@dluz #2:据我所知,$timeout对于这种情况来说足够可靠,但是更新后的答案应该解决对此的任何担忧。

在这里使用document.ready()是不合适的,因为这与加载页面的浏览器状态有关,而不是 Angular 如何与 DOM 一起工作。因为我们的 Angular 代码已经在运行,所以我们知道 ready 事件已经触发——document.ready()必须在 Angular 运行之前触发。

Lu4 遇到的问题与 Angular 如何处理指令有关 - 它从外向内对每个元素进行操作,在移动到子元素及其指令之前初始化所有指令(为简单起见,我们忽略terminal指令)。所以当selectpicker指令被调用时,Angular 还没有处理子元素。

更新答案:

更新您的 HTML 以MyModels作为您要观看的集合传递给 selectpicker 指令。

<select multiple selectpicker="MyModels">
    ...
</select>

然后更新指令以在属性$watch值上设置一个。selectpicker

从我的快速测试来看,$watch一旦 DOM 被更新并且你应该能够调用selectpicker().

myApp.directive('selectpicker', [
    return {
        function(){
            restrict: 'A',
            scope: true,
            link: function(scope, element, iAttrs, controller){
                console.log('selectpicker::link: element=', element.eq(0).children().length);
                
                scope.$watchCollection(iAttrs['selectpicker'], function(newValue){
                    console.log('selectpicker::$watch: element=',  element.eq(0).children().length);
                    element.selectpicker();
                });
            }
        };
    }]);

使用这种方法,$watch当在范围上设置集合或替换集合时,将触发。在 Angular 1.2 中,您应该使用$watchCollection,以便在数组中的项目数量发生变化时通知您。


原答案:

为了解决这个问题,您需要使用该$timeout服务将您的呼叫延迟element.selectpicker()到下一个“滴答”。

myApp.directive('selectpicker', ['$timeout',
    function($timeout){
        return {
            restrict: 'A',
            link: function(scope, element, iAttrs, controller){
                // Log the number of children of the <select>.
                // This will be 0 because Angular hasn't processed the children yet.
                console.log('selectpicker::link: element=', element.eq(0).children().length);
                
                var initSelectpicker = function(){
                    // Now the children have been created.
                    console.log('selectpicker::init: element=', element.eq(0).children().length);
                    
                    element.selectpicker();
                }
                
                $timeout(initSelectpicker, 0, false);
            }
        };
    }]);

这应该让事情开始,但你必须小心 - 如果MyModels发生变化,那么你将不得不确保 selectpicker 也保持最新。

于 2013-10-18T03:46:22.760 回答
1

您需要使用link:指令的功能调用插件。在链接阶段,您只能在元素上注册任何侦听器并使用范围设置任何监视。(不是编译阶段)

如果您仔细查看您提到的 YouTube 视频教程,他会在link:函数内完成所有操作。

 myApp.directive('selectpicker', [function () {
        return {
            restrict: 'A',
            link: function (scope, element, iAttrs, controller) { 

              console.log(element);
              element.selectpicker(); 

            }

        };
    }]);

compile通常,如果您需要转换/更改模板的 DOM 元素,则只需要使用阶段。另一方面,该link函数将允许指令在特定克隆的 DOM 元素实例上注册侦听器,以及将内容从范围复制到 DOM。

您可以在这里找到更多信息 - http://docs.angularjs.org/guide/directive

于 2013-10-17T23:25:36.237 回答