Improve this Doc  View Source

ngModel.NgModelController

  1. - type in module ng

NgModelController provides API for the ngModel directive. The controller contains services for data-binding, validation, CSS updates, and value formatting and parsing. It purposefully does not contain any logic which deals with DOM rendering or listening to DOM events. Such DOM related logic should be provided by other directives which make use of NgModelController for data-binding to control elements. Angular provides this DOM logic for most input elements. At the end of this page you can find a custom control example that uses ngModelController to bind to contenteditable elements.

Methods

Properties

Example

Custom Control Example

This example shows how to use NgModelController with a custom control to achieve data-binding. Notice how different directives (contenteditable, ng-model, and required) collaborate together to achieve the desired result.

contenteditable is an HTML5 attribute, which tells the browser to let the element contents be edited in place by the user.

We are using the $sce service here and include the $sanitize module to automatically remove "bad" content like inline event listener (e.g. <span onclick="...">). However, as we are using $sce the model can still decide to provide unsafe content if it marks that content using the $sce service.

  Edit in Plunker
[contenteditable] {
  border: 1px solid black;
  background-color: white;
  min-height: 20px;
}

.ng-invalid {
  border: 1px solid red;
}
angular.module('customControl', ['ngSanitize']).
directive('contenteditable', ['$sce', function($sce) {
  return {
    restrict: 'A', // only activate on element attribute
    require: '?ngModel', // get a hold of NgModelController
    link: function(scope, element, attrs, ngModel) {
      if (!ngModel) return; // do nothing if no ng-model

      // Specify how UI should be updated
      ngModel.$render = function() {
        element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
      };

      // Listen for change events to enable binding
      element.on('blur keyup change', function() {
        scope.$evalAsync(read);
      });
      read(); // initialize

      // Write data to the model
      function read() {
        var html = element.html();
        // When we clear the content editable the browser leaves a <br> behind
        // If strip-br attribute is provided then we strip this out
        if ( attrs.stripBr && html == '<br>' ) {
          html = '';
        }
        ngModel.$setViewValue(html);
      }
    }
  };
}]);
<form name="myForm">
 <div contenteditable
      name="myWidget" ng-model="userContent"
      strip-br="true"
      required>Change me!</div>
  <span ng-show="myForm.myWidget.$error.required">Required!</span>
 <hr>
 <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
</form>
it('should data-bind and become invalid', function() {
  if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
    // SafariDriver can't handle contenteditable
    // and Firefox driver can't clear contenteditables very well
    return;
  }
  var contentEditable = element(by.css('[contenteditable]'));
  var content = 'Change me!';

  expect(contentEditable.getText()).toEqual(content);

  contentEditable.clear();
  contentEditable.sendKeys(protractor.Key.BACK_SPACE);
  expect(contentEditable.getText()).toEqual('');
  expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
});