95

I have the following ckEditor directive. At the bottom are two variations that I have seen from examples on how to set the data in the editor:

app.directive('ckEditor', [function () {
    return {
        require: '?ngModel',
        link: function ($scope, elm, attr, ngModel) {

            var ck = null;
            var config = attr.editorSize;
            if (config == 'wide') {
                ck = CKEDITOR.replace(elm[0], { customConfig: 'config-wide.js' });
            } else {
                ck = CKEDITOR.replace(elm[0], { customConfig: 'config-narrow.js' });
            }


            function updateModel() {
                $scope.$apply(function () {
                    ngModel.$setViewValue(ck.getData());
                });
            }

            $scope.$on('modalObjectSet', function (e, modalData) {
                // force a call to render
                ngModel.$render();
            });

            ck.on('change', updateModel);
            ck.on('mode', updateModel);
            ck.on('key', updateModel);
            ck.on('dataReady', updateModel);

            ck.on('instanceReady', function () {
                ngModel.$render();
            });

            ck.on('insertElement', function () {
                setTimeout(function () {
                    $scope.$apply(function () {
                        ngModel.$setViewValue(ck.getData());
                    });
                }, 1000);
            });

            ngModel.$render = function (value) {
                ck.setData(ngModel.$modelValue);
            };

            ngModel.$render = function (value) {
                ck.setData(ngModel.$viewValue);
            };
        }
    };
}])

Can someone tell me what is the difference between:

ck.setData(ngModel.$modelValue);
ck.setData(ngModel.$viewValue);

And which should I use. I looked at the angular documentation and it says:

$viewValue

Actual string value in the view.

$modelValue

The value in the model, that the control is bound to.

I have no idea what the author meant when he wrote this in the document :-(

Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427

3 Answers3

153

You are looking at the correct documentation, but it might just be that you're a little confused. The $modelValue and $viewValue have one distinct difference. It is this:

As you already noted above:

$viewValue: Actual string (or Object) value in the view.
$modelValue: The value in the model, that the control is bound to.

I'm going to assume that your ngModel is referring to an <input /> element...? So your <input> has a string value that it displays to the user, right? But the actual model might be some other version of that string. For example, the input might be showing the string '200' but the <input type="number"> (for example) will actually contain a model value of 200 as an integer. So the string representation that you "view" in the <input> is the ngModel.$viewValue and the numeric representation will be the ngModel.$modelValue.

Another example would be a <input type="date"> where the $viewValue would be something like Jan 01, 2000 and the $modelValue would be an actual javascript Date object that represents that date string. Does that make sense?

I hope that answers your question.

Ofer Zelig
  • 17,068
  • 9
  • 59
  • 93
tennisgent
  • 14,165
  • 9
  • 50
  • 48
  • So basically, `$viewValue` is always a string? – cdmckay Mar 07 '14 at 01:40
  • 7
    As the docs say: `$viewValue: Actual string value in the view.`. So, yes. – tennisgent Mar 07 '14 at 14:09
  • 7
    Another note. When an `` value is empty, the `$modelValue` property is `undefined`, whereas the `$viewValue` is `''` empty string. This can make a difference if you're sniffing the "length" of the `$modelValue` which won't work, but `$viewValue` will. – BradGreens Oct 07 '14 at 21:55
  • You clean my doubts, In my case date types $modelValue is what I need. Thanks – Full-Stack Software Engineer Feb 20 '15 at 13:48
  • 8
    The `$viewValue` is not always a string. It is a string for the current Angular core directives, but it may be a primitive or an Object in your custom controls. A good example, is the `` component, where viewValue contains `FileList` object with files attached by the user. The Angular docs are confusing about this right now and should be updated. – demisx Feb 23 '15 at 17:59
  • 4
    Also not if the input is invalid the $modelValue won't be set. Ie, if you have and you input is only 5 characters long, the $viewValue will show those 5 characters but $modelValue will not exist. – honkskillet Oct 16 '15 at 14:11
  • Hi, Is it possible to have a but the actual value is number? like viewValue = "200" and modelValue = 200 Kindly see my issue in this link and see the latest fiddle. http://stackoverflow.com/questions/38165818/angularjs-formatted-number-calculation/38166477?noredirect=1#comment63822012_38166477 – aldesabido Jul 05 '16 at 09:57
  • @tennisgent I manage to do it but the var type of the input always outputs as a string. Please see my fiddle. http://jsfiddle.net/aldesabido/1syh7cne/19/ – aldesabido Jul 06 '16 at 04:53
27

You can see things like this :

  • $modelValue is your external API, that is to say, something exposed to your controller.
  • $viewValue is your internal API, you should use it only internally.

When editing $viewValue, the render method won't be called, because it is the "rendered model". You will have to do it manually, whereas the rendering method will be called automatically upon $modelValue modifications.

However, the information will remain consistent, thanks to $formatters and $parsers :

  • If you change $viewValue, $parsers will translate it back to $modelValue.
  • If you change $modelValue, $formatters will convert it to $viewValue.
Vianney Dupoy de Guitard
  • 2,254
  • 1
  • 14
  • 10
  • When editing $viewValue, the render method won't be called.If you change $viewValue, $parsers will translate it back to $modelValue.means $modelvalue change.and rendering method will be called automatically upon $modelValue modifications.so indirectly,when $viewValue changes, render method is called. is it ? – Mukund Kumar Dec 30 '14 at 07:18
  • 1
    You need to dig in into Angular ngModel two-way binding pipeline to understand how this works. When updating `$viewValue` via `setViewValue(viewValue)` method, parsers/validators kick in (if any) and parse that `viewValue` to the modelValue, validate it, write it to the scope and then kick of `viewChangeListeners`. Next time digest runs, the model value is retrieved from the scope and compared to the $modelValue in the controller: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngModel.js#L813. If they are equal (and they will be equal in your scenario), then it returns. – demisx Feb 21 '15 at 07:55
18

Angular has to keep track of two views of ngModel data- there's the data as seen by the DOM(browser) and then there's Angular's processed representation of those values. The $viewValue is the DOM side value. So, for example, in an <input> the $viewValue is what the user typed in to their browser.

Once someone types something in <input> then $viewValue is processed by $parsers and turned into Angular's view of the value which is called $modelValue.

So you can think of $modelValue being angular's processed version of the value, the value you see in the model, while $viewValue is the raw version.

To take this one step further imagine we do something that changes the $modelValue. Angular sees this change and calls $formatters to create an updated $viewValue (based on the new $modelValue) to be sent to the DOM.

JstnPwll
  • 8,585
  • 2
  • 33
  • 56
KayakDave
  • 24,636
  • 3
  • 65
  • 68