具有Transclusion和分块数据的AngularJS指令

时间:2014-01-16 18:36:28

标签: javascript jquery angularjs

我正在尝试重新创建一个我在AngularJS中创建的jQuery插件作为指令。我在翻译方面遇到了一些问题。

jQuery Widget插件:http://plnkr.co/edit/xxZIb2DyAere7pBY6qm7?p=preview

AngularJS指令:http://plnkr.co/edit/N6f5H8oZkpNy5jbVQPgj?p=preview

-

我有一系列用户:

[
    { name: 'intellix' }, { name: 'and' }, { name: 'konoro' }, { name: 'kingdom' }, { name: 'are' }, { name: 'awesome' },{ name: 'really!' }
]

我的jQuery小部件将数据分块,因此它们分为3行并滑动它们......数据被转换为块并放入自己的容器中,如:

[
    [
        { name: 'intellix' }, { name: 'and' }, { name: 'konoro' }
    ], 
    [
        { name: 'kingdom' }, { name: 'are' }, { name: 'awesome' }
    ],
    [
        { name: 'really!' }
    ]
]

作为一名设计师或任何使用这个小部件的人,他们不应该自己分块,这就是小部件/指令应该是什么,你应该能够拥有自己的HTML ......如下: / p>

<flicker delay="1000">
    <flicker-row ng-repeat="user in users">
        <p>User: {{user.name}}</p>
    </flicker-row>
</flicker>

我想要的结果是:

<flicker delay="1000">
    <div class="container">
        <flicker-row>
            <p>User: intellix</p>
        </flicker-row>
        <flicker-row>
            <p>User: and</p>
        </flicker-row>
        <flicker-row>
            <p>User: konoro</p>
        </flicker-row>
    </div>
    <div class="container">
        <flicker-row>
            <p>User: kingdom</p>
        </flicker-row>
        <flicker-row>
            <p>User: are</p>
        </flicker-row>
        <flicker-row>
            <p>User: awesome</p>
        </flicker-row>
    </div>
    <div class="container">
        <flicker-row>
            <p>User: really</p>
        </flicker-row>
    </div>
</flicker>

ngTransclude只是将整个HTML循环遍历并将其置于闪烁指令的模板中。我想在该指令中创建3个块,然后循环遍历这些块,将HTML打印到这3个容器中。

如何转换创建范围,但不能将整个结果转储到模板中?

我试图在我的控制器中事先将数据分块并有2个控制器......但是在我的闪烁行指令中,项目还没有循环,所以我无法处理它们

<flicker delay="1000">
    <flicker-row ng-repeat="users in userChunks">
        <div class="item" ng-repeat="user in users">
            <p>{{user.name}}</p>
        </div>
    </flicker-row>
</flicker>

3 个答案:

答案 0 :(得分:3)

使用自定义Transclusion检查我的解决方案。

DEMO

JS:

.directive('flicker', function() {
  return {
    restrict: 'E',
    scope: {
      collection:"=",
      item:"@"
    },
    transclude: true,
    replace:true, //I don't want redundant tag after compilation
    template: '<div></div>',//simple template for demonstration.

    compile: function (element, attr, linker) {//the linker parameter is for custom translusion

        return function (scope, element, attr) {
          scope.$watchCollection("collection", function(collection){

            var children = element.children();

            //check if there are already elements, if so remove its scope
            for (i = 0; i < children.length; i++){           
              children.eq(i).children().eq(0).scope().$destroy();
            };

            element.html("");//clear old content

            var chunks = collection.chunk(3);//hardcode 3 for demonstration, we could pass this to the directive's scope by exposing 1 more property in the scope.

            for (i = 0; i < chunks.length; i++) {
              var div = angular.element("<div class='container'>");
              element.append(div);

              for (j=0;j<chunks[i].length;j++){
            // create a new scope for every element in the collection.
                var childScope = scope.$new();
                // pass the current element of the collection into that scope
                childScope[scope.item] = chunks[i][j];

                  linker(childScope, function(clone){
                    // clone the transcluded element, passing in the new scope.
                       div.append(clone); // add to DOM
                  });
                }
            }
          });

        };
     }
  };
})

HTML:

<flicker item="user" collection="users" >
    <flicker-row>
        <p>U: {{user.name}}</p>
    </flicker-row>
</flicker>

闪烁指令有两个参数:

  • collection:用于渲染子项的集合。
  • item:一个字符串,表示绑定的属性名称。在这种情况下,我使用user

IMO,在这种情况下,范围管理应该由<flicker>负责,因为闪烁决定了如何分块数据。 <flicker>的内部html只是动态生成的模板。

如果您需要使用ng-repeat之类的语法。试试这个:

DEMO

HTML:

<flicker repeat="user in users" >
      <flicker-row>
        <p>U: {{user.name}}</p>
      </flicker-row>
    </flicker>

JS:

.directive('flicker', function() {
  return {
    restrict: 'E',

    transclude: true,
    replace:true,
    template: '<div></div>',

    compile: function (element, attr, linker) {
        return function (scope, element, attr) {
           var match = attr.repeat.match(/^\s*(.+)\s+in\s+(.*?)\s*$/), //parse the syntax string
            itemString = match[1],
            collectionString = match[2];

          scope.$watchCollection(collectionString, function(collection){

            var children = element.children();

            //check if there are already elements, if so remove its scope
            for (i = 0; i < children.length; i++){           
              children.eq(i).children().eq(0).scope().$destroy();
            };

            element.html("");//clear old content

            var chunks = collection.chunk(3);

            for (i = 0; i < chunks.length; i++) {
              var div = angular.element("<div class='container'>");
              element.append(div);

              for (j=0;j<chunks[i].length;j++){
            // create a new scope for every element in the collection.
                var childScope = scope.$new();
                // pass the current element of the collection into that scope
                childScope[itemString] = chunks[i][j];

                  linker(childScope, function(clone){
                    // clone the transcluded element, passing in the new scope.
                       div.append(clone); // add to DOM
                  });
                }
            }
          });

        };
     }
  };
})

答案 1 :(得分:1)

您可以进行“手动”转换。

看看我的示例:Custom transclude example

答案 2 :(得分:1)

我刚试过不再发明轮子所以我在我的指令中使用了flicker.js和jquery。结果是一个易于使用的指令。希望有用。 DEMO PAGE

在视图中

 <flicker users="users"></flicker>

闪烁模板:

<section class="flicker">
    <article ng-repeat="users in chunks" class="row">
        <div class="innerSlider">
            <div class="item" ng-repeat="user in users">
                <p>U: {{user.name}}</p>
            </div>
        </div>
    </article>
</section>

脚本:

 Array.prototype.chunk = function (chunkSize) {
        var array = this;
        return [].concat.apply([],
          array.map(function (elem, i) {
              return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
          })
        );
    };

    angular.module('flicker', [])
    .controller('FlickerCtrl', function ($scope) {
        $scope.users = [
          { name: 'intellix' }, { name: 'are' }, { name: 'konoro' }, { name: 'kingdom' }, { name: 'are' }, { name: 'awesome' }, { name: 'really!' }
        ];
    })
    .directive('flicker', function ($timeout) {
        return {
            restrict: 'E',
            replace: false,
            scope: {
                users: '='
            },
            templateUrl: 'flicker-template.html',
            link: function (scope, element, attrs) {
                scope.chunks = scope.users.chunk(3);

                $timeout(function () { $('.flicker', element).flicker({}); });

            }
        };
    });