ngModel Formatters and Parsers

AngularjsAngular Ngmodel

Angularjs Problem Overview


I posted the same question in different form, but no one answered. I am not getting a clear picture of what the Formatters and Parsers do in angular js.

By the definition, both the Formatters and Parsers look similar to me. Maybe I am wrong, as I am new to this angularjs.

Formatters Definition

Array of functions to execute, as a pipeline, whenever the model value changes. Each function is called, in turn, passing the value through to the next. Used to format / convert values for display in the control and validation.

Parsers Definition

Array of functions to execute, as a pipeline, whenever the control reads value from the DOM. Each function is called, in turn, passing the value through to the next. Used to sanitize / convert the value as well as validation. For validation, the parsers should update the validity state using $setValidity(), and return undefined for invalid values.

Please help me to understand both features with a simple example. A simple illustration of both will be appreciated.

Angularjs Solutions


Solution 1 - Angularjs

This topic was covered really well in a related question: https://stackoverflow.com/questions/11616636/how-to-do-two-way-filtering-in-angular-js

To summarize:

  • Formatters change how model values will appear in the view.
  • Parsers change how view values will be saved in the model.

Here is a simple example, building on an example in the [NgModelController api documentation][1]:

  //format text going to user (model to view)
  ngModel.$formatters.push(function(value) {
    return value.toUpperCase();
  });
  
  //format text from the user (view to model)
  ngModel.$parsers.push(function(value) {
    return value.toLowerCase();
  });

You can see it in action: http://plnkr.co/UQ5q5FxyBzIeEjRYYVGX?plnkr=legacy

<input type="button" value="set to 'misko'" ng-click="data.name='misko'"/>
<input type="button" value="set to 'MISKO'" ng-click="data.name='MISKO'"/>
<input changecase ng-model="data.name" />

When you type a name in (view to model), you will see that the model is always lowercase. But, when you click a button and programatically change the name (model to view), the input field is always uppercase. [1]: http://docs.angularjs.org/api/ng/type/ngModel.NgModelController

Solution 2 - Angularjs

Another usage for formatters and parsers is when you want to store dates in UTC time and display them in local time on inputs, I created the below datepicker directive and utcToLocal filter for this.

(function () {
    'use strict';

    angular
        .module('app')
        .directive('datepicker', Directive);

    function Directive($filter) {
        return {
            require: 'ngModel',
            link: function (scope, element, attr, ngModel) {
                element.addClass('datepicker');
                element.pickadate({ format: 'dd/mm/yyyy', editable: true });

                // convert utc date to local for display
                ngModel.$formatters.push(function (utcDate) {
                    if (!utcDate)
                        return;

                    return $filter('utcToLocal')(utcDate, 'dd/MM/yyyy');
                });

                // convert local date to utc for storage
                ngModel.$parsers.push(function (localDate) {
                    if (!localDate)
                        return;

                    return moment(localDate, 'DD/MM/YYYY').utc().toISOString();
                });
            }
        };
    }
})();

It uses this utcToLocal filter that ensures the input date is in the correct format before converting to local time.

(function () {
    'use strict';

    angular
        .module('app')
        .filter('utcToLocal', Filter);

    function Filter($filter) {
        return function (utcDateString, format) {
            if (!utcDateString) {
                return;
            }

            // append 'Z' to the date string to indicate UTC time if the timezone isn't already specified
            if (utcDateString.indexOf('Z') === -1 && utcDateString.indexOf('+') === -1) {
                utcDateString += 'Z';
            }

            return $filter('date')(utcDateString, format);
        };
    }
})();

moment.js is used to convert local to utc dates.

pickadate.js is the datepicker plugin used

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRONEView Question on Stackoverflow
Solution 1 - Angularjsj.wittwerView Answer on Stackoverflow
Solution 2 - AngularjsJason WatmoreView Answer on Stackoverflow