1+ xtForm . directive ( 'ngModel' , function ( xtFormConfig , $rootScope , $interpolate , $document ) {
2+ 'use strict' ;
3+
4+ var UNTOUCHED_CLASS = 'ng-untouched' ,
5+ TOUCHED_CLASS = 'ng-touched' ;
6+
7+ return {
8+ require : [ 'ngModel' , '^?xtForm' , '^?form' ] ,
9+ link : function ( scope , element , attrs , ctrls ) {
10+
11+ var defaultErrors = xtFormConfig . getErrorMessages ( ) ,
12+ ngModel = ctrls [ 0 ] ,
13+ xtForm = ctrls [ 1 ] ,
14+ form = ctrls [ 2 ] ,
15+ setTouchedFn ,
16+ validationStrategyFn ;
17+
18+ /**
19+ * Active the directive
20+ */
21+ function activate ( ) {
22+
23+ setTouchedFn = ngModel . $setTouched || setTouchedPolyfill ;
24+ validationStrategyFn = xtForm . getValidationStrategy ( ) ;
25+ ngModel . $untouched = true ;
26+
27+ // add extensions to ngModel
28+ var labelEl = $document [ 0 ] . querySelectorAll ( 'label[for="' + attrs . id + '"]' ) ;
29+ angular . extend ( ngModel , {
30+ $focused : false ,
31+ $label : labelEl . length > 0 ? labelEl [ 0 ] . innerText : '' ,
32+ $xtErrors : [ ]
33+ } ) ;
34+
35+ // set errors on the ngModel when $error changes
36+ scope . $watch ( function ( ) {
37+ return ngModel . $error ;
38+ } , updateErrors , true ) ;
39+
40+ scope . $on ( 'XtForm.ForceErrorUpdate' , updateErrors ) ;
41+
42+ element
43+ . on ( 'focus' , function ( ) {
44+ if ( ! ngModel . $touched ) {
45+ setTouchedFn ( ) ;
46+ }
47+ ngModel . $focused = true ;
48+ updateErrors ( ) ;
49+ scope . $apply ( ) ;
50+ } )
51+ . on ( 'blur' , function ( ) {
52+ ngModel . $focused = false ;
53+ updateErrors ( ) ;
54+ scope . $apply ( ) ;
55+ } ) ;
56+ }
57+
58+ function getErrorMessageForKey ( key ) {
59+ var attrKey = 'msg' + key [ 0 ] . toUpperCase ( ) + key . substring ( 1 ) ;
60+
61+ // use either the provided string as an interpolated attribute, or the default message
62+ return attrs [ attrKey ] ?
63+ attrs [ attrKey ] :
64+ $interpolate ( defaultErrors [ key ] ) ( attrs ) ;
65+ }
66+
67+ /**
68+ * Sets the $xtErrors collection on validation change
69+ */
70+ function updateErrors ( ) {
71+ ngModel . $xtErrors = [ ] ;
72+
73+ angular . forEach ( ngModel . $error , function ( item , key ) {
74+ var showErrors = validationStrategyFn ( form , ngModel ) ;
75+ if ( showErrors ) {
76+ var error = {
77+ key : key ,
78+ message : getErrorMessageForKey ( key )
79+ } ;
80+
81+ // Ensure required is the last message to be shown
82+ // TODO possibly introduce priority here.
83+ if ( key === 'required' ) {
84+ ngModel . $xtErrors . push ( error ) ;
85+ } else {
86+ ngModel . $xtErrors . unshift ( error ) ;
87+ }
88+ }
89+ } ) ;
90+
91+ $rootScope . $broadcast ( 'XtForm.ErrorsUpdated' , ngModel ) ;
92+ }
93+
94+ // Polyfill for $touched in AngularJS < 1.3
95+ function setTouchedPolyfill ( ) {
96+ ngModel . $touched = true ;
97+ ngModel . $untouched = false ;
98+ element . addClass ( TOUCHED_CLASS ) . removeClass ( UNTOUCHED_CLASS ) ;
99+ }
100+
101+ if ( xtForm ) {
102+ activate ( ) ;
103+ }
104+ }
105+ } ;
106+ } ) ;
0 commit comments