Dynamically-generated attribute not available to the controller in AngularJS

I'm absolutely stumped. I started thinking I knew what I was doing, and have now tried so many variations, I have no idea what the issue might be.

http://jsfiddle.net/PCfZV/11/

I'm creating a directive called "mylist" that I'd like to hand off some data to (in this case, a number):

<span ng-repeat="node in [1,2,3,4,5]">
    <mylist counter="{{node}}"></mylist>
</span>

So far, so good ... creating my directive works fine.

var myApp = angular.module('myApp', []);
myApp.directive('mylist', function() {
    return {
        restrict: "E",
        template: "<P>You counted to: '{{inTemplate}}'.</P>",
        replace: true,
        controller: MyCtrl,
        scope: { inTemplate: "@counter" }
    }
});

Now, when I add in my controller, I don't have any idea where to find the counter (or inTemplate) variable.

function MyCtrl($scope, $http, $attrs, $element) {
    $scope.inTemplate = "blah blah" + $attrs.counter;
}​

As always, appreciate any insight. It might just be that Angular is too much for me :)

Thanks much,

Nate

The counter is part of the directive's scope, you can see this in detail with batarang.

You should be able to reach it through $scope.inTemplate. I've meddled with your fiddle and got it working three ways:

With an attribute http://jsfiddle.net/PCfZV/46/ :

<mylist node="{{node}}"></mylist>

    template: "<P>You counted to: '{{countTo()}}'.</P>",
    replace: true,
    controller: MyCtrl,
    scope: {node: '@'}

function MyCtrl($scope, $http, $attrs, $element) {
    $scope.countTo = function(){return "blah blah" + $scope.node};
}​

With a link to the parent scope http://jsfiddle.net/PCfZV/47/ :

<mylist is-counter="node"></mylist>

    template: "<P>You counted to: '{{inTemplate}}'.</P>",
    replace: true,
    controller: MyCtrl,
    scope: {
        "isCounter": "="
    }

With an expression http://jsfiddle.net/PCfZV/48/ :

<mylist is-counter="'bla bla' + node"></mylist>

    template: "<P>You counted to: '{{isCounter()}}'.</P>",
    scope: {
        "isCounter": "&"
    }

Look also at the console.log to get some insight in the value of the attribute when the controller is instantiated.

In your post, the directive creates an "isolate scope" -- because of the line scope: { ... }. (Isolate scopes do not prototypically inherit from their parent scopes. If you want to learn more about what that means, including a picture of what an isolate scope looks like in relation to its parent scope, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?, section directives).

In your working fiddle (that you mention in the comment to @iwein), the directive does not create a new scope, but it defines a controller, so the controller and the directive are using the same scope -- so they can both see any properties that either defines on the scope. In your fiddle, is-counter="{{node}}" is not doing anything, so it can be removed and it will still work.

Also of note, for each array item/node, you are creating a separate MyCtrl controller (I'm not sure if that is intentional or not.), since the directive has the line controller: MyCtrl. Angular takes MyCtrl as the constructor function and creates a controller each time it encounters the mylist directive in the HTML (which is 5 times, due to the ng-repeat).

Normally, you'll want to specify where the controller has dominion in the HTML:

<div ng-controller="MyCtrl">
   <span ng-repeat="node in [1,2,7,6,5]">
   ...
   </span>
</div>

(There are times you might want a controller instantiated for each directive, but that is less common.)

If you use ng-controller, you don't need to specify a controller in your directive -- the directive will (by default) use the parent scope -- i.e., the same scope as the controller.

I'm not exactly sure what you are trying to do in the controller, but I would just define a property on the controller scope to hold your extra text,

$scope.extraText= "blah blah";

and then use it in the template:

template: "<P>You counted to: {{extraText}} '{{node}}'.</P>",

Fiddle.

It might just be that Angular is too much for me :)

For me, the learning curve for AngularJS was rather steep (and I'm still learning). Don't give up on it. I think it is a fantastic framework.