简体   繁体   English

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

[英]Parse content within AngularJS directive before rendering template

I have an element on the page that has been rendered by the server. 我在页面上有一个由服务器呈现的元素。 Let's call it a playlist . 我们称之为播放列表 It's going to be a directive. 这将是一个指令。
<div playlist></div>

A playlist contains a number of tracks before Angular compile time. 播放列表在Angular编译时间之前包含许多曲目
<div class="Track" data-track-name="Pompeii" data-*="etc">...</div>

Once the page is loaded I'm including AngularJS and parsing playlist and a directive. 加载页面后,我将包括AngularJS并解析播放列表和指令。

When I initialise the playlist directive, I'd like to loop through it's contents before compiling it's template and using the data collected to draw track directives in an ng-repeat directive belonging to the playlist directive. 当我初始化播放列表指令时,我想在编译它的模板之前循环遍历它的内容,并使用收集的数据在属于播放列表指令的ng-repeat指令中绘制轨道指令。

Questions: 问题:

  1. Is there native functionality for parsing content before the template replaces any content within the directive tag? 在模板替换指令标记内的任何内容之前,是否存在用于解析内容的本机功能? Once I'm in the directive controller the content has already been replaced. 一旦我进入指令控制器,内容就已经被替换了。

  2. Is there a better solution to my problem? 我的问题有更好的解决方案吗? I unfortunately have to use content already rendered on the page as a data-source as a solution to a whole bunch of requirements for this project 遗憾的是,我不得不使用已在页面上呈现的内容作为数据源,作为该项目的大量需求的解决方案

  3. Could I use a track directive within my content from the server to avoid DOM manipulation? 我可以在服务器的内容中使用track指令来避免DOM操作吗?

Extra explanation 额外的解释

Before compile: 在编译之前:

<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>

After compile: 编译后:

<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>

Assuming this is your data structure, you could easily do this all without a directive: 假设这是您的数据结构,您可以在没有指令的情况下轻松完成所有操作:

Data Structure/Controller 数据结构/控制器

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'] }
];
}

Template: 模板:

<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>

[edits] [编辑]

Since you need to parse the DOM, you can use this directive to do it. 由于您需要解析DOM,因此可以使用此指令来执行此操作。 It will parse the DOM and place it into a controller scope array. 它将解析DOM并将其放入控制器范围数组中。 You can then pass this scope into a template or template URL. 然后,您可以将此范围传递到模板或模板URL中。 Use any jQuery you need to wipe the original DOM. 使用你需要的任何jQuery擦除原始DOM。 jsFiddle 的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 = [];
        }
    }
});

[edit #2] Including Beyer's suggestions. [编辑#2]包括拜尔的建议。 Adding this in case someone finds this useful in the future. 添加此项以防将来有人发现这有用。 jsFiddle 的jsfiddle

Template: 模板:

<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>

Directive: 指示:

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 = [];
        }
    }
});

I've found a solution that I'm super happy with using ngTransclude . 我找到了一个使用ngTransclude非常满意的解决方案。

I write my content from the server for the tracks in their directive form: 我从服务器以指令形式为轨道编写我的内容:

<div track track-id="245" track-name="Pompeii" track-duration="3.24">Pompeii</div>

And in my playlist template, I use a <div ng-transclude></div> directive that takes the content of the playlist from the original DOM, parses it as individual directives and is injected into the specified part of the playlist template. 在我的播放列表模板中,我使用了一个<div ng-transclude></div>指令,该指令从原始DOM中获取播放列表的内容,将其解析为单独的指令并注入到播放列表模板的指定部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM