I'm learning angular and I'm trying to figure out what is the best solution to use getters/setter.
Saying, I'm using a library which exposes getters and setters (as Moment.js does).
I've tried several ways to deal with getters and setters, here they are:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Example - example-ngModel-getter-setter-production</title>
<script data-require="[email protected]" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"> </script>
<script src="app.js"></script>
</head>
<body ng-app="getterSetterExample">
<div ng-controller="ExampleController">
<form name="userForm">
Name :
<input type="text" name="userName" ng-model="user.name" ng-model-options="{ getterSetter: true }" />
<br/>Name1:
<input type="text" name="userName1" ng-model="user1.name" ng-model-options="{ getterSetter: true }" />
<br/>Name2:
<input type="text" name="userName2" ng-model="user2.name" ng-model-options="{ getterSetter: true }" />
<br/>Name3:
<input type="text" name="userName3" ng-model="user3.name" ng-model-options="{ getterSetter: true }" />
</form>
<pre>user.name = <span ng-bind="user.name()"></span>
</pre>
<pre>user1.name = <span ng-bind="user1.name()"></span>
</pre>
<pre>user2.name = <span ng-bind="user2.name()"></span>
</pre>
<pre>user3.name = <span ng-bind="user3.name()"></span>
</pre>
</div>
</body>
</html>
app.js
angular.module('getterSetterExample', [])
.controller('ExampleController', ['$scope',
function($scope) {
var _name = 'Brian';
var _name3 = 'Joe';
var name1 = {
_name: 'George',
name:function(newName) {
if (angular.isDefined(newName)) {
this._name = newName;
}
return this._name;
}
};
var name2 = {
_name: 'Michael',
name:function(newName) {
if (angular.isDefined(newName)) {
this._name = newName;
}
return this._name;
}
};
var name3 = {
name:function(newName) {
if (angular.isDefined(newName)) {
_name3 = newName;
}
return _name3;
}
};
$scope.user = {
name: function(newName) {
if (angular.isDefined(newName)) {
_name = newName;
}
return _name;
}
};
$scope.user1 = {
name: name1.name
};
$scope.user2 = {
name: function(newName) {
return name2.name(newName);
}
};
$scope.user3 = {
name: name3.name
};
}
]);
You can try it here: http://plnkr.co/edit/S1qKre9umNpLOt0sjpZf?p=preview
2 Questions:
user1 tries to direcly use the getter/setter provided by the name1 objet, it doesn't work properly, can you explain why?
Is there a way to avoid to rewrite a "proxy" for each getter/setter as I've done in user3? what would be the best method to use getters/setters provided by an external library?
Thank for your help
1 Answer 1
user1 tries to direcly use the getter/setter provided by the name1 objet, it doesn't work properly, can you explain why?
The issue is with the context, You are just merely copying the function reference name1.name by doing:-
$scope.user1 = {
name: name1.name
};
so when it is run this in the getter will actually point to the window/global (in non strict mode). You can workaround this by using Function.bind.
Example:-
$scope.user1 = {
name: name1.name.bind(name1)
};
Is there a way to avoid to rewrite a "proxy" for each getter/setter as I've done in user3?
I would just create a wrapper so that i don't run into context issues like these.
$scope.user = getModel('name', 'Brian');
$scope.user1 = getModel('name', 'George');
$scope.user2 = getModel('name', 'Michael');
$scope.user3 = getModel('name', 'Joe');
$scope.address = getModel('address');
//You can improve this by passing an optional getter functionality as well for some specific evaluation on the value when set.
function getModel(propertyName, defValue) {
var obj = {};
obj._defVal = defValue;
obj[propertyName] = function(newVal){
if (angular.isDefined(newVal)) {
obj[prop] = newVal;
}
return obj[prop];
}
return obj;
}
}
Or just
function getModel(propertyName, defValue) {
var obj = {};
var propValue = defValue;
obj[propertyName] = function(newVal){
if (angular.isDefined(newVal)) {
propValue = newVal;
}
return propValue;
}
return obj;
}
}
4 Comments
this. I did not get what you mean. Can you paste your code in a plunker..if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) { modelValue = modelValue(); } Bascially the function reference is modelValue and it is just executed with no context. It is just the copy of function reference that is being executed. This is always the problem when we use this in the piece of code where we dont have a control over the execution context.