9

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?

Handsome Nerd
  • 17,114
  • 22
  • 95
  • 173
  • What's inside Util? I can't think on why would you need to do this. – Antonio Laguna Jun 09 '15 at 12:12
  • 1
    Seems a misuse of bind to me. – Shawn Erquhart Jun 09 '15 at 12:19
  • 1
    Is the problem that a value *is* being supplied to `$scope.delete`, but it's an *old* value? Or is the function just totally failing (or not being supplied a value at all)? – apsillers Jun 09 '15 at 12:19
  • @ShawnErquhart What makes you think so? – a better oliver Jun 09 '15 at 13:01
  • @apsillers "…changes in $scope is not send to binded method (bar here)." – Handsome Nerd Jun 09 '15 at 14:33
  • @zeroflagL he's using it for code cleanliness, not for explicitly defining 'this'. – Shawn Erquhart Jun 09 '15 at 14:42
  • @ShawnErquhart Defining a value for `this` is not the only valid use case. After all it's called `bind`, not `setThisArg`. – a better oliver Jun 09 '15 at 14:56
  • 1
    @PHPst Please modify this post to include an [MCVE](http://stackoverflow.com/help/mcve) – deostroll Jun 15 '15 at 07:25
  • The behaviour that you describes is the expected for me, because you are removeing the CLOSURE of that method with bind(null...) I know I'm not helping a lot, but I would recommend to check how the reference objects are passed in Javascript, how works the closure in Javascript, and what the method bind does. I guess after that you will understand exactly why the $context is not being updated Tip: Without closure that var is not related with the method anymore. – eMarine Jun 18 '15 at 14:53
  • What are you trying to do with scope before calling `delete`? I'm specifically interested in the properties you are setting. Would you share some code, or pseudocode illustrating the case? – danypype Jun 19 '15 at 01:17
  • "after $scope has changed to refer to a different value". Are you actually binding `$scope` to a different value (i.e. `$scope = {};`)? In that case `delete` will still be curried with whatever the value of `$scope` was at execution. If you need the value at call time, you'll need to keep the wrapping function. If only a property of `$scope` is changing, then `delete` should read the current value at call time. – Noah Freitas Jun 20 '15 at 23:23

5 Answers5

10

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.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • Thanks, What is the alternative method for the second codes. – Handsome Nerd Jun 10 '15 at 09:04
  • @PHPst The alternative is what you're already doing in your first example. Can you edit to explain why that is not sufficient? – apsillers Jun 15 '15 at 01:23
  • as @apsillers said in `bind` $scope gets resolved and gets used in subsequent calls cleaner way is first but still want bind then use this app.controller('foo', ['$scope',function ($scope) { $scope.delete = function(){ bar.bind(null, $scope); } }]); – vinayakj Jun 18 '15 at 20:41
4

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).

Community
  • 1
  • 1
Ana F
  • 641
  • 4
  • 13
2

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);
}]);
Victor
  • 9,210
  • 3
  • 26
  • 39
1

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

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); 
     }
}]); 
vinayakj
  • 5,591
  • 3
  • 28
  • 48