JavaScript `bind` method does not work as expected

485 views Asked by At

The following controller works without problem.

 app.controller('foo', ['$scope',function ($scope) {
        $scope.delete = function(){
            bar($scope);
         }
    }]);

I tried to make it a little cleaner by using bind:

 app.controller('foo', ['$scope',function ($scope) {
        $scope.delete = bar.bind(null, $scope);
    }]);

Unfortunately, this form does not work as expected and $scope is always supplied with an old version of $scope in bound method (bar here), even after $scope has changed to refer to a different value. What is wrong with it?

What else?

If I should not use bind here, what is the alternative?

5

There are 5 answers

3
apsillers On BEST ANSWER

I assume that your problem is that your bound Util.bar is always supplied with an old version of $scope, even after $scope has changed to refer to a different value.

bind binds values, not variables. You are binding the current value of $scope to Util.bar. On the other hand, your first style forces the identifier $scope to be resolved to a value (or, really, outer-scope variable record) every time the function runs.

If $scope changes to refer to a completely different value, you must use the first form. .bind(null, $scope) will resolve $scope to a value immediately and use that value forever, while the first form without bind will resolve $scope to a value every time the function runs.

0
Victor On

Are you sure bar doesn't use anything from Util? Do this:

app.controller('foo', ['$scope',function ($scope) {
    $scope.delete = Util.bar.bind(Util, $scope);
}]);
0
AudioBubble On

As mentioned in apsillers answer above, the bind method is being immediately evaluated upon assignment - so $scope's current value is bound as the argument to pass to the bar function. As far as a 'cleaner' alternative, I don't see why you need something 'cleaner': you're looking to assign $scope.delete as a function that invokes bar with the current $scope value, which your current code does to a T. If you're still searching for something a bit leaner code wise you could always adopt ES6 fat arrow syntax (but you'd need a transpiler like babel)- so your code would look like:

app.controller('foo', ['$scope',function ($scope) {
    $scope.delete = () => bar($scope);
}]);
1
vinayakj On

as @apsillers said, in bind $scope gets resolved and gets used in subsequent calls,so cleaner way is the first one but still If you want to use bind then use

app.controller('foo', ['$scope',function ($scope) { 
     $scope.delete = function(){ 
         bar.bind(null, $scope); 
     }
}]); 
0
Ana F On

Have a look at this Plunker .

   $scope.delete1 = function(){
      bar($scope);
   };

   $scope.delete2 = bar.bind(null, $scope);

   $scope.delete3 = function(){
      bar(this);
   };

To me it seems to behave exactly as it should: delete1 and delete2 seem to do the same thing on both parent and child controller. Delete 3 behaves differently - the reason is explained very nicely in this answer: controller's scope

Maybe you can specify exactly which behaviour(usecase) you find wrong. The go back links are so that you can leave the controller page and then come back to new instance of controller(and a new scope - as you can see from $scope.$id).