Animal2 Animal2 - 2 months ago 13
Javascript Question

Controller 'uibCarousel', required by directive 'uibSlide', can't be found when wrapping

I have a directive that wraps that carousel directive. When I replace the slides object it comes up with an error saying "Controller 'uibCarousel', required by directive 'uibSlide', can't be found when wrapping."

I managed to replicate it in a plunkr. I added a simple directive as follows:

angular.module('ui.bootstrap.demo').directive('mydir', ['$compile',function($compile){
function link(scope, element, attrs) {
scope.$watch('slides', function (value) {
var template = '<uib-carousel interval="myInterval" no-wrap="noWrapSlides">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active">' +
'<img ng-src="{{slide.image}}" style="margin:auto;">' +
'<div class="carousel-caption">' +
'<h4>Slide {{$index}}</h4>' +
'<p>{{slide.text}}</p>' +
'</div>' +
'</uib-slide>' +
'</uib-carousel>;';
element.empty();
element.html(template);
$compile(element.contents())(scope);
});
}
return {
link: link,
restrict: 'E'
};
}]);


I also added this function to replace the slides:

$scope.createNewSlide = function(){
$scope.slides = [];
var newWidth = 600 + $scope.slides.length + 1;
$scope.slides.push({
image: '//placekitten.com/' + newWidth + '/300',
text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' ' +
['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4]
});
};


If you hit the replace slides button, the carousel will still appear but an error will show up in your console.
http://plnkr.co/edit/IGyaWwXGUa8n2LykMkmV?p=preview

Am I doing something that shouldn't be doing when I replace the slides object?

EDIT: One thing I did notice is that removing ng-repeat directive doesn't cause this problem. Also another observation was that angular actually compiles all the old DOM elements that have been since removed from the previous time it compiled the directive. I noticed the first time around when it was looking for required controllers by uibSlide, the element the uibSlide was actually on the DOM. When I added a new array by clicking the button, the first uibSlide that was looking for a controller was on an element that has been removed from the DOM.

Answer

I figured out how to get rid of the error which stops angular from recompiling DOM elements that are currently removed.

I changed the linker function to hold a child scope. I destroy it myself when the slides array gets changed and create a new one afterwards.

  function link(scope, element, attrs) {
    var childScope
    scope.$watch('slides', function (value) {
        var template = '<uib-carousel interval="myInterval" no-wrap="noWrapSlides">' +
        '<uib-slide ng-repeat="slide in slides" active="slide.active">' +
          '<img ng-src="{{slide.image}}" style="margin:auto;">' +
          '<div class="carousel-caption">' +
            '<h4>Slide {{$index}}</h4>' +
            '<p>{{slide.text}}</p>' +
          '</div>' +
        '</uib-slide>' +
      '</uib-carousel>;';
        element.empty();
        if(childScope)
          childScope.$destroy();
        childScope = scope.$new();
        element.html(template);
        $compile(element.contents())(childScope);
    });
  }

http://plnkr.co/edit/g7wN2LSgbT4s7mULAzoJ?p=preview

Comments