1
+ // a helper directive for injecting formatters and parsers
2
+ angular . module ( 'ui.directives' ) . directive ( 'injectTransformers' , [ function ( ) {
3
+ return {
4
+ restrict : 'A' ,
5
+ require : 'ngModel' ,
6
+ priority : - 1 ,
7
+ link : function ( scope , element , attr , ngModel ) {
8
+ var local = scope . $eval ( attr . injectTransformers ) ;
9
+
10
+ if ( ! angular . isObject ( local ) || ! angular . isFunction ( local . fromModel ) || ! angular . isFunction ( local . fromElement ) ) {
11
+ throw "The injectTransformers directive must be bound to an object with two functions (`fromModel` and `fromElement`)" ;
12
+ }
13
+
14
+ ngModel . $parsers . push ( local . fromElement ) ;
15
+ ngModel . $formatters . push ( local . fromModel ) ;
16
+ }
17
+ } ;
18
+ } ] ) ;
19
+
1
20
/*global describe, beforeEach, module, inject, it, spyOn, expect, $ */
2
21
describe ( 'uiSelect2' , function ( ) {
3
22
'use strict' ;
@@ -16,6 +35,54 @@ describe('uiSelect2', function () {
16
35
query . callback ( data ) ;
17
36
}
18
37
} ;
38
+
39
+ scope . transformers = {
40
+ fromModel : function ( modelValue ) {
41
+ if ( ! modelValue ) {
42
+ return modelValue ;
43
+ }
44
+
45
+ if ( angular . isArray ( modelValue ) ) {
46
+ return modelValue . map ( function ( val ) {
47
+ val . text += " - I've been formatted" ;
48
+ return val ;
49
+ } ) ;
50
+ }
51
+
52
+ if ( angular . isObject ( modelValue ) ) {
53
+ modelValue . text += " - I've been formatted" ;
54
+ return modelValue ;
55
+ }
56
+
57
+ return modelValue + " - I've been formatted" ;
58
+ } ,
59
+ fromElement : function ( elementValue ) {
60
+ var suffix = " - I've been formatted" ;
61
+
62
+ if ( ! elementValue ) {
63
+ return elementValue ;
64
+ }
65
+
66
+ if ( angular . isArray ( elementValue ) ) {
67
+ return elementValue . map ( function ( val ) {
68
+ val . text += val . text . slice ( 0 , val . text . indexOf ( " - I've been formatted" ) ) ;
69
+ return val ;
70
+ } ) ;
71
+ }
72
+
73
+ if ( angular . isObject ( elementValue ) ) {
74
+
75
+ elementValue . text = elementValue . text . slice ( 0 , elementValue . text . indexOf ( suffix ) ) ;
76
+ return elementValue ;
77
+ }
78
+
79
+ if ( elementValue ) {
80
+ return elementValue . slice ( 0 , elementValue . indexOf ( suffix ) ) ;
81
+ }
82
+
83
+ return undefined ;
84
+ }
85
+ } ;
19
86
} ) ) ;
20
87
21
88
/**
@@ -94,7 +161,7 @@ describe('uiSelect2', function () {
94
161
compile ( '<input ui-select2/>' ) ;
95
162
} ) . toThrow ( ) ;
96
163
} ) ;
97
- it ( 'should creae proper DOM structure' , function ( ) {
164
+ it ( 'should create proper DOM structure' , function ( ) {
98
165
var element = compile ( '<input ui-select2="options" ng-model="foo"/>' ) ;
99
166
expect ( element . siblings ( ) . is ( 'div.select2-container' ) ) . toBe ( true ) ;
100
167
} ) ;
@@ -135,10 +202,95 @@ describe('uiSelect2', function () {
135
202
} ) ;
136
203
} ) ;
137
204
} ) ;
205
+ describe ( 'consumers of ngModel should correctly use $viewValue' , function ( ) {
206
+ it ( 'should use any formatters if present (select - single select)' , function ( ) {
207
+ scope . foo = 'First' ;
208
+ var element = compile ( '<select ui-select2 ng-model="foo" inject-transformers="transformers"><option>First - I\'ve been formatted</option><option>Second - I\'ve been formatted</option></select>' ) ;
209
+ expect ( element . select2 ( 'val' ) ) . toBe ( 'First - I\'ve been formatted' ) ;
210
+ scope . $apply ( 'foo = "Second"' ) ;
211
+ expect ( element . select2 ( 'val' ) ) . toBe ( 'Second - I\'ve been formatted' ) ;
212
+ } ) ;
213
+
214
+ // isMultiple && falsey
215
+ it ( 'should use any formatters if present (input multi select - falsey value)' , function ( ) {
216
+ // need special function to hit this case
217
+ // old code checked modelValue... can't just pass undefined to model value because view value will be the same
218
+ scope . transformers . fromModel = function ( modelValue ) {
219
+ if ( modelValue === "magic" ) {
220
+ return undefined ;
221
+ }
222
+
223
+ return modelValue ;
224
+ } ;
225
+
226
+ var element = compile ( '<input ng-model="foo" multiple ui-select2="options" inject-transformers="transformers">' ) ;
227
+ spyOn ( $ . fn , 'select2' ) ;
228
+ scope . $apply ( 'foo="magic"' ) ;
229
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'data' , [ ] ) ;
230
+ } ) ;
231
+ // isMultiple && isArray
232
+ it ( 'should use any formatters if present (input multi select)' , function ( ) {
233
+ var element = compile ( '<input ng-model="foo" multiple ui-select2="options" inject-transformers="transformers">' ) ;
234
+ spyOn ( $ . fn , 'select2' ) ;
235
+ scope . $apply ( 'foo=[{ id: 1, text: "first" },{ id: 2, text: "second" }]' ) ;
236
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'data' , [ { id : 1 , text : "first - I've been formatted" } , { id : 2 , text : "second - I've been formatted" } ] ) ;
237
+ } ) ;
238
+ // isMultiple...
239
+ it ( 'should use any formatters if present (input multi select - non array)' , function ( ) {
240
+ var element = compile ( '<input ng-model="foo" multiple ui-select2="options" inject-transformers="transformers">' ) ;
241
+ spyOn ( $ . fn , 'select2' ) ;
242
+ scope . $apply ( 'foo={ id: 1, text: "first" }' ) ;
243
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'val' , { id : 1 , text : "first - I've been formatted" } ) ;
244
+ } ) ;
245
+
246
+ // !isMultiple
247
+ it ( 'should use any formatters if present (input - single select - object)' , function ( ) {
248
+ var element = compile ( '<input ng-model="foo" ui-select2="options" inject-transformers="transformers">' ) ;
249
+ spyOn ( $ . fn , 'select2' ) ;
250
+ scope . $apply ( 'foo={ id: 1, text: "first" }' ) ;
251
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'data' , { id : 1 , text : "first - I've been formatted" } ) ;
252
+ } ) ;
253
+ it ( 'should use any formatters if present (input - single select - non object)' , function ( ) {
254
+ var element = compile ( '<input ng-model="foo" ui-select2="options" inject-transformers="transformers">' ) ;
255
+ spyOn ( $ . fn , 'select2' ) ;
256
+ scope . $apply ( 'foo="first"' ) ;
257
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'val' , "first - I've been formatted" ) ;
258
+ } ) ;
259
+
260
+ it ( 'should not set the default value using scope.$eval' , function ( ) {
261
+ // testing directive instantiation - change order of test
262
+ spyOn ( $ . fn , 'select2' ) ;
263
+ spyOn ( $ . fn , 'val' ) ;
264
+ scope . $apply ( 'foo=[{ id: 1, text: "first" },{ id: 2, text: "second" }]' ) ;
265
+
266
+ var element = compile ( '<input ng-model="foo" multiple ui-select2="options" inject-transformers="transformers">' ) ;
267
+ expect ( element . val ) . not . toHaveBeenCalledWith ( [ { id : 1 , text : "first" } , { id : 2 , text : "second" } ] ) ;
268
+ } ) ;
269
+ it ( 'should expect a default value to be set with a call to the render method' , function ( ) {
270
+ // this should monitor the events after init, when the timeout callback executes
271
+ var opts = angular . copy ( scope . options ) ;
272
+ opts . multiple = true ;
273
+
274
+ scope . $apply ( 'foo=[{ id: 1, text: "first" },{ id: 2, text: "second" }]' ) ;
275
+
276
+ spyOn ( $ . fn , 'select2' ) ;
277
+ var element = compile ( '<input ng-model="foo" multiple ui-select2="options" inject-transformers="transformers">' ) ;
278
+
279
+ // select 2 init
280
+ expect ( element . select2 ) . toHaveBeenCalledWith ( opts ) ;
281
+
282
+ // callback setting
283
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'data' , [ { id : 1 , text : "first - I've been formatted" } , { id : 2 , text : "second - I've been formatted" } ] ) ;
284
+
285
+ // retieve data
286
+ expect ( element . select2 ) . toHaveBeenCalledWith ( 'data' ) ;
287
+ } ) ;
288
+
289
+ } ) ;
138
290
it ( 'should set the model when the user selects an item' , function ( ) {
139
291
var element = compile ( '<input ng-model="foo" multiple ui-select2="options">' ) ;
140
292
// TODO: programmactically select an option
141
- // expect(scope.foo).toBe(/* selected val */);
293
+ // expect(scope.foo).toBe(/* selected val */) ;
142
294
} ) ;
143
295
} ) ;
144
296
} ) ;
0 commit comments