AngularJS - scope.$watch vs. ctrl.$render

NgModelController ex.

by gavinfoley

HTML

<div ng-app="form-example2">
    <div ng-controller="MyCtrl">
        <div contentEditable="true" ng-model="content" class="panel" title="Click to edit">
            Editable text
        </div> 
        
        <div class="panel callout">
            Model = {{content}}
        </div>
        
        <a href="" class="button tiny secondary round" ng-click="changeModel()">Reset</a>
    </div>
    
</div>

CSS

</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> 
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/4.1.6/css/foundation.min.css"> 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> 
<style>
body {padding: 20px;}

JavaScript

// http://stackoverflow.com/questions/15393427/angularjs-directives-best-practices-when-using-ngmodel-with-jquery-widget

function MyCtrl($scope) {
    $scope.changeModel = function () {
        $scope.content = "This is the reset text!"
    }
}

angular.module('form-example2', [])
.directive('contenteditable', function ($log) {
    return {
        require: '?ngModel', // get a hold of NgModelController
        link: function (scope, elm, attrs, ngModel) {
            if(!ngModel) return; // do nothing if no ng-model
            
            // view -> model
            elm.bind('blur', function () {
                $log.info('view -> model - blur called')
                scope.$apply(function () {
                    ngModel.$setViewValue(elm.html());
                });
            });
            
            // model -> view
            ngModel.$render = function () {
                $log.info('model -> view - render called')
                elm.html(ngModel.$viewValue);
            };
            
            scope.$watch(attrs.ngModel, function() {
                $log.info('watch called');
            });

            // load init value from DOM
            ngModel.$setViewValue(elm.html());
        }
    };
});