Search code examples
javascriptangularjsangularjs-scopeangular-directive-link

$compile not updating dynamically generated html runtime


Here is jsfiddle: https://jsfiddle.net/vikramkute/eq3zpmp9/5/

I am new to angular. I have an object which needs to be appended runtime in html. I am using angular 1.2.25

Expected output is

1 Quest
2 Quest
3 Quest

but I am getting last value repeated three times. As per my trial and error, I feel problem is with $compile. I tried different solutions provided on different forums but nothing worked. Any help much appreciated. Thanks.

In Directive (within link function)

            scope.obj =
            [
                {
                    "questionText": "1 Quest"
                },
                {
                    "questionText": "2 Quest"
                },
                {
                    "questionText": "3 Quest"
                }
            ]

            scope.addData = function() {
                for (var i = 0; i < scope.obj.length; i++) {
                    addSlide(scope.obj[i]);
                }
            }

           addSlide = function (obj) {
               scope.singleObj = obj;
               el = $('<div ng-bind="singleObj.questionText"></div>');
               scope.owl.append(el);
               $compile(el)(scope);
           };

Output:

3 Quest
3 Quest
3 Quest

Here is full directive:

angular.module('journeycarousel', [])
    .directive('journeyCarousel', function ($compile) {
        return {
            restrict: 'E',
            templateUrl: '../components/journeyCarousel/journeyCarousel.html',
            transclude: true,
            link: function (scope, element) {

                scope.obj =
                    [
                        {
                            "questionText": "1 Quest"
                        },
                        {
                            "questionText": "2 Quest"
                        },
                        {
                            "questionText": "3 Quest"
                        }
                    ]

                scope.addData = function() {
                    for (var i = 0; i < scope.obj.length; i++) {
                        addSlide(scope.obj[i]);
                    }
                }

                addSlide = function (obj) {
                    scope.singleObj = obj;
                    el = $('<div ng-bind="singleObj.questionText"></div>');
                    scope.owl.append(el);
                    $compile(el)(scope);
                };
            }
        }
    });

Above code is simplified version. This is actual code:

    scope.singleObj = obj;
    el = $('<div class="questionContainer" <div ng-repeat="obj in singleObj"> ng-click="onSlideClick($event,singleObj)"> <div class="item"> <div class="questionSection" ng-bind="singleObj.questionText"></div> <div class="answerSection" ng-bind="singleObj.questionAnswer + singleObj.questionUnitOfMeasure"></div> </div> </div>');
   $('.owl-carousel').owlCarousel('add', el).owlCarousel('update');
   $compile(el)(scope);

Solution

  • I believe the reason your output is

    3 Quest
    3 Quest
    3 Quest
    

    because digest cycle kicks in only after for loop is executed for 3 times in your case. So, by the end of the 3rd iteration

    scope.singleObj 
    

    will always be

    {
         "questionText": "3 Quest"
    }
    

    So, all of the complied elements will always refer to same scope.singleObj

    to get rid of that you can do

    $scope.singleObj = [];
    var addSlide = function(obj, i) {
        $scope.singleObj.push(obj);
        var ele = '<div ng-bind=\"singleObj[' + i + '].questionText"></div>'
        el = $(ele);
        $("#container").append(el);
        $compile(el)($scope);
    };
    
    $scope.addData = function() {
        for (var i = 0; i < $scope.newCarouselSlideData.length; i++) {
            addSlide($scope.newCarouselSlideData[i], i);
        }
    }