在渲染模板之前解析 AngularJS 指令中的内容

Ale*_*lex 5 javascript angularjs angularjs-directive

我的页面上有一个由服务器呈现的元素。我们称其为播放列表。这将是一个指令。
<div playlist></div>

播放列表包含Angular 编译时间之前的许多曲目。
<div class="Track" data-track-name="Pompeii" data-*="etc">...</div>

页面加载后,我将包含 AngularJS 并解析播放列表和指令。

当我初始化播放列表指令时,我想在编译它的模板之前循环遍历它的内容,并使用收集的数据在属于播放列表指令的指令中绘制轨道指令。 ng-repeat

问题:

  1. 在模板替换指令标记中的任何内容之前,是否有用于解析内容的本机功能?一旦我进入指令控制器,内容就已经被替换了。

  2. 对于我的问题有更好的解决方案吗?不幸的是,我必须使用页面上已经呈现的内容作为数据源,作为该项目的一大堆需求的解决方案

  3. 我可以在服务器内容中使用 track 指令来避免 DOM 操作吗?

额外说明

编译前:

<div playlist>
   <div class="Track" data-track-name="Pompeii">Pompeii</div>
   <div class="Track" data-track-name="Weight of living">Weight of living</div>
</div>
Run Code Online (Sandbox Code Playgroud)

编译后:

<div playlist>
   <!-- from playlist template -->
   <div class="Playlist">
       <div class="Playlist-controls">....</div>
       <div class="Playlist-tracks">
           <div track ng-repeat="track in tracks">
               <!-- from track template -->
               <div class="Track">...</div>
            </div>
       </div>

   </div>
</div>
Run Code Online (Sandbox Code Playgroud)

Pet*_*ete 5

假设这是您的数据结构,您可以轻松地在没有指令的情况下完成这一切:

数据结构/控制器

function ctrl($scope) {
$scope.Playlists = [
  { name: 'Playlist 1', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] },
  { name: 'Playlist 2', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] },
  ...
  { name: 'Playlist n', tracks: [ 'Track 1', 'Track 2', ..., 'Track n'] }
];
}
Run Code Online (Sandbox Code Playgroud)

模板:

<div ng-controller="ctrl">
  <div ng-repeat="playlist in Playlists">
    <div> {{ playlist.name }} </div>
    <div ng-repeat="track in playlist.tracks">
       {{ track }}
    </div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

[编辑]

由于您需要解析 DOM,因此可以使用此指令来完成它。它将解析 DOM 并将其放入控制器范围数组中。然后,您可以将此范围传递到模板或模板 URL 中。使用任何您需要的 jQuery 来擦除原始 DOM。jsFiddle

var myApp = angular.module('myApp',[]);

myApp.directive('playlist', function() {
    return {
        restrict: 'A',
        scope: false,
        link: {
            pre: function(scope, element) {
                $('.Track').each(function(index, ele) {
                   scope.tracks.push($(ele).attr('data-track-name')); 
                });
                console.log(scope.tracks);
            },
            post: function(scope, element) {
              // do any compiling, etc...    
            }
        },
        controller: function($scope, $element) {
            $scope.tracks = [];
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

[编辑#2] 包括拜尔的建议。添加这个以防将来有人发现它有用。jsFiddle

模板:

<div ng-app="myApp">
    <script type="text/ng-template" id="tpl.html">
        <div>My playlist controls</div>
        <div ng-repeat="track in tracks">
           {{ track }}
        </div>
   </script>
    <div playlist>
       <div class="Track" data-track-name="Pompeii">Pompeii</div>
       <div class="Track" data-track-name="Weight of living">Weight of living</div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

指示:

var myApp = angular.module('myApp',[]);

myApp.directive('playlist', function($compile, $templateCache) {
    var extractData = function(scope) {
        $('.Track').each(function(index, ele) {
            scope.tracks.push($(ele).attr('data-track-name'));
        });
    }

    return {
        replace: true,
        restrict: 'A',
        compile: function(ele, attr, ctrl) {
            return {
              pre: function preLink(scope, ele, attr, ctrl) {
                  extractData(scope);
              },
              post: function postLink(scope, ele, attr, ctrl) {
                  ele.html($templateCache.get("tpl.html"));
                  $compile(ele.contents())(scope);
              }
            }
        },
        controller: function($scope, $element) {
            $scope.tracks = [];
        }
    }
});
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 0

我找到了一个我非常喜欢使用ngTransclude 的解决方案。

我从服务器以指令形式编写曲目的内容:

<div track track-id="245" track-name="Pompeii" track-duration="3.24">Pompeii</div>
Run Code Online (Sandbox Code Playgroud)

在我的播放列表模板中,我使用一个指令,该指令从原始 DOM 中获取播放列表<div ng-transclude></div>的内容,将其解析为单独的指令,然后注入到播放列表模板的指定部分中。