@@ -628,6 +628,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
628
628
/**
629
629
* @ngdoc directive
630
630
* @name angular.module.ng.$compileProvider.directive.textarea
631
+ * @restrict E
631
632
*
632
633
* @description
633
634
* HTML textarea element control with angular data-binding. The data-binding and validation
@@ -782,6 +783,79 @@ var VALID_CLASS = 'ng-valid',
782
783
*
783
784
* @description
784
785
*
786
+ * `NgModelController` provides API for the `ng-model` directive. The controller contains
787
+ * services for data-binding, validation, CSS update, value formatting and parsing. It
788
+ * specifically does not contain any logic which deals with DOM rendering or listening to
789
+ * DOM events. The `NgModelController` is meant to be extended by other directives where, the
790
+ * directive provides DOM manipulation and the `NgModelController` provides the data-binding.
791
+ *
792
+ * This example shows how to use `NgModelController` with a custom control to achieve
793
+ * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
794
+ * collaborate together to achieve the desired result.
795
+ *
796
+ * <example module="customControl">
797
+ <file name="style.css">
798
+ [contenteditable] {
799
+ border: 1px solid black;
800
+ background-color: white;
801
+ min-height: 20px;
802
+ }
803
+
804
+ .ng-invalid {
805
+ border: 1px solid red;
806
+ }
807
+
808
+ </file>
809
+ <file name="script.js">
810
+ angular.module('customControl', []).
811
+ directive('contenteditable', function() {
812
+ return {
813
+ restrict: 'A', // only activate on element attribute
814
+ require: '?ngModel', // get a hold of NgModelController
815
+ link: function(scope, element, attrs, ngModel) {
816
+ if(!ngModel) return; // do nothing if no ng-model
817
+
818
+ // Specify how UI should be updated
819
+ ngModel.$render = function() {
820
+ element.html(ngModel.$viewValue || '');
821
+ };
822
+
823
+ // Listen for change events to enable binding
824
+ element.bind('blur keyup change', function() {
825
+ scope.$apply(read);
826
+ });
827
+ read(); // initialize
828
+
829
+ // Write data to the model
830
+ function read() {
831
+ ngModel.$setViewValue(element.html());
832
+ }
833
+ }
834
+ };
835
+ });
836
+ </file>
837
+ <file name="index.html">
838
+ <form name="myForm">
839
+ <div contenteditable
840
+ name="myWidget" ng-model="userContent"
841
+ required>Change me!</div>
842
+ <span ng-show="myForm.myWidget.$error.required">Required!</span>
843
+ <hr>
844
+ <textarea ng-model="userContent"></textarea>
845
+ </form>
846
+ </file>
847
+ <file name="scenario.js">
848
+ it('should data-bind and become invalid', function() {
849
+ var contentEditable = element('[contenteditable]');
850
+
851
+ expect(contentEditable.text()).toEqual('Change me!');
852
+ input('userContent').enter('');
853
+ expect(contentEditable.text()).toEqual('');
854
+ expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
855
+ });
856
+ </file>
857
+ * </example>
858
+ *
785
859
*/
786
860
var NgModelController = [ '$scope' , '$exceptionHandler' , '$attrs' , 'ngModel' , '$element' ,
787
861
function ( $scope , $exceptionHandler , $attr , ngModel , $element ) {
@@ -794,9 +868,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$e
794
868
this . $dirty = false ;
795
869
this . $valid = true ;
796
870
this . $invalid = false ;
797
- this . $render = noop ;
798
871
this . $name = $attr . name ;
799
872
873
+ /**
874
+ * @ngdoc function
875
+ * @name angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$render
876
+ * @methodOf angular.module.ng.$compileProvider.directive.ngModel.NgModelController
877
+ *
878
+ * @description
879
+ * Called when the view needs to be updated. It is expected that the user of the ng-model
880
+ * directive will implement this method.
881
+ */
882
+ this . $render = noop ;
883
+
800
884
var parentForm = $element . inheritedData ( '$formController' ) || nullFormCtrl ,
801
885
invalidCount = 0 , // used to easily determine if we are valid
802
886
$error = this . $error = { } ; // keep invalid keys here
@@ -958,7 +1042,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$e
958
1042
* - {@link angular.module.ng.$compileProvider.directive.textarea textarea}
959
1043
*
960
1044
*/
961
- var ngModelDirective = [ function ( ) {
1045
+ var ngModelDirective = function ( ) {
962
1046
return {
963
1047
inject : {
964
1048
ngModel : 'accessor'
@@ -978,7 +1062,7 @@ var ngModelDirective = [function() {
978
1062
} ) ;
979
1063
}
980
1064
} ;
981
- } ] ;
1065
+ } ;
982
1066
983
1067
984
1068
/**
@@ -1039,11 +1123,12 @@ var ngChangeDirective = valueFn({
1039
1123
} ) ;
1040
1124
1041
1125
1042
- var requiredDirective = [ function ( ) {
1126
+ var requiredDirective = function ( ) {
1043
1127
return {
1044
1128
require : '?ngModel' ,
1045
1129
link : function ( scope , elm , attr , ctrl ) {
1046
1130
if ( ! ctrl ) return ;
1131
+ attr . required = true ; // force truthy in case we are on non input element
1047
1132
1048
1133
var validator = function ( value ) {
1049
1134
if ( attr . required && ( isEmpty ( value ) || value === false ) ) {
@@ -1063,7 +1148,7 @@ var requiredDirective = [function() {
1063
1148
} ) ;
1064
1149
}
1065
1150
} ;
1066
- } ] ;
1151
+ } ;
1067
1152
1068
1153
1069
1154
/**
@@ -1144,7 +1229,7 @@ var ngListDirective = function() {
1144
1229
1145
1230
var CONSTANT_VALUE_REGEXP = / ^ ( t r u e | f a l s e | \d + ) $ / ;
1146
1231
1147
- var ngValueDirective = [ function ( ) {
1232
+ var ngValueDirective = function ( ) {
1148
1233
return {
1149
1234
priority : 100 ,
1150
1235
compile : function ( tpl , tplAttr ) {
@@ -1162,4 +1247,4 @@ var ngValueDirective = [function() {
1162
1247
}
1163
1248
}
1164
1249
} ;
1165
- } ] ;
1250
+ } ;
0 commit comments