J'ai une page à onglets avec plusieurs onglets qui cliquent une fois sur appeler un service pour renvoyer des données. Certaines de ces données renvoient des formulaires HTML et sont très aléatoires. Je souhaite collecter les valeurs saisies et renvoyer les données via un service au serveur. Le problème que j'ai est que je ne peux pas obtenir les données des éléments d'entrée dans le code HTML que je crée de manière dynamique.
J'ai créé un Plunker pour montrer quel est le problème. Notez que la valeur HTML peut changer à tout moment, donc le codage en dur du HTML ne fonctionnera pas. Voici le code du plunker, mais s'il vous plaît regardez le plunker pour la meilleure vue de ce qui se passe.
app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $sce, $compile) {
$scope.name = 'World';
$scope.html = "";
$scope.htmlElement = function(){
var html = "<input type='text' ng-model='html'></input>";
return $sce.trustAsHtml(html);
}
});
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div ng-bind-html="htmlElement()"></div>
{{html}}
</body>
</html>
Une solution consisterait à utiliser ngInclude avec $ templateCache, comme indiqué dans ce document Plunker .
Il y a quelques choses à noter.
La première est que vous pouvez récupérer votre modèle en utilisant un service et l'ajouter à $ templateCache, comme décrit ici (exemple copié):
myApp.service('myTemplateService', ['$http', '$templateCache', function ($http, $templateCache) {
$http(/* ... */).then(function (result) {
$templateCache.put('my-dynamic-template', result);
});
}]);
Ensuite, vous pouvez l'inclure dans votre modèle comme suit:
<div ng-include="'my-dynamic-template'"></div>
ngInclude autorisera la liaison de données sur la chaîne html, vous n'avez donc pas besoin de ngBindHtml.
La seconde est que, lorsque ngInclude crée une nouvelle portée, accéder à la propriété html
en dehors de la portée nouvellement créée ne fonctionnera pas correctement, sauf si vous y accédez via un objet de la portée parent (par exemple, ng-model="data.html"
au lieu de ng-model="html"
. Notez que le $scope.data = {}
dans la portée parente est ce qui rend le code HTML accessible en dehors de la portée ngInclude dans ce cas.
(Voir cette réponse pour plus d’informations sur les raisons pour lesquelles vous devriez toujours utiliser un point dans vos ngModels.)
Modifier
Comme vous l'avez souligné, l'option ngInclude est beaucoup moins utile lors de l'utilisation d'un service pour renvoyer le code HTML.
Voici l'édition plunker avec une solution basée sur des directives qui utilise $ compile, comme dans le commentaire de David ci-dessus.
L'addition pertinente:
app.directive('customHtml', function($compile, $http){
return {
link: function(scope, element, attrs) {
$http.get('template.html').then(function (result) {
element.replaceWith($compile(result.data)(scope));
});
}
}
})
Sur la base de la réponse de Sarah, j'ai créé une structure pour mettre la directive
.directive('dynamic', function(AmazonService, $compile) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
AmazonService.getHTML()
.then(function(result){
element.replaceWith($compile(result.data)(scope));
})
.catch(function(error){
console.log(error);
});
}
};
});
Et dans le HTML:
<dynamic></dynamic>
Merci Sarah, beaucoup aidé !!!
J'ai une table dinamyc avec des répétitions de ng, puis quand j'ai essayé de remplir une colonne avec la fonction de rappel javascript, elle me donne juste en texte HTML
<td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
<td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
<td class="tableList_"+myValue> "span class=someclass> some_text /span>" </td>
J'ai donc résolu mon problème avec jQuery:
$(".tableListFilas td").each(function(){
var td_class = $(this).attr("class");
if(td_class == 'tableList_'+titulo)
{
**var toExtraHtml = $(this).text();**
**$(this).html(toExtraHtml);**
}
});
alors le résultat final était bon:
<td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>
<td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>
<td class="tableList_COLORS"> <span class=someclass>some_text</span> </td>