Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can pass a scope variable into a directive's link function, but not the compile function, angular

I'm using ng-repeat and I need to pass a scope variable into a directive's compile function. I know how to do it with the link function, but not the compile function.

My html looks like:

    <div ng-repeat="item in chapter.main">
      <block type="item.type"></block>
    </div>

Let's say item.type="blah" no matter the item. Then this link function works fine

app.directive('block', function() {
  return {
      restrict: 'E',
      link: function(scope, element, attributes){
            scope.$watch(attributes.type, function(value){
                console.log(value); //will output "blah" which is correct
            });

        }
  }
});

But I can't do the same with compile?

app.directive('block', function() {
  return {
      restrict: 'E',
      compile: function(element, attrs, scope) {
        scope.$watch(attrs.type, function(value){
             console.log(value);
         });
      }
  }
});

The error I get is "cannot read property $watch of undefined"..

This is how I'd like my directive to look like:

app.directive('block', function() {
  return {
      restrict: 'E',
      compile: function(element, attrs) {
        element.append('<div ng-include="\'{{type}}-template.html\'"></div>');
        //or element.append('<div ng-include="\'{' + attrs.type + '}-template.html\'"></div>');
        //except the above won't interpret attr.type as a variable, just as the literal string 'item.type'
      }
  }
});
like image 672
thatandrey Avatar asked Feb 16 '26 09:02

thatandrey


1 Answers

The compile function doesn't have scope as one it's parameter.

function compile(tElement, tAttrs, transclude) { ... }

NOTE: transclude is deprecated in the latest version of Angular.

Is there any reason you don't want to use link?

From the DOC

The compile function deals with transforming the template DOM. Since most directives do not do template transformation, it is not used often. The compile function takes the following arguments:

tElement - template element - The element where the directive has been declared. It is safe to do template transformation on the element and child elements only.

tAttrs - template attributes - Normalized list of attributes declared on this element shared between all directive compile functions.

transclude - [DEPRECATED!] A transclude linking function: function(scope, cloneLinkingFn)

UPDATE

To access the scope from inside compile function, you need to have either a preLink or postLink function. In your case, you need only the postLink function. So this ...

compile: function compile(tElement, tAttrs, transclude) {
    return function postLink(scope, element, attrs) { ... }
},

PROPOSED SOLUTION Might not be exact but should help you on your way.

html

<div ng-app="myApp" ng-controller="app">
    <block type="item.type"></block>
</div>

JS (Controller + Directive)

var myApp = angular.module('myApp', []);

myApp.controller('app', function ($scope, $http) {
    $scope.item = {
        type: 'someTmpl'
    };
}).directive('block', ['$compile', function ($compile) {
    return {
        restrict: 'AE',
        transclude: true,
        scope: {
            type: '='
        },
        compile: function (element, attrs) {
            return function (scope, element, attrs) {
                var tmpl;
                tmpl = scope.type + '-template.html';
                
                console.log(tmpl);
                
                element.append('<div ng-include=' + tmpl + '></div>');

                $compile(element.contents())(scope);
            };
        }
    };
}]);
like image 58
dcodesmith Avatar answered Feb 19 '26 19:02

dcodesmith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!