I have an object exposing 2 properties (say foo
and bar
) via getters/setters in the form of method([value])
, so you can get their value by calling method()
and you can set their value by calling method(value)
.
Also, this object keeps foo
and bar
synchronized, in the way it makes bar
always to be 1 greater than foo
). This means whenever you set the value of foo
, it internally updates the value of bar
, and viceversa.
This is the sample implementation:
function obj() {
var foo = 1;
var bar = 2;
return {
foo: function (value) {
if (value) {
foo = value;
bar = foo + 1;
}
return foo;
},
bar: function (value) {
if (value) {
bar = value;
foo = bar - 1;
}
return bar;
}
}
}
Now I have two input
elements, one for each of these properties.
// in my controller
$scope.myobj = obj();
<!-- in the HTML -->
<input my-directive ng-model="myobj.foo">
<input my-directive ng-model="myobj.bar">
Please remember that foo
and bar
are functions, so I write a $formatter
to get the value by calling the getter; and a $parser
to set the value by calling the setter, like this:
.directive('myDirective', function () {
return {
require: 'ngModel',
link: function ($scope, $element, $attrs, ngModel) {
ngModel.$formatters.push(function (modelValue) {
return modelValue();
});
ngModel.$parsers.push(function (viewValue) {
ngModel.$modelValue(viewValue);
return ngModel.$modelValue;
});
}
};
});
You can check the example in jsFiddle or Plunker.
As you can see, the formatter/parser thing works just fine, but the problem is that the <input>
value of the property that is internally modified (say bar
if you changed foo
) is not updated.
I can't even grasp why in earth is not working. As you can see in the example, below each input I'm interpolating the same value which seems perfectly updated upon any change. Why ng-model isn't updating my <input>
value?
I have an object exposing 2 properties (say foo
and bar
) via getters/setters in the form of method([value])
, so you can get their value by calling method()
and you can set their value by calling method(value)
.
Also, this object keeps foo
and bar
synchronized, in the way it makes bar
always to be 1 greater than foo
). This means whenever you set the value of foo
, it internally updates the value of bar
, and viceversa.
This is the sample implementation:
function obj() {
var foo = 1;
var bar = 2;
return {
foo: function (value) {
if (value) {
foo = value;
bar = foo + 1;
}
return foo;
},
bar: function (value) {
if (value) {
bar = value;
foo = bar - 1;
}
return bar;
}
}
}
Now I have two input
elements, one for each of these properties.
// in my controller
$scope.myobj = obj();
<!-- in the HTML -->
<input my-directive ng-model="myobj.foo">
<input my-directive ng-model="myobj.bar">
Please remember that foo
and bar
are functions, so I write a $formatter
to get the value by calling the getter; and a $parser
to set the value by calling the setter, like this:
.directive('myDirective', function () {
return {
require: 'ngModel',
link: function ($scope, $element, $attrs, ngModel) {
ngModel.$formatters.push(function (modelValue) {
return modelValue();
});
ngModel.$parsers.push(function (viewValue) {
ngModel.$modelValue(viewValue);
return ngModel.$modelValue;
});
}
};
});
You can check the example in jsFiddle or Plunker.
As you can see, the formatter/parser thing works just fine, but the problem is that the <input>
value of the property that is internally modified (say bar
if you changed foo
) is not updated.
I can't even grasp why in earth is not working. As you can see in the example, below each input I'm interpolating the same value which seems perfectly updated upon any change. Why ng-model isn't updating my <input>
value?
-
1
$formatters
run "whenever the model value changes." My guess is that$modelValue
never changes--it remains a static constant reference tofoo()
orbar()
. You call the function to change an internal representation of some data, but the thing thatngModel
is attached to never changes. The DOM updates because the binding tofoo()
andbar()
--the results of those function calls--do update. – Michelle Tilley Commented May 30, 2013 at 5:03
2 Answers
Reset to default 4This is one way you could do it:
http://plnkr.co/edit/7HCpSb?p=preview
(It looks a kind of hacky and I do not like my solution very much, though.)
As @Brandon pointed out, you are watching the getter function. The function evaluation may give different values, but function definition never changes in your example, so formatter never fires in your directive.
In my example, I'm watching the evaluation of the getter function
,
so it fires whenever internal value changes.
I avoided using ngModel as it does not look fit in this way.
in the template:
<input my-directive accessor="myobj.foo">
in the directive link function:
$scope.$watch( $attrs.accessor + '()', function( v ) {
if ( v ) $element[0].value = v;
});
I could get a getter/setter scenario to work by coding another directive besides of ng-model for specifying the getter and the setter of a ng-model binding. See:
https://stackoverflow./a/21290588/738808
Using the ng-model-getter and ng-model-setter directives described in this question, you would just proceed this way in your html:
<input my-directive ng-model="$foo" ng-model-getter="myobj.foo()" ng-model-setter="myobj.foo($value)">
<input my-directive ng-model="$bar" ng-model-getter="myobj.bar()" ng-model-setter="myobj.bar($value)">