28

I've been fighting with this for almost two days. I hope you guys can help me.

Summary:
I have problems setting the view value of some input fields programatically.
I have a form with inputs whose values are saved before the form is removed (multiple elements and multiple forms possible, user might close a form, and reopen later). On reopening the form I want to restore the previous view values (main reason is to get back also the invalid view values which were not saved in the model). This doesn't work.

If I call ctrl.$setViewValue(previousValue) I get the model (visibly) updated (if valid), the view values of the formControl (while debugging in console) are changed too, but I don't get them actually rendered in the input fields. I don't understand why :(

I reduced the problem to this fiddle:
http://jsfiddle.net/g0mjk750/1/

javascript

var app = angular.module('App', [])

    function Controller($scope) {
        $scope.form = {
            userContent: 'initial content'
        }
    }
app.controller('Controller', Controller);
app.directive('resetOnBlur', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {
            element.bind('blur', function () {
                console.log(ngModel);
                scope.$apply(setAnotherValue);
            });
            function setAnotherValue() {
                ngModel.$setViewValue("I'm a new value of the model. I've been set using the setViewValue method");
            }
        }
    };
});

Html

<form name="myForm" ng-app="App" ng-controller="Controller" class="form">
    Text: {{form.userContent}}
    <hr />
    If you remove the text, "Required!" will be displayed.<br/>
    If you change the input value, the text will update.<br/>
    If you blur, the text will update, but the (visible) input value not.
    <hr />
    <input class="input" type="text" ng-model="form.userContent" name="userContent" reset-on-blur required></textarea>
    <span ng-show="myForm.userContent.$error.required">Required!</span>
</form>

I hope you guys can explain to me why this doesn't work and how to fix this...

PSL
  • 123,204
  • 21
  • 253
  • 243
Allisone
  • 8,434
  • 4
  • 32
  • 54

2 Answers2

85

You need to call ngModel.$render() to have the viewvalue change reflected in the input. There is no watch created on $viewValue so that changes are automatically reflected.

   function setAnotherValue() {
        ngModel.$setViewValue("I'm a new value of the model. I've been set using the setViewValue method");
        ngModel.$render();
    }

Plnkr

Default implementation of $render does this:-

 element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);

However you can override and customize your implementation for $render as well..

PSL
  • 123,204
  • 21
  • 253
  • 243
  • 2
    So easy. call $render and it works. that's cool. but I really need to overwrite $render because in 1.3.0-rc.3 $render() looks almost the same, but it checks $isEmpty(ctrl.$modelValue) not $isEmpty(ctrl.$viewValue). Well and in setViewValue the modelValue is set only if it's valid. but I wanted invalid fields to be rerendered as well. Without overwriting render to behave like it did once (like in your answer) my fields are empty. For now I've overridden the render method. I wonder why they changed the render method. – Allisone Oct 02 '14 at 09:45
-4

try scope.$apply() to invoke change on model since you're liking changing model outside of scope where ngModel was inited

evandrix
  • 6,041
  • 4
  • 27
  • 38
eugenekgn
  • 1,652
  • 2
  • 17
  • 38
  • `scope.$apply()` doesn't work for me. Calling $setViewValue(...) I think already fires off whatever $apply does since when I call $setViewValue the watches on that model go off. – Jerinaw Feb 17 '16 at 18:37