Angular has this concept in directives called $parsers and $formatters. It's mechanism to be able to format data from model to view so that it's presented in a more human-friendly way to the user, and when they modify it, it can be translated back to a more computer-friendly mode. It leverages the ngModel controller to do this.

$parsers/$formatters are an array of actions that take in input, translate it to either the computer-friendly or human-friendly format respectively and return the translated value.

The Code

.directive('myDirective', function () {
	return {
    	// $parsers/$formatters live on the
        // ngModel controller, so we need this!
    	require: 'ngModel',
        link: function (scope, elem, attrs, ngModel) {
        	ngModel.$parsers.push(function toModel(input) {
            	// do something to format user input
                // to be more "computer-friendly"
                return modifiedInput;
            ngModel.$formatters.push(function toView(input) {
            	// do something to format user input
                // to be more "human-friendly"
                return modifiedInput;

Your $parsers/$formatters can do just about anything, and you don't strictly need to have one of each, but it usually makes sense that if you take an input and apply a matching $parser and $formatter (or vice versa), you would get the same original input. This is just probably the most common use-case, but a hard and fast rule or anything.

Note that we're pushing (you can also unshift) functions onto our $formatters/$parsers. Remember that inputs can have multiple directives on them, and thus can have multiple $formatters/$parsers.

Example: Tag List

In this example, you can enter in a string of comma separated values, and the model will be an actual array of values split by the commas. Conversely, you can set the model to an array and the input will appear as a string of comma separated values.

See the Pen $parsers/$formatters demo by Cameron Spear (@CWSpear) on CodePen.