There are a number of ways you can do this, and using $watch is certainly one of them. As mentioned by Matt, you could also use the ng-change directive to fire a method on your controller.
The third way that I would like to offer up, is to make use of ES5 properties, and the Controller 'as' syntax that Angular introduced in 1.2+
If you define your controller as a JS object instead of using an anonymous function, you can add properties and methods to the prototype:
myController = function () {
this.map = {'A': 1,'B': 2,'C': 3,'D': 4};
this._letter = 'A';
this._number = 1;
};
Now we can extract the work you have already done for getting your letter and number values into functions:
myController.prototype.getLetterValue = function (num) {
for (var key in this.map) {
if (this.map.hasOwnProperty(key)) {
if (this.map[key] === num) {
return key;
}
}
}
};
myController.prototype.getNumberValue = function (letter) {
return this.map[letter];
};
Lastly, we are going to declare a couple of properties on your controller that encapsulate the desired functionality using Object.defineProperty.
Object.defineProperty(
myController.prototype,
"letter", {
get: function () {
return this._letter;
},
set: function (newValue) {
this._letter = newValue;
this._number = this.getNumberValue(this._letter);
},
enumerable: true,
configurable: true
});
Object.defineProperty(
myController.prototype,
"number", {
get: function () {
return this._number;
},
set: function (newValue) {
this._number = newValue;
this._letter = this.getLetterValue(this._number);
},
enumerable: true,
configurable: true
});
Add this controller to your module:
angular.module("test", [])
.controller("MyController", myController);
And lastly, you just need to modify your binding syntax slightly in order to use the new Controller 'as' syntax. This will allow you to bind directly to properties and methods on your controller instead of having to use $scope
<div ng-app="test">
<div ng-controller="MyController as ctrl">
<input ng-model="ctrl.letter" />
<input type="number" ng-model="ctrl.number" />
</div>
</div>
Live Demo
Summary
This isn't exactly less code, but does have several advantages.
- Your controller is decoupled from
$scope and $watch making it more portable
- The controller code is easier to read because all the functionality isn't nested inside an anonymous function
- The code is a little more forward looking because future versions of Angular will probably eliminate
$scope and the $digest loop altogether by using native observables.