[jquery] AngularJS + JQuery : How to get dynamic content working in angularjs

I am working on a Ajax app using both jQuery and AngularJS.

When I update content (which contains AngularJS bindings) of a div using jQuery's html function, the AngularJS bindings doesn't work.

Following is code of what I am trying to do:

_x000D_
_x000D_
$(document).ready(function() {_x000D_
  $("#refreshButton").click(function() {_x000D_
    $("#dynamicContent").html("<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>")_x000D_
  });_x000D_
});
_x000D_
</style><script src="http://docs.angularjs.org/angular-1.0.1.min.js"></script><style>.ng-invalid {_x000D_
  border: 1px solid red;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>_x000D_
<div ng-app="">_x000D_
  <div id='dynamicContent'>_x000D_
    <button ng-click="count = count + 1" ng-init="count=0">_x000D_
        Increment_x000D_
      </button>_x000D_
    <span>count: {{count}} </span>_x000D_
  </div>_x000D_
_x000D_
_x000D_
  <button id='refreshButton'>_x000D_
    Refresh_x000D_
  </button>_x000D_
</div>
_x000D_
_x000D_
_x000D_

I have dynamic content inside a div with the ID #dynamicContent, and I have a refresh button that would update contents of this div when refresh is clicked. Increment works as expected if I don't refresh the content, but after I refresh, the AngularJS binding stops working.

This may not be valid in AngularJS, but I initially built application with jQuery and started using AngularJS later on so I can't migrate everything to AngularJS. Any help with getting this working in AngularJS is greatly appreciated.

This question is related to jquery angularjs

The answer is


Another Solution in Case You Don't Have Control Over Dynamic Content

This works if you didn't load your element through a directive (ie. like in the example in the commented jsfiddles).

Wrap up Your Content

Wrap your content in a div so that you can select it if you are using JQuery. You an also opt to use native javascript to get your element.

<div class="selector">
    <grid-filter columnname="LastNameFirstName" gridname="HomeGrid"></grid-filter>
</div>

Use Angular Injector

You can use the following code to get a reference to $compile if you don't have one.

$(".selector").each(function () {
    var content = $(this);
    angular.element(document).injector().invoke(function($compile) {
        var scope = angular.element(content).scope();
        $compile(content)(scope);
    });
});

Summary

The original post seemed to assume you had a $compile reference handy. It is obviously easy when you have the reference, but I didn't so this was the answer for me.

One Caveat of the previous code

If you are using a asp.net/mvc bundle with minify scenario you will get in trouble when you deploy in release mode. The trouble comes in the form of Uncaught Error: [$injector:unpr] which is caused by the minifier messing with the angular javascript code.

Here is the way to remedy it:

Replace the prevous code snippet with the following overload.

...
angular.element(document).injector().invoke(
[
    "$compile", function($compile) {
        var scope = angular.element(content).scope();
        $compile(content)(scope);
    }
]);
...

This caused a lot of grief for me before I pieced it together.


Addition to @jwize's answer

Because angular.element(document).injector() was giving error injector is not defined So, I have created function that you can run after AJAX call or when DOM is changed using jQuery.

  function compileAngularElement( elSelector) {

        var elSelector = (typeof elSelector == 'string') ? elSelector : null ;  
            // The new element to be added
        if (elSelector != null ) {
            var $div = $( elSelector );

                // The parent of the new element
                var $target = $("[ng-app]");

              angular.element($target).injector().invoke(['$compile', function ($compile) {
                        var $scope = angular.element($target).scope();
                        $compile($div)($scope);
                        // Finally, refresh the watch expressions in the new element
                        $scope.$apply();
                    }]);
            }

        }

use it by passing just new element's selector. like this

compileAngularElement( '.user' ) ;