Ben Finkel
Ben Finkel

Reputation: 4803

Controller parameter is undefined in my directive link function

I'm trying to do something very simple, using the controller parameter of the link function for my directive, but it's being passed as 'undefined'. Can anyone tell me what I'm missing?

The HTML:

    <div ng-app="myApp">
        <div ng-controller="SampleCtrl" my-form >
            <p> Click count: {{ count }} </p>               
        </div>  
    </div>

The Javascript:

myApp.controller('SampleCtrl', function($scope){    
    $scope.count = 0;

    this.init = function(val) {
        $scope.count = val;
    }   
});


myApp.directive('myForm', function() {    
    var linkFn = function(scope, elem, attrs, ctrl) {

        ctrl.init(17); //Error here.  ctrl is undefined

        elem.bind('click', function() {
            scope.$apply(function(){                
                scope.count++;
            });
        });     
    };

    return linkFn;
});

Upvotes: 4

Views: 4669

Answers (3)

Amicable
Amicable

Reputation: 3091

As Dan correctly askes in his comment on the accepted answer

Why in the world should a directive have to have any direct reference to a particular controller? Aren't they supposed to be nice and portable?

You not need to reference a controller to leverage the ctrl parameter in a directive.

Instead you can use require: 'ngModel'

As the model will be defined inside a ng-controller scope value this creates your link to the controller without having to hard code the controller name.

Here's an exampled based off of a directive I use to set a form as invalid if an input file is too large.

myApp.directive('maxFileSize', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            var maxSize = Number(attrs.maxFileSize);

            var sizeHandler = function () {
                if (element.get(0).files.length) {
                    var fileSize = element.get(0).files[0].size; // in bytes
                    if (fileSize > maxSize) {
                        //console.log('file size is more than ' + maxSize + ' bytes!');

                        ctrl.$setValidity("fileSize", false);
                    } else {
                        ctrl.$setValidity("fileSize", true);
                    }
                }
            };

            element.bind('change', sizeHandler);
        }
    };
});

Upvotes: 2

Ben Finkel
Ben Finkel

Reputation: 4803

It appears that my directive has to use the Directive Definition Object to return the link function and include a reference to the Controller as the 'controller' parameter of the ddo, like so:

myApp.directive('myForm', function() {

    var linkFn = function(scope, elem, attrs, ctrl) {

        ctrl.init("17"); //This now works, due to my return below


        elem.bind('click', function() {
            scope.$apply(function(){                
                scope.count++;
            });
        });     
    };

    return {
        controller: 'SampleCtrl',
        link:linkFn};
});

Upvotes: -1

user2740086
user2740086

Reputation:

Instead of trying to work off the controller, could you work of the scope like I have done in this Plunk?

Upvotes: 1

Related Questions