AngularUI Bootstrap version ^2.4.22
AngularJS version 1.6.4
Angular Sanitize version ^1.6.1
I'm having trouble using AngularUI Bootstrap's Carousel plugin. In my scenario, i need to read an external file containing some template paths, and load each of them as a slide. See example below:
index.html (where directive is being called)
<body id="body" ng-app="homePage">
<div id="miolo">
<div example-directive class="ng-hide"></div>
<div banner-rotativo></div>
<div id="menu-footer"></div>
</div>
</body>
banner-rotativo.directive.js - Basically, in this directive, I have a template following the structure of AngularUI Bootstrap's demo, and i'm binding the response data to $scope.slides
array. When i push into htmlContent
property the $compile(objResponseInner)($scope)
result, the carousel behavior works okay, but it renders [[object HTMLDivElement]] and things like that as an item.
angular.module('homePage')
.directive('bannerRotativo', ['$compile', '$http', 'moduleUrl', '$templateRequest', function ($compile, $http, moduleUrl, $templateRequest) {
return {
template: '<div style="height: 305px" ng-controller="bannerHomeController" class="" >\
<div uib-carousel active="active" interval="myInterval" no-wrap="noWrapSlides">\
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">\
<div ng-bind-html="slide.htmlContent">\
</div>\
</div>\
</div>\
</div>',
link: function (scope, element, attributes, controller) {
//Carousel
scope.myInterval = 5000;
scope.noWrapSlides = false;
scope.active = 0;
scope.slides = [];
var intCurrentIndex = 0;
$http({
method: 'GET',
url: moduleUrl.getUrl('homepage', '../config/banner-rotativo.conf')
}).then(function success(objResponse, status, headers, config) {
var objData = objResponse.data;
if (objData.slides) {
angular.forEach(objData.slides, function (objItem, strObjectName) {
var strTemplatePath = moduleUrl.getUrl('homepage', '..' + objItem.caminho);
if (strTemplatePath) {
$templateRequest(strTemplatePath).then(function success(objResponseInner) {
var objContent = $compile(objResponseInner)(scope);
scope.slides.push({
htmlContent: objContent,
id: intCurrentIndex++
});
});
}
});
}
});
}
}
}]);
banner-rotativo.conf
{
"slides": {
"banner-ex-one": {
"titulo": "exone",
"caminho-imagem": "assets/one.jpg",
"caminho": "/html/components/banner-rotativo/banner-ex-one.view.html"
},
"banner-ex-two" : {
"titulo": "extwo",
"caminho-imagem": "assets/two.jpg",
"caminho": "/html/components/banner-rotativo/banner-ex-two.view.html"
},
"banner-rav" : {
"title": "rav",
"caminho-imagem": "assets/rav.jpg",
"caminho": "/html/components/banner-rotativo/banner-rav.view.html"
},
"banner-aviso" : {
"title": "Quadro de comunicações 1",
"caminho-imagem": "assets/aviso.jpg",
"caminho": "/html/components/banner-rotativo/banner-aviso.view.html"
},
"banner-custom" : {
"title": "Quadro de comunicações 2",
"caminho-imagem": "assets/custom.jpg",
"caminho": "/html/components/banner-rotativo/banner-custom.view.html"
}
}
}
Loaded template example:
<div id="frameOne" ng-controller="slideOneController" class="varejo-clique-promocao-one" title="Conteúdo Varejo - Quadro One">
<div class="item">
<div id="dados">
<!-- Imagem banner one -->
<img id="one" ng-click="enviarFormOne()" class="one" alt="" ng-if="1==1" ng-src="caminhoImagem"
/>
<!-- End imagem banner -->
<span ng-if="hasText">{{bannerText}}</span>
</div>
<div id="excecao" class="excecao" ng-if="typeof(one.excecao) !== 'undefined'">
DEU EXCECAO
</div>
<div class="carousel-title" id="tituloOne" ng-if="1==1" title="{{bannerTitle}}">
{{bannerTitle}}
</div>
</div>
Some important points:
$compile
because my injected templates have controllers too. If i don't use it, my controllers aren't processed. When i simply insert the HTML without the $compile
, it renders okay.What's wrong?
The problem is that ng-bind-html
expects html string and you are giving it the result from $compile
that is actually an element object. You could take the HTML string from the compiled element and pass that instead, but you would probably run into all kind of trouble with that.
But you can actually just skip the hassle with $compile
by using ngInclude instead of ng-bind-html. It will handle both the template request and the compilation for you.
So instead of requesting and compiling strTemplatePath
, store that to the slide list:
var strTemplatePath = moduleUrl.getUrl('homepage', '..' + objItem.caminho);
if (strTemplatePath) {
scope.slides.push({
htmlUrl: strTemplatePath,
id: intCurrentIndex++
});
}
And then use that in the template:
<div uib-slide ng-repeat="slide in slides track by slide.id" index="slide.id">
<div ng-include="slide.htmlUrl"></div>
</div>
Here's a somewhat working fiddle: jsfiddle.net, although I had to fill in a few blanks here and there.