aboutsummaryrefslogtreecommitdiffstats
path: root/src/ng/directive/input.js
diff options
context:
space:
mode:
authorMisko Hevery2012-05-25 10:29:54 -0700
committerMisko Hevery2012-06-02 16:02:09 -0700
commit8024a5742c46a42ef204988ff7362a4fc14b7a2d (patch)
treefc8e4dcae5e84ad462ba5f06bd7f0389590e3a1b /src/ng/directive/input.js
parent073e76f8353ca3f743ea61ff21f7de7b1e5a7701 (diff)
downloadangular.js-8024a5742c46a42ef204988ff7362a4fc14b7a2d.tar.bz2
doc(NgModelController) add example and $render documentation
Closes#930
Diffstat (limited to 'src/ng/directive/input.js')
-rw-r--r--src/ng/directive/input.js99
1 files changed, 92 insertions, 7 deletions
diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js
index 6e394afd..5fe32125 100644
--- a/src/ng/directive/input.js
+++ b/src/ng/directive/input.js
@@ -628,6 +628,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.textarea
+ * @restrict E
*
* @description
* HTML textarea element control with angular data-binding. The data-binding and validation
@@ -782,6 +783,79 @@ var VALID_CLASS = 'ng-valid',
*
* @description
*
+ * `NgModelController` provides API for the `ng-model` directive. The controller contains
+ * services for data-binding, validation, CSS update, value formatting and parsing. It
+ * specifically does not contain any logic which deals with DOM rendering or listening to
+ * DOM events. The `NgModelController` is meant to be extended by other directives where, the
+ * directive provides DOM manipulation and the `NgModelController` provides the data-binding.
+ *
+ * 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.
+ *
+ * <example module="customControl">
+ <file name="style.css">
+ [contenteditable] {
+ border: 1px solid black;
+ background-color: white;
+ min-height: 20px;
+ }
+
+ .ng-invalid {
+ border: 1px solid red;
+ }
+
+ </file>
+ <file name="script.js">
+ angular.module('customControl', []).
+ directive('contenteditable', function() {
+ 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(ngModel.$viewValue || '');
+ };
+
+ // Listen for change events to enable binding
+ element.bind('blur keyup change', function() {
+ scope.$apply(read);
+ });
+ read(); // initialize
+
+ // Write data to the model
+ function read() {
+ ngModel.$setViewValue(element.html());
+ }
+ }
+ };
+ });
+ </file>
+ <file name="index.html">
+ <form name="myForm">
+ <div contenteditable
+ name="myWidget" ng-model="userContent"
+ required>Change me!</div>
+ <span ng-show="myForm.myWidget.$error.required">Required!</span>
+ <hr>
+ <textarea ng-model="userContent"></textarea>
+ </form>
+ </file>
+ <file name="scenario.js">
+ it('should data-bind and become invalid', function() {
+ var contentEditable = element('[contenteditable]');
+
+ expect(contentEditable.text()).toEqual('Change me!');
+ input('userContent').enter('');
+ expect(contentEditable.text()).toEqual('');
+ expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
+ });
+ </file>
+ * </example>
+ *
*/
var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$element',
function($scope, $exceptionHandler, $attr, ngModel, $element) {
@@ -794,9 +868,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$e
this.$dirty = false;
this.$valid = true;
this.$invalid = false;
- this.$render = noop;
this.$name = $attr.name;
+ /**
+ * @ngdoc function
+ * @name angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$render
+ * @methodOf angular.module.ng.$compileProvider.directive.ngModel.NgModelController
+ *
+ * @description
+ * Called when the view needs to be updated. It is expected that the user of the ng-model
+ * directive will implement this method.
+ */
+ this.$render = noop;
+
var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
invalidCount = 0, // used to easily determine if we are valid
$error = this.$error = {}; // keep invalid keys here
@@ -958,7 +1042,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$e
* - {@link angular.module.ng.$compileProvider.directive.textarea textarea}
*
*/
-var ngModelDirective = [function() {
+var ngModelDirective = function() {
return {
inject: {
ngModel: 'accessor'
@@ -978,7 +1062,7 @@ var ngModelDirective = [function() {
});
}
};
-}];
+};
/**
@@ -1039,11 +1123,12 @@ var ngChangeDirective = valueFn({
});
-var requiredDirective = [function() {
+var requiredDirective = function() {
return {
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
+ attr.required = true; // force truthy in case we are on non input element
var validator = function(value) {
if (attr.required && (isEmpty(value) || value === false)) {
@@ -1063,7 +1148,7 @@ var requiredDirective = [function() {
});
}
};
-}];
+};
/**
@@ -1144,7 +1229,7 @@ var ngListDirective = function() {
var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
-var ngValueDirective = [function() {
+var ngValueDirective = function() {
return {
priority: 100,
compile: function(tpl, tplAttr) {
@@ -1162,4 +1247,4 @@ var ngValueDirective = [function() {
}
}
};
-}];
+};