简体   繁体   English

AngularJS如何创建具有HTML内容的指令?

[英]AngularJS how to create a directive that has HTML content?

I'm trying to create a directive that will load the page and make it available in a service and as scope and it's going to have content inside the directives element. 我正在尝试创建一个指令,它将加载页面并使其在服务中可用并作为范围,并且它将在directives元素中包含内容。

This should be pretty self-explaining (simplified) what I try to do: 这应该是我尝试做的非常自我解释(简化):

<cms-page page-id="829">
    <h1>Testing</h1>
    <ul ui-sortable ng-model="pageData.sections.main">
        <li ng-repeat="element in pageData.CmsPage.sections.main track by $index">
            <div ng-include="'/templates/cms/elements/' + element.element_type + '.html'"></div>
        </li>
    </ul>
    <pre>{{pageData | json}}</pre>
</cms-page>

The issue with that is now that it doesn't show the {{pageData}}. 现在的问题是它没有显示{{pageData}}。 How can I create a directive that will show the existing markup and parse the existing markup and child directives? 如何创建一个指令来显示现有的标记并解析现有的标记和子指令?

Here is my directive: 这是我的指示:

angular.module(cms).directive('cmsPage', ['CmsPage', 'CmsPagesService', function(CmsPage, CmsPagesService) {
    return {
        restrict: 'E',
        transclude: true,
        template: '<div ng-transclude></div>',
        scope: {
            pageId: '@pageId'
        },
        controller: function($scope) {
            $scope.pageData = {};
            CmsPagesService.get($scope.pageId).then(function(result) {
                if (result.status == 'success') {
                    $scope.pageData = result.data;
                } else {
                    throw 'Page failed to load.';
                }
            });
            $scope.$watch('pageData', function() {
                CmsPage.setPage($scope.pageData);
            });
        }
    };
}]);

As mentioned in the AngularJS $compile documentation, regarding transclusion : AngularJS $ compile文档中所述,关于transclusion

Transclusion is the process of extracting a collection of DOM element from one part of the DOM and copying them to another part of the DOM, while maintaining their connection to the original AngularJS scope from where they were taken . Transclusion是从DOM的一个部位提取的DOM元素的集合,将它们复制到DOM的另一部分, 同时保持它们 他们被带到这里 原来AngularJS范围连接的过程。

This suggests that the transcluded element only has access on the scope from which it was taken from. 这表明transcluded元素只能访问从中获取的元素。 If you want to have pageData available, then you'd have to instruct your directive's scope definition to provide two-way data binding towards pageData . 如果你想让pageData可用,那么你必须指示你的指令的范围定义来提供对pageData的双向数据绑定。

DEMO DEMO

  .directive('cmsPage', ['CmsPage', 'CmsPagesService', function(CmsPage, CmsPagesService) {
    return {
          restrict: 'E',
          transclude: true,
          template: '<div ng-transclude></div>',
          scope: {
              pageId: '@pageId',
              pageData: '='
          },
          controller: function($scope) {
              $scope.pageData = {};
              CmsPagesService.get($scope.pageId).then(function(result) {
                $scope.pageData = result.data;
              });
              $scope.$watch('pageData', function() {
                  CmsPage.setPage($scope.pageData);
              });
          }
      };
  }]);

Your problem comes from the scope to which your transcluded content is bound. 您的问题来自您的已转换内容的范围。 It might appear as though the html within your <cms-page> tag inherits the isolated scope on the cms-page directive — a fair assumption given that it's nested within it — but in actuality it does not. 看起来好像你的<cms-page>标签中的html继承了cms-page指令中的隔离范围 - 假设它嵌套在它内部是一个公平的假设 - 但实际上它并没有。 Transcluded content will, by default, respect the scope from which it was taken. 默认情况下,被转换的内容将遵循其获取的范围。

The consequence of such is that, in practice, you have two scopes in parallel - the isolated scope on the directive on which pageData exists, and the original scope governing your markup where pageData is undefined (and it's this scope that your transcluded html is bound to). 这样做的结果是,在实践中,你有两个并行的范围 - pageData所在的指令上的隔离范围,以及管理你的标记的原始范围,其中pageData是未定义的(并且这个范围是你的transcluded html被绑定的至)。 There are two approaches you could take to rectify this: 您可以采取两种方法来纠正这个问题:

Directive template 指令模板

As presented, there appears to be little reason why transclusion is needed here. 如上所述,似乎没有理由在此需要进行翻译。 This seems like a fairly regular directive whereby the directive html can exist on the directive itself: 这似乎是一个相当规则的指令,指令html可以存在于指令本身:

HTML : HTML

<cms-page page-id="829"></cms-page>

Directive : 指令

template: // the original html to be transcluded

This has a few advantages: 这有一些优点:

  • if the directive is needed in more than one place, the nested markup need not be repeated 如果在多个地方需要该指令,则不需要重复嵌套标记
  • pageData is inherently bound to the correct scope pageData固有地绑定到正确的范围
  • your markup is more intuitive; 你的标记更直观; it would be confusing to anyone unfamiliar with your code where pageData comes from by looking at your original html 对于那些不熟悉你的代码的人来说,看看你原来的html pageData变得混乱

If a variable template is required, you can select one dynamically by using the template function: 如果需要变量模板,可以使用模板函数动态选择一个:

HTML : HTML

<cms-page page-id="829" page-template="templateA"></cms-page>

Directive : 指令

template: function(tElem, tAttrs) {
  if(tAttrs.pageTemplate) {
    return '<div>...</div>';
  }  // and so on...
}

Manual Transclusion 手动转换

If for some reason you cannot use a directive template, then instead of having angular transclude your content, which it does by associating it with the scope from which it was taken, you can transclude the content yourself and point it to whichever scope you please. 如果由于某种原因你不能使用指令模板,那么你可以自己转换内容并将其指向你喜欢的范围,而不是让角度转换你的内容(通过将其与拍摄范围相关联)。 The transclude function is available as the fifth argument of the link function: transclude函数可用作链接函数的第五个参数:

transclude: true,
template: '<div></div>',
scope: {
  pageId: '@'
}
link: function(scope, elem, attrs, ctrl, transclude) {
  transclude(scope, function(clone) {
    // transcluded html is now bound to the isolated scope of the directive
    // therein making pageData accessible "externally"
    elem.append(clone);
  });
}

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

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