8
8
9
9
function classDirective ( name , selector ) {
10
10
name = 'ngClass' + name ;
11
- return [ '$animate' , function ( $animate ) {
11
+ return [ '$animate' , '$parse' , function ( $animate , $parse ) {
12
12
return {
13
13
restrict : 'AC' ,
14
14
link : function ( scope , element , attr ) {
15
- var oldVal ;
15
+ var oldClasses ;
16
16
17
- scope . $watch ( attr [ name ] , ngClassWatchAction , true ) ;
17
+ var classFn = $parse ( attr [ name ] , arrayClasses ) ;
18
+ scope . $watch ( classFn , ngClassWatchAction , true ) ;
18
19
19
20
attr . $observe ( 'class' , function ( value ) {
20
- ngClassWatchAction ( scope . $eval ( attr [ name ] ) ) ;
21
+ ngClassWatchAction ( classFn ( scope ) ) ;
21
22
} ) ;
22
23
23
24
24
25
if ( name !== 'ngClass' ) {
25
26
scope . $watch ( '$index' , function ( $index , old$index ) {
26
- /* eslint-disable no-bitwise */
27
+ // eslint-disable-next-line no-bitwise
27
28
var mod = $index & 1 ;
29
+ // eslint-disable-next-line no-bitwise
28
30
if ( mod !== ( old$index & 1 ) ) {
29
- var classes = arrayClasses ( scope . $eval ( attr [ name ] ) ) ;
30
31
if ( mod === selector ) {
31
- addClasses ( classes ) ;
32
+ ngClassWatchAction ( classFn ( scope ) ) ;
32
33
} else {
33
- removeClasses ( classes ) ;
34
+ removeClasses ( oldClasses ) ;
35
+ oldClasses = [ ] ;
34
36
}
35
37
}
36
- /* eslint-enable */
37
38
} ) ;
38
39
}
39
40
@@ -80,18 +81,13 @@ function classDirective(name, selector) {
80
81
function ngClassWatchAction ( newVal ) {
81
82
// eslint-disable-next-line no-bitwise
82
83
if ( selector === true || ( scope . $index & 1 ) === selector ) {
83
- var newClasses = arrayClasses ( newVal || [ ] ) ;
84
- if ( ! oldVal ) {
84
+ var newClasses = ( newVal || [ ] ) . join ( ' ' ) . split ( ' ' ) ;
85
+ if ( ! oldClasses ) {
85
86
addClasses ( newClasses ) ;
86
- } else if ( ! equals ( newVal , oldVal ) ) {
87
- var oldClasses = arrayClasses ( oldVal ) ;
87
+ } else if ( ! arrayEqualClasses ( oldClasses , newClasses ) ) {
88
88
updateClasses ( oldClasses , newClasses ) ;
89
89
}
90
- }
91
- if ( isArray ( newVal ) ) {
92
- oldVal = newVal . map ( function ( v ) { return shallowCopy ( v ) ; } ) ;
93
- } else {
94
- oldVal = shallowCopy ( newVal ) ;
90
+ oldClasses = shallowCopy ( newClasses ) ;
95
91
}
96
92
}
97
93
}
@@ -112,24 +108,46 @@ function classDirective(name, selector) {
112
108
}
113
109
114
110
function arrayClasses ( classVal ) {
115
- var classes = [ ] ;
111
+ var classes ;
116
112
if ( isArray ( classVal ) ) {
117
- forEach ( classVal , function ( v ) {
118
- classes = classes . concat ( arrayClasses ( v ) ) ;
119
- } ) ;
120
- return classes ;
121
- } else if ( isString ( classVal ) ) {
122
- return classVal . split ( ' ' ) ;
113
+ classes = classVal . map ( classNames ) ;
123
114
} else if ( isObject ( classVal ) ) {
124
- forEach ( classVal , function ( v , k ) {
125
- if ( v ) {
126
- classes = classes . concat ( k . split ( ' ' ) ) ;
115
+ classes = [ ] ;
116
+ forEach ( classVal , function ( val , key ) {
117
+ if ( val ) {
118
+ classes . push ( key ) ;
119
+ } else if ( isUndefined ( val ) ) {
120
+ // This case is for one time binding:
121
+ // ::expression are evaluated until no undefineds are found
122
+ // if no undefined is placed inside the array,
123
+ // it would assume that the value is fully computed and will fail
124
+ classes . push ( val ) ;
127
125
}
128
126
} ) ;
129
- return classes ;
127
+ } else if ( isString ( classVal ) ) {
128
+ classes = [ classVal ] ;
129
+ } else {
130
+ classes = classVal ;
130
131
}
131
- return classVal ;
132
+
133
+ return classes ;
132
134
}
135
+
136
+ function classNames ( values ) {
137
+ if ( isObject ( values ) ) {
138
+ return Object . keys ( values ) . filter ( function ( k ) {
139
+ return values [ k ] ;
140
+ } ) . join ( ' ' ) ;
141
+ } else {
142
+ return values ;
143
+ }
144
+ }
145
+
146
+ function arrayEqualClasses ( a1 , a2 ) {
147
+ return a1 === a2 ||
148
+ isArray ( a1 ) && isArray ( a2 ) && a1 . join ( ' ' ) === a2 . join ( ' ' ) ;
149
+ }
150
+
133
151
} ] ;
134
152
}
135
153
0 commit comments