ng-change get new value and original value
Asked Answered
U

7

125

I'm using ng-options to select values from a pulldown. I'd like to be able to compare the old value to the new value. ng-change works well for grabbing the new value of the pull down, but how can I get both the new value and the original value?

<select ng-change="updateValue(user)" ng-model="user.id" ng-options="user.id as user.name for user in users"></select> 

For instance, let's say I wanted the controller to log, "Your former user.name was BILL, your current user name is PHILLIPE."

Unpaid answered 29/10, 2014 at 0:55 Comment(2)
check my answer here #21909663 might be duplicateHemistich
not sure how this works administratively but somehow the answers from the duplicate should be merged with this one. bresleveloper is a nice solution (from the duplicate) but TGH answer should be shown as well. The first relies on workings of framework, which could change in future, while the second is framework agnostic.Chirurgeon
B
287

With an angular {{expression}} you can add the old user or user.id value to the ng-change attribute as a literal string:

<select ng-change="updateValue(user, '{{user.id}}')" 
        ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>

On ngChange, the 1st argument to updateValue will be the new user value, the 2nd argument will be the literal that was formed when the select-tag was last updated by angular, with the old user.id value.

Bona answered 20/1, 2015 at 13:56 Comment(4)
Note that the user in method call is the one from ng-model, and not from ng-options (may be misleading). Hopefully this elegant solution will work also in future versions of angular :)Marlenmarlena
This should be considered harmful. I just came across a dirty bug occuring when user.id contains a special character (like ' or /).This is because Angular expression parser does not like expression like updateValue(user, 'blah /blah').Toshiatoshiko
In the function updateValue, $scope.user.id already contains the newly selected value - there is no need to pass a parameter for the new value to itRodmur
@LINQ2Vodka, I think it only works without the quotation marks if the user.id is numeric... it will not work if user.id is a string or a guidJo
F
17

Also you can use

<select ng-change="updateValue(user, oldValue)"     
       ng-init="oldValue=0"
       ng-focus="oldValue=user.id"
       ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>
Footwork answered 2/3, 2016 at 7:27 Comment(2)
This answer works really well of ng-repeat. You can also use ng-click instead if the element you're using this on supports ng-change but not ng-focus.Rattish
ng-init="oldValue=0" & ng-focus="oldValue=user.id" did the trick for me.Putupon
C
16

You can use something like ng-change=someMethod({{user.id}}). By keeping your value in side {{expression}} it will evaluate expression in-line and gives you current value(value before ng-change method is called).

<select ng-model="selectedValue" ng-change="change(selectedValue, '{{selectedValue}}')">
Carlenacarlene answered 1/3, 2016 at 6:23 Comment(0)
C
15

Just keep a currentValue variable in your controller that you update on every change. You can then compare that to the new value every time before you update it.'

The idea of using a watch is good as well, but I think a simple variable is the simplest and most logical solution.

Copenhagen answered 29/10, 2014 at 0:58 Comment(3)
Watch is little expensive operation , I liked the answer of db-inf .. it is simple working solutionSynchro
Best answer. If you are inside a ng-repeat, create a variable in sub-scope using ng-init.Casuist
IMHO this is the best alternative. Since retrieving old values is not provided by ngChange out-of-the-box, solutions like the one from @Bona might implode on future versions. Besides, this sounds like a controller's responsability, seems weird to delegate it to the view layer.Aggri
T
9

You can use a scope watch:

$scope.$watch('user', function(newValue, oldValue) {
  // access new and old value here
  console.log("Your former user.name was "+oldValue.name+", you're current user name is "+newValue.name+".");
});

https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

Truesdale answered 29/10, 2014 at 1:1 Comment(3)
I have come across an article that states that watch is much more dirty/inefficient compared to ng-change. benlesh.com/2013/10/title.htmlBlockish
In my experience you almost never want to use a watchDung
If programming was a subjective art you might have something there. Alas - there are many reasons why you might want to avoid ng-charge or other directive based approaches, unrelated to doing things the "angular" way.Truesdale
H
2

You could use a watch instead, because that has the old and new value, but then you're adding to the digest cycle.

I'd just keep a second variable in the controller and set that.

Heterosis answered 29/10, 2014 at 1:1 Comment(3)
This is a pretty trivial example, I'd take readability over worrying about a single watcher in this instance. Still a good thing to be weary of I suppose.Truesdale
Watch and ng-change actually have different behaviours: ng-change only detects user events, whereas $watch will fire every time the variable changes. Watchers increase complexity and are prone to creating update cycles when code changes their values.Overeager
I agree with @Rhys van der Waerden... this article states that $watch is a bit hazardous: benlesh.com/2013/10/title.htmlBlockish
B
0

You can always do:

... ng-model="file.PLIK_STATUS" ng-change="file.PLIK_STATUS = setFileStatus(file.PLIK_ID,file.PLIK_STATUS,'{{file.PLIK_STATUS}}')" ...

and in controller:

$scope.setFileStatus = function (plik_id, new_status, old_status) {
    var answer = confirm('Czy na pewno zmienić status dla pliku ?');
    if (answer) {
        podasysService.setFileStatus(plik_id, new_status).then(function (result) {
            return new_status;
        });
    }else{
        return old_status;
    }
};
Barely answered 13/11, 2020 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.