Angular.js: NgModel needs a way to manually re-run the formatter chain

Created on 31 Jul 2013  ·  3Comments  ·  Source: angular/angular.js

See this fiddle:
http://jsfiddle.net/tPWBK/1/

Say you have a data transformation directive that requires 'ngModel' and adds to the formatter and parser chains. If the transformation is dependent on some dynamic data other than $modelValue or $viewValue, there's no way to do a watch on that data and re-run the formatter chain.

See this excerpt from https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L1081

$scope.$watch(function ngModelWatch() {
  var value = ngModelGet($scope);

  // if scope model value and ngModel value are out of sync
  if (ctrl.$modelValue !== value) {

    var formatters = ctrl.$formatters,
        idx = formatters.length;

    ctrl.$modelValue = value;
    while(idx--) {
      value = formatters[idx](value);
    }

    if (ctrl.$viewValue !== value) {
      ctrl.$viewValue = value;
      ctrl.$render();
    }
  }
});

Should everything inside the (ctrl.$modelValue !== value) check be a function that's exposed publicly on NgModelController?

forms feature

Most helpful comment

+1 would be really nice to have this. the lack of async formatters and parsers makes working with async data pretty nasty. this would help prevent some of the race conditions introduced by synchronous validation against an async data source.

for reference, i did it very similarly to @jpsimons:

scope.$watch('myAsyncCollection', () => {
  ngModel.$viewValue = ngModel.$formatters.reduceRight((prev, fn) => fn(prev)), ngModel.$modelValue)
  ngModel.$render()
})

All 3 comments

Well, I guess one could just copy that block into a directive. It's all public stuff. Would be handy to have a function to do it for you though.

+1 would be really nice to have this. the lack of async formatters and parsers makes working with async data pretty nasty. this would help prevent some of the race conditions introduced by synchronous validation against an async data source.

for reference, i did it very similarly to @jpsimons:

scope.$watch('myAsyncCollection', () => {
  ngModel.$viewValue = ngModel.$formatters.reduceRight((prev, fn) => fn(prev)), ngModel.$modelValue)
  ngModel.$render()
})

just if someone is searching the code snippet - it has moved:
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngModel.js#L822

Was this page helpful?
0 / 5 - 0 ratings