0

In my code i need to compile html returned from another api from inside a javascript callback function.

The following is a simplified version of my code. I am using a factory method which recomplies any element using $compile and $rootScope.

The strange thing about this setup is that the compile function is making the data factory execute multiple times. What is the reason for this? And any suggestions or any flaws in this method of compiling dynamic html?

here is a plunker link http://plnkr.co/edit/D32kCS4BkslvpBsRtFoS

var app = angular.module('mainApp', []);
app.factory('CompileDirective', function($compile, $rootScope) {
  function compileApp() {
    $compile($("[ng-app='mainApp']"))($rootScope);
  }
  return {
    compileApp: compileApp
  };
});
app.factory('data', function() {
  alert("run");
  return "data";
});
app.directive('testDirective', function(data) {
  return {
    restrict: 'E',
    templateUrl: 'tpl.html'
  };
});

function addDirective() {
  $('#container').append('<test-directive></test-directive>');
  callback();
}

function callback() {
  alert('callback called');
  angular.injector(['ng', 'mainApp']).get("CompileDirective").compileApp();
}
<script data-require="angular.js@1.3.7" data-semver="1.3.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
<script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body ng-app="mainApp">
  <script type="text/ng-template" id="tpl.html">
    {{ "hello" + "world"}}
  </script>
  <h1>Hello Plunker!</h1>
  <input type="button" value="Add Directive" onClick="addDirective()" />
  <div id='container'>
    <test-directive></test-directive>
  </div>
</body>
dev
  • 3
  • 1
  • It runs every time you recompile the entire app. To avoid, recompile only the added directive. Or better yet, don't add directives or manipulate the DOM in the controller. Read this to understand how ["to think in Angular"](http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background). – New Dev Feb 01 '15 at 19:12

1 Answers1

0

personally I wouldnt put that in a factory but add a directive to compile the code or do it in the controller....

if I understood what you are trying to do correctly this is what I suggest:

for a static html you already have the ng-bind-html directive... and if you need it to be dynamic just create a directive like this

angular.module('app',[]).directive('ngHtmlCompile',function ($compile) {
  return function(scope, element, attrs) {
      scope.$watch(
        function(scope) {
           // watch the 'compile' expression for changes
          return scope.$eval(attrs.ngHtmlCompile);
        },
        function(value) {
          // when the 'compile' expression changes
          // assign it into the current DOM
          element.html(value);

          // compile the new DOM and link it to the current
          // scope.
          // NOTE: we only compile .childNodes so that
          // we don't get into infinite loop compiling ourselves
          $compile(element.contents())(scope);
        }
    );
};

});

Jony-Y
  • 1,579
  • 1
  • 13
  • 30
  • Used almost the same code mentioned above but as an attribute directive. This allowed to provide the functionality of on demand compile on any element using a function defined in the scope. – dev Mar 25 '15 at 18:12