0

所以我有機會獲得一個REST API,我打,返回以下預生成的HTML返回:AngularJS:編譯內部HTML指令通過API

<p class="p"> 
    <sup id="John.3.16" class="v">16</sup> 
    <span class="wj">「For </span> 
    <span class="wj">God so loved </span> 
    <span class="wj">the world,</span> 
    <span class="wj">that he gave his only Son, that whoever believes in him should not </span> 
    <span class="wj">perish but have eternal life.</span> 
</p> 

這就提出了一個有趣的新挑戰我學習AngularJS。我無法控制從API返回的HTML,因爲它不是我創建的API。

我想要做的事(這可能是完全錯誤的做法)是在「v」類上構建一個類指令,以便我可以添加一個ng-click屬性到經文編號並通過我的應用程序的另一部分的詩歌信息。

下面是我目前擁有的代碼,雖然我認爲它會做,但它似乎沒有做任何事情。

var app = angular.module('ProjectTimothy'); 

app.filter("sanitize", ['$sce', function($sce) { 
    return function(htmlCode){ 
     return $sce.trustAsHtml(htmlCode); 
    } 
}]); 

app.controller("timothy.ctrl.search", ['$scope', '$http', function($scope, $http){ 
    $scope.url = "http://apiendpoint.com/"; 
    $scope.copyright = ""; 

    $scope.search = function() { 
     // Make the request to the API for the verse that was entered 
     // Had to modify some defaults in $http to get post to work with JSON data 
     // but this part is working well now 
     $http.post($scope.url, { "query" : $scope.searchwords, "version": "eng-ESV"}) 
     .success(function(data, status) { 
      // For now I'm just grabbing parts of the object that I know exists 
      $scope.copyright = data.response.search.result.passages[0].copyright; 
      $scope.result = data.response.search.result.passages[0].text; 
     }) 
     .error(function(data, status) { 
      $scope.data = data || "Request failed"; 
      $scope.status = status;   
     }); 

    }; 
}]); 

app.directive("v", ['$compile', function($compile) { 
    return { 
     restrict: 'C', 
     transclude: true, 
     link: function(scope, element, attrs) { 
      element.html("<ng-transclude></ng-transclude>").show(); 
      $compile(element.contents())(scope); 
     }, 
     scope: { id:'@' }, 
     /*template: "<ng-transclude></ng-transclude>",*/ 
     replace: false 
    }; 
}]); 

HTML模板被植入了由API返回的HTML:

<div class="bible_verse_search_container" ng-controller="timothy.ctrl.search"> 
    <div class="input-group"> 
     <input type="text" class="form-control" placeholder="Bible Verse To Read (i.e. John 11:35)" ng-model="searchwords"> 
     <span class="input-group-btn"> 
      <button class="btn btn-default" type="button" ng-click="search()">Search</button> 
     </span> 
    </div> 
    <div class="well" ng-show="copyright" ng-bind-html="copyright | sanitize"></div> 
    <div ng-bind-html="result | sanitize"></div> 
</div> 

所以我希望會發生將是該HTML被填充到結合的HTML底部的div,然後以某種方式調用$ compile來將「v」類sup轉換爲我可以修改的指令。再一次,我對Angular來說很新,所以可能有一種超級簡單的方法來做到這一點,就像Anguler中的其他事情一樣,我還沒有找到。

真的,最終目標是使每個節數轉換爲它自己的指令,能夠使它可點擊並訪問ID屬性,它有這樣我就可以送一些用戶內容的信息反饋給我自己的API。

這感覺就像很多的信息,所以讓我知道,如果有什麼不清楚。我會繼續努力的,所以如果我先弄明白,我一定會更新一個答案。

IN PROGRESS

經過了這樣一個問題:https://stackoverflow.com/a/21067137/1507210

現在我想知道它是否會更有意義,試圖轉換,其中的詩句顯示爲指令的部分,然後讓搜索控制器用服務器中的HTML填充一個範圍變量,然後用它作爲指令的模板... think think think

回答

1

我認爲你的第二種方法 - 將se在哪裏將詩歌顯示爲指令 - 將是一個很好的方法。有了這樣的指令

<div ng-bind-html="result | sanitize"></div> 

可以將這段

<verse-display verse-html="{{result}}"></verse-display> 

該指令的定義是這樣的:

app.directive('verseDisplay', ['$compile', function($compile) { 

    function handleClickOnVerse(e) { 
     var verseNumber = e.target.id; 

     // do what you want with the verse number here 
    } 

    return { 
     restrict: 'E', 
     scope: { 
      verseHtml: '@' 
     }, 
     replace: true, 
     transclude: false, 
     template: '<div ng-bind-html="verseHtml | sanitize"></div>', 
     link: function(scope, element, attrs) { 
      $compile(element.contents())(scope); 
      element.on('click', '.v', handleClickOnVerse); 
     } 
    }; 
}]); 

所以,你可以應用自己的單擊該元素的處理程序。

這是fiddle。 (打開控制檯查看註銷的詩句號碼。)

1

可能是我在這裏發佈的最不明智的事情,但它非常酷的代碼。我不知道是否我推薦實際運行這個,但這裏有一個jsfiddle

所以我稱之爲不明智的原因之一是因爲注入的代碼將運行任何指令,你不只是你想要的。除此之外,還可能存在許多其他安全風險。但它非常有效。如果你信任你正在檢索的HTML,那就去做吧。

退房小提琴的代碼的其餘部分:

function unwiseCompile($compile) { 
    return function (scope, element, attrs) { 
     var compileWatch = scope.$watch(
      function (scope) { return scope.$eval(attrs.unwiseCompile); }, 
      function (unwise) { 
      element.html(unwise); 
      $compile(element.contents())(scope); 
      // for better performance, compile once then un-watch 
      if (scope.onlyOnce) { 
       // un-watch 
       compileWatch(); 
      } 
      }); 
    }; 
}