23

I want to use $compile in a controller inside a function and not in a directive. is it possible? I am trying the below code.

$compile('<div ng-attr-tooltip="test">Cancel</div>')(scope)

But this is throwing scope is undefined error. I tried to pass $scope inside the function but it is not working.

Kevin Brechbühl
  • 4,717
  • 3
  • 24
  • 47
user1673394
  • 537
  • 2
  • 6
  • 11
  • http://stackoverflow.com/questions/12546945/difference-between-the-controller-link-and-compile-functions-when-definin – BKM Mar 13 '14 at 06:24
  • http://stackoverflow.com/questions/15676614/directive-link-vs-compile-vs-controller – BKM Mar 13 '14 at 06:25
  • 1
    Could you explain why you want to compile in a controller instead of in a directive? A controller shouldn't be aware of the DOM. – Anders Ekdahl Mar 13 '14 at 07:25

5 Answers5

20

How would Angular know that you changed the DOM? You need to compile your html before appending it (using $compile service).

If you absolutely need access outside of a directive you can create an injector.

$(function() {
  // myApp for test directive to work, ng for $compile
  var $injector = angular.injector(['ng', 'myApp']);
  $injector.invoke(function($rootScope, $compile) {
    $('body').prepend($compile('<div ng-attr-tooltip="test">Cancel</div>')($rootScope));
  });
});
Vaibhav Jain
  • 33,887
  • 46
  • 110
  • 163
12

It's worth to note, the injector in previous answer (var $injector = angular.injector(['ng', 'myApp']);) will not append compiling directive to your currently running angular app, it will create new instead.

To dynamically append new directives to your app, you should use already existed injector:

$(function() {
  angular.element(document).injector().invoke(function($rootScope, $compile) {
    $('body').prepend($compile('<div ng-attr-tooltip="test">Cancel</div>')($rootScope));
  });
});

See last paragraph in documentation.

Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
idmitme
  • 899
  • 7
  • 13
5

I tried @Vaibhav Jain's answer, with no success. After a little more digging, this is what I found to work on Angular 1.3, and jQuery:

$(function() {
  angular.element(document).injector().invoke(['$compile', function ($compile) {
    // Create a scope.
    var $scope = angular.element(document.body).scope();
    // Specify what it is we'll be compiling.
    var to_compile = '<div ng-attr-tooltip="test">Cancel</div>';
    // Compile the tag, retrieving the compiled output.
    var $compiled = $compile(to_compile)($scope);
    // Ensure the scope and been signalled to digest our data.
    $scope.$digest();
    // Append the compiled output to the page.
    $compiled.appendTo(document.body);
  });
});
Joshua Burns
  • 8,268
  • 4
  • 48
  • 61
1

I did this

var SCOPE;
app_module.controller('appController', function ($scope, $compile) {
    SCOPE = $scope;
    $scope.compile = function (elem_from, elem_to) {
        var content = $compile(angular.element(elem_from))($scope);
        angular.element(elem_to).append(content);
    }
});

use like this

SCOPE.compile(elem1.content, elem2);
Inuart
  • 1,432
  • 3
  • 17
  • 28
1

I recompiled my html by the following way when I was needed to recompile my html to apply the changes on the page.

It happens when I was trying to go to other link and back again to the page but for some reason the angular code was not compiling.

So I fixed this by compiling the html part of the page again at a load event.

function OnLoad() {
angular.element("form:first").injector().invoke(['$compile', function ($compile) {
    var $scope = angular.element("form:first").scope();
    $compile("form:first")($scope);
}]);
}

Below is the app declaration.

<form ng-app="formioApp" ng-controller="formioAppCtrl">

and OnLoad() function is assigned in a html element's onload event on that page.

Khademul Basher
  • 127
  • 1
  • 2