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

Problem

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'
      }
  }
});
Problem courtesy of: thatandrey

Solution

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);
            };
        }
    };
}]);
Solution courtesy of: dcodesmith

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.