簡體   English   中英

AngularJS如何創建具有HTML內容的指令?

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

我正在嘗試創建一個指令,它將加載頁面並使其在服務中可用並作為范圍,並且它將在directives元素中包含內容。

這應該是我嘗試做的非常自我解釋(簡化):

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

現在的問題是它沒有顯示{{pageData}}。 如何創建一個指令來顯示現有的標記並解析現有的標記和子指令?

這是我的指示:

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

AngularJS $ compile文檔中所述,關於transclusion

Transclusion是從DOM的一個部位提取的DOM元素的集合,將它們復制到DOM的另一部分, 同時保持它們 他們被帶到這里 原來AngularJS范圍連接的過程。

這表明transcluded元素只能訪問從中獲取的元素。 如果你想讓pageData可用,那么你必須指示你的指令的范圍定義來提供對pageData的雙向數據綁定。

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

您的問題來自您的已轉換內容的范圍。 看起來好像你的<cms-page>標簽中的html繼承了cms-page指令中的隔離范圍 - 假設它嵌套在它內部是一個公平的假設 - 但實際上它並沒有。 默認情況下,被轉換的內容將遵循其獲取的范圍。

這樣做的結果是,在實踐中,你有兩個並行的范圍 - pageData所在的指令上的隔離范圍,以及管理你的標記的原始范圍,其中pageData是未定義的(並且這個范圍是你的transcluded html被綁定的至)。 您可以采取兩種方法來糾正這個問題:

指令模板

如上所述,似乎沒有理由在此需要進行翻譯。 這似乎是一個相當規則的指令,指令html可以存在於指令本身:

HTML

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

指令

template: // the original html to be transcluded

這有一些優點:

  • 如果在多個地方需要該指令,則不需要重復嵌套標記
  • pageData固有地綁定到正確的范圍
  • 你的標記更直觀; 對於那些不熟悉你的代碼的人來說,看看你原來的html pageData變得混亂

如果需要變量模板,可以使用模板函數動態選擇一個:

HTML

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

指令

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

手動轉換

如果由於某種原因你不能使用指令模板,那么你可以自己轉換內容並將其指向你喜歡的范圍,而不是讓角度轉換你的內容(通過將其與拍攝范圍相關聯)。 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