Notre application Angular est imbriquée dans une directive appelée Page, soutenue par un contrôleur, qui contient un div avec un attribut ng-bind-html-unsafe. Ceci est assigné à une variable $ scope appelée 'pageContent'. Cette variable reçoit du code HTML généré dynamiquement à partir d'une base de données. Lorsque l'utilisateur passe à la page suivante, la base de données est appelée et la propriété pageContent var est définie sur ce nouveau code HTML, qui est affiché à l'écran via ng-bind-html-unsafe. Voici le code:
directive de page
angular.module('myApp.directives')
.directive('myPage', function ($compile) {
return {
templateUrl: 'page.html',
restrict: 'E',
compile: function compile(element, attrs, transclude) {
// does nothing currently
return {
pre: function preLink(scope, element, attrs, controller) {
// does nothing currently
},
post: function postLink(scope, element, attrs, controller) {
// does nothing currently
}
}
}
};
});
modèle de directive de page ("page.html" de la propriété templateUrl ci-dessus)
<div ng-controller="PageCtrl" >
...
<!-- dynamic page content written into the div below -->
<div ng-bind-html-unsafe="pageContent" >
...
</div>
contrôleur de page
angular.module('myApp')
.controller('PageCtrl', function ($scope) {
$scope.pageContent = '';
$scope.$on( "receivedPageContent", function(event, args) {
console.log( 'new page content received after DB call' );
$scope.pageContent = args.htmlStrFromDB;
});
});
Ça marche. Nous voyons le code HTML de la page à partir de la base de données bien rendu dans le navigateur. Lorsque l'utilisateur passe à la page suivante, nous voyons le contenu de la page suivante, etc. Jusqu'ici tout va bien.
Le problème ici est que nous voulons avoir un contenu interactif à l'intérieur du contenu d'une page. Par exemple, le code HTML peut contenir une image miniature dans laquelle, lorsque l'utilisateur clique dessus, Angular devrait faire quelque chose de génial, tel que l'affichage d'une fenêtre modale contextuelle. J'ai placé Angular appels de méthode (ng-click) dans les chaînes HTML de notre base de données, mais bien sûr Angular ne reconnaîtra ni les appels de méthode, ni les directives, à moins que analyse la chaîne HTML, les reconnaît et les compile.
Dans notre DB
Contenu pour la page 1:
<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>
Contenu pour la page 2:
<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>
De retour dans le contrôleur de page, nous ajoutons ensuite la fonction $ scope correspondante:
contrôleur de page
$scope.doSomethingAwesome = function( id, action ) {
console.log( "Going to do " + action + " with "+ id );
}
Je n'arrive pas à comprendre comment appeler cette méthode 'doSomethingAwesome' à partir de la chaîne HTML à partir de la base de données. Je réalise que Angular doit analyser la chaîne HTML d'une manière ou d'une autre, mais comment? J'ai lu de vagues rumeurs sur le service $ compile et copié/collé quelques exemples, mais rien ne fonctionne. De plus, la plupart des exemples montrent que le contenu dynamique n'est défini que pendant la phase de liaison de la directive. Nous voudrions que Page reste en vie tout au long de la vie de l'application. Il reçoit, compile et affiche en permanence de nouveaux contenus au fur et à mesure que l'utilisateur navigue dans les pages.
Dans un sens abstrait, vous pouvez dire que nous essayons d’emboîter de manière dynamique des morceaux de Angular au sein d’une application Angular et que nous devons pouvoir les échanger.
J'ai lu plusieurs parties de la documentation Angular plusieurs fois, ainsi que toutes sortes d'articles de blogs et de JS Fiddled avec le code des personnes. Je ne sais pas si je me trompe complètement d'Angular ou si je manque quelque chose de simple, ou peut-être que je suis lent. En tout cas, je pourrais utiliser un conseil.
ng-bind-html-unsafe
ne restitue que le contenu en HTML. Il ne lie pas Angular scope au DOM résultant. Vous devez utiliser le service $compile
à cette fin. J'ai créé this plunker pour montrer comment utiliser $compile
pour créer une directive rendant le code HTML dynamique entré par les utilisateurs et se liant à la portée du contrôleur. La source est affichée ci-dessous.
demo.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<h1>Compile dynamic HTML</h1>
<div ng-controller="MyController">
<textarea ng-model="html"></textarea>
<div dynamic="html"></div>
</div>
</body>
</html>
script.js
var app = angular.module('app', []);
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyController($scope) {
$scope.click = function(arg) {
alert('Clicked ' + arg);
}
$scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
Dans angular 1.2.10, la ligne scope.$watch(attrs.dynamic, function(html) {
renvoyait une erreur de caractère non valide car elle essayait de surveiller la valeur de attrs.dynamic
qui était du texte HTML.
J'ai corrigé cela en récupérant l'attribut depuis la propriété scope
scope: { dynamic: '=dynamic'},
Mon exemple
angular.module('app')
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'dynamic' , function(html){
element.html(html);
$compile(element.contents())(scope);
});
}
};
});
Trouvé dans un groupe de discussion google. Travaille pour moi.
var $injector = angular.injector(['ng', 'myApp']);
$injector.invoke(function($rootScope, $compile) {
$compile(element)($rootScope);
});
Vous pouvez utiliser
ng-bind-html https://docs.angularjs.org/api/ng/service/ $ sce
directive pour lier le HTML dynamiquement. Cependant, vous devez obtenir les données via le service $ sce.
S'il vous plaît voir la démo en direct à http://plnkr.co/edit/k4s3Bx
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$sce) {
$scope.getHtml=function(){
return $sce.trustAsHtml("<b>Hi Rupesh hi <u>dfdfdfdf</u>!</b>sdafsdfsdf<button>dfdfasdf</button>");
}
});
<body ng-controller="MainCtrl">
<span ng-bind-html="getHtml()"></span>
</body>
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'attrs.dynamic' , function(html){
element.html(scope.dynamic);
$compile(element.contents())(scope);
});
}
};
});
Essayez cet élément.html (scope.dynamic); que element.html (attr.dynamic);