@angular-wave/angular.ts 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (645) hide show
  1. package/@types/index.d.ts +1 -84
  2. package/{src/index.ts → @types/namespace.d.ts} +4 -24
  3. package/@types/router/template-factory.d.ts +2 -2
  4. package/dist/angular-ts.esm.js +3 -3
  5. package/dist/angular-ts.umd.js +3 -3
  6. package/dist/angular-ts.umd.min.js +1 -1
  7. package/package.json +9 -2
  8. package/.github/workflows/ci.yml +0 -104
  9. package/.github/workflows/gh-pages.yml +0 -75
  10. package/.husky/pre-commit +0 -5
  11. package/.prettierignore +0 -9
  12. package/CHANGELOG.md +0 -17667
  13. package/CODE_OF_CONDUCT.md +0 -3
  14. package/CONTRIBUTING.md +0 -247
  15. package/DEVELOPERS.md +0 -499
  16. package/Makefile +0 -60
  17. package/RELEASE.md +0 -86
  18. package/TRIAGING.md +0 -127
  19. package/docs/.cspell.yml +0 -8
  20. package/docs/.github/dependabot.yml +0 -14
  21. package/docs/.nvmrc +0 -1
  22. package/docs/CONTRIBUTING.md +0 -28
  23. package/docs/Dockerfile +0 -4
  24. package/docs/LICENSE +0 -201
  25. package/docs/README.md +0 -217
  26. package/docs/assets/icons/logo.svg +0 -1
  27. package/docs/assets/scss/_variables_project.scss +0 -12
  28. package/docs/assets/scss/_variables_project_after_bs.scss +0 -8
  29. package/docs/assets/scss/index.scss +0 -48
  30. package/docs/config.yaml +0 -15
  31. package/docs/content/_index.md +0 -28
  32. package/docs/content/docs/_index.md +0 -61
  33. package/docs/content/docs/directive/_index.md +0 -4
  34. package/docs/content/docs/directive/app.md +0 -11
  35. package/docs/content/docs/directive/aria.md +0 -0
  36. package/docs/content/docs/directive/bind.md +0 -72
  37. package/docs/content/docs/directive/blur.md +0 -38
  38. package/docs/content/docs/directive/channel.md +0 -37
  39. package/docs/content/docs/directive/class-even.md +0 -47
  40. package/docs/content/docs/directive/class-odd.md +0 -48
  41. package/docs/content/docs/directive/class.md +0 -64
  42. package/docs/content/docs/directive/click.md +0 -41
  43. package/docs/content/docs/directive/cloak.md +0 -74
  44. package/docs/content/docs/directive/copy.md +0 -38
  45. package/docs/content/docs/directive/cut.md +0 -40
  46. package/docs/content/docs/directive/dblclick.md +0 -41
  47. package/docs/content/docs/directive/focus.md +0 -38
  48. package/docs/content/docs/directive/get.md +0 -203
  49. package/docs/content/docs/directive/include.md +0 -7
  50. package/docs/content/docs/directive/keydown.md +0 -38
  51. package/docs/content/docs/directive/keyup.md +0 -38
  52. package/docs/content/docs/directive/load.md +0 -43
  53. package/docs/content/docs/directive/mousedown.md +0 -38
  54. package/docs/content/docs/directive/mouseenter.md +0 -38
  55. package/docs/content/docs/directive/mouseleave.md +0 -38
  56. package/docs/content/docs/directive/mousemove.md +0 -38
  57. package/docs/content/docs/directive/mouseout.md +0 -38
  58. package/docs/content/docs/directive/mouseover.md +0 -38
  59. package/docs/content/docs/directive/mouseup.md +0 -38
  60. package/docs/content/docs/directive/non-bindable.md +0 -28
  61. package/docs/content/docs/filter/_index.md +0 -4
  62. package/docs/content/docs/filter/filter.md +0 -78
  63. package/docs/content/docs/filter/json.md +0 -19
  64. package/docs/content/docs/filter/limit-to.md +0 -30
  65. package/docs/content/docs/filter/order-by.md +0 -123
  66. package/docs/content/docs/provider/_index.md +0 -4
  67. package/docs/content/docs/provider/eventBusProvider.md +0 -35
  68. package/docs/content/docs/provider/locationProvider.md +0 -26
  69. package/docs/content/docs/provider/logProvider.md +0 -59
  70. package/docs/content/docs/provider/sceProvider.md +0 -194
  71. package/docs/content/docs/provider/templateCacheProvider.md +0 -100
  72. package/docs/content/docs/provider/templateRequestProvider.md +0 -5
  73. package/docs/content/docs/service/_index.md +0 -4
  74. package/docs/content/docs/service/compile.md +0 -5
  75. package/docs/content/docs/service/controller.md +0 -5
  76. package/docs/content/docs/service/eventBus.md +0 -56
  77. package/docs/content/docs/service/http.md +0 -161
  78. package/docs/content/docs/service/interpolation.md +0 -5
  79. package/docs/content/docs/service/location.md +0 -57
  80. package/docs/content/docs/service/log.md +0 -113
  81. package/docs/content/docs/service/parse.md +0 -5
  82. package/docs/content/docs/service/rootElement.md +0 -5
  83. package/docs/content/docs/service/rootScope.md +0 -5
  84. package/docs/content/docs/service/sce.md +0 -194
  85. package/docs/content/docs/service/templateCache.md +0 -64
  86. package/docs/content/docs/service/templateRequest.md +0 -5
  87. package/docs/content/docs/service/url.md +0 -5
  88. package/docs/content/docs/values/_index.md +0 -4
  89. package/docs/content/docs/values/document.md +0 -29
  90. package/docs/content/docs/values/window.md +0 -29
  91. package/docs/docker-compose.yaml +0 -12
  92. package/docs/docsy.work +0 -5
  93. package/docs/docsy.work.sum +0 -0
  94. package/docs/go.mod +0 -5
  95. package/docs/go.sum +0 -6
  96. package/docs/hugo-disabled.toml +0 -220
  97. package/docs/hugo.yaml +0 -200
  98. package/docs/layouts/404.html +0 -13
  99. package/docs/layouts/_markup/render-heading.html +0 -1
  100. package/docs/layouts/partials/hooks/head-end.html +0 -3
  101. package/docs/layouts/shortcodes/showcss.html +0 -2
  102. package/docs/layouts/shortcodes/showhtml.html +0 -2
  103. package/docs/layouts/shortcodes/showjs.html +0 -2
  104. package/docs/layouts/shortcodes/showraw.html +0 -1
  105. package/docs/layouts/shortcodes/version.html +0 -1
  106. package/docs/package-lock.json +0 -2293
  107. package/docs/package.json +0 -53
  108. package/docs/static/examples/counter/counter-test.html +0 -13
  109. package/docs/static/examples/counter/counter.html +0 -5
  110. package/docs/static/examples/counter/counter.test.js +0 -28
  111. package/docs/static/examples/document/document.html +0 -3
  112. package/docs/static/examples/eventbus/eventbus-test.html +0 -15
  113. package/docs/static/examples/eventbus/eventbus.html +0 -13
  114. package/docs/static/examples/eventbus/eventbus.js +0 -15
  115. package/docs/static/examples/eventbus/eventbus.test.js +0 -19
  116. package/docs/static/examples/i18n/i18n.html +0 -77
  117. package/docs/static/examples/ng-bind/ng-bind.html +0 -9
  118. package/docs/static/examples/ng-blur/ng-blur.html +0 -9
  119. package/docs/static/examples/ng-channel/ng-channel-test.html +0 -17
  120. package/docs/static/examples/ng-channel/ng-channel.html +0 -24
  121. package/docs/static/examples/ng-channel/ng-channel.test.js +0 -31
  122. package/docs/static/examples/ng-class/ng-class.html +0 -71
  123. package/docs/static/examples/ng-class-even/ng-class-even.html +0 -8
  124. package/docs/static/examples/ng-class-odd/ng-class-odd.html +0 -8
  125. package/docs/static/examples/ng-click/ng-click.html +0 -6
  126. package/docs/static/examples/ng-copy/ng-copy.html +0 -6
  127. package/docs/static/examples/ng-cut/ng-cut.html +0 -6
  128. package/docs/static/examples/ng-dblclick/ng-dblclick.html +0 -10
  129. package/docs/static/examples/ng-focus/ng-focus.html +0 -9
  130. package/docs/static/examples/ng-keydown/ng-keydown.html +0 -9
  131. package/docs/static/examples/ng-keyup/ng-keyup.html +0 -9
  132. package/docs/static/examples/ng-load/ng-load.html +0 -8
  133. package/docs/static/examples/ng-mousedown/ng-mousedown.html +0 -6
  134. package/docs/static/examples/ng-mouseenter/ng-mouseenter.html +0 -4
  135. package/docs/static/examples/ng-mouseleave/ng-mouseleave.html +0 -4
  136. package/docs/static/examples/ng-mousemove/ng-mousemove.html +0 -4
  137. package/docs/static/examples/ng-mouseout/ng-mouseout.html +0 -4
  138. package/docs/static/examples/ng-mouseover/ng-mouseover.html +0 -4
  139. package/docs/static/examples/ng-mouseup/ng-mouseup.html +0 -4
  140. package/docs/static/examples/ng-non-bindable/ng-non-bindable-test.html +0 -13
  141. package/docs/static/examples/ng-non-bindable/ng-non-bindable.html +0 -3
  142. package/docs/static/examples/ng-non-bindable/ng-non-bindable.test.js +0 -11
  143. package/docs/static/examples/window/window.html +0 -4
  144. package/docs/static/typedoc/.nojekyll +0 -1
  145. package/docs/static/typedoc/assets/hierarchy.js +0 -1
  146. package/docs/static/typedoc/assets/highlight.css +0 -29
  147. package/docs/static/typedoc/assets/icons.js +0 -18
  148. package/docs/static/typedoc/assets/icons.svg +0 -1
  149. package/docs/static/typedoc/assets/main.js +0 -60
  150. package/docs/static/typedoc/assets/navigation.js +0 -1
  151. package/docs/static/typedoc/assets/search.js +0 -1
  152. package/docs/static/typedoc/assets/style.css +0 -1633
  153. package/docs/static/typedoc/classes/Location.html +0 -55
  154. package/docs/static/typedoc/classes/LocationProvider.html +0 -20
  155. package/docs/static/typedoc/classes/LogProvider.html +0 -6
  156. package/docs/static/typedoc/classes/PubSub.html +0 -71
  157. package/docs/static/typedoc/classes/PubSubProvider.html +0 -4
  158. package/docs/static/typedoc/classes/TemplateCacheProvider.html +0 -5
  159. package/docs/static/typedoc/hierarchy.html +0 -1
  160. package/docs/static/typedoc/index.html +0 -1
  161. package/docs/static/typedoc/interfaces/DefaultPorts.html +0 -5
  162. package/docs/static/typedoc/interfaces/Html5Mode.html +0 -23
  163. package/docs/static/typedoc/interfaces/HttpHeadersGetter.html +0 -1
  164. package/docs/static/typedoc/interfaces/HttpProviderDefaults.html +0 -31
  165. package/docs/static/typedoc/interfaces/HttpRequestConfigHeaders.html +0 -6
  166. package/docs/static/typedoc/interfaces/HttpRequestTransformer.html +0 -1
  167. package/docs/static/typedoc/interfaces/HttpResponse.html +0 -7
  168. package/docs/static/typedoc/interfaces/HttpResponseTransformer.html +0 -1
  169. package/docs/static/typedoc/interfaces/HttpService.html +0 -38
  170. package/docs/static/typedoc/interfaces/LogService.html +0 -12
  171. package/docs/static/typedoc/interfaces/RequestConfig.html +0 -48
  172. package/docs/static/typedoc/interfaces/RequestShortcutConfig.html +0 -38
  173. package/docs/static/typedoc/interfaces/ServiceProvider.html +0 -5
  174. package/docs/static/typedoc/interfaces/UrlParts.html +0 -9
  175. package/docs/static/typedoc/types/HttpParamSerializer.html +0 -2
  176. package/docs/static/typedoc/types/HttpParams.html +0 -2
  177. package/docs/static/typedoc/types/HttpPromise.html +0 -1
  178. package/docs/static/typedoc/types/HttpResponseStatus.html +0 -1
  179. package/docs/static/typedoc/types/LogCall.html +0 -2
  180. package/docs/static/typedoc/types/LogServiceFactory.html +0 -2
  181. package/docs/static/typedoc/types/UrlChangeListener.html +0 -5
  182. package/docs/static/typedoc/variables/EventBus.html +0 -1
  183. package/docs/static/version.js +0 -13
  184. package/docs/test-results/.last-run.json +0 -4
  185. package/docs/test-results/static-examples-counter-counter-counter-example/error-context.md +0 -50
  186. package/eslint.config.js +0 -26
  187. package/images/android-chrome-192x192.png +0 -0
  188. package/images/android-chrome-512x512.png +0 -0
  189. package/images/apple-touch-icon.png +0 -0
  190. package/images/favicon-16x16.png +0 -0
  191. package/images/favicon-32x32.png +0 -0
  192. package/images/favicon.ico +0 -0
  193. package/images/site.webmanifest +0 -19
  194. package/index.html +0 -86
  195. package/legacy.d.ts +0 -1678
  196. package/playwright.config.ts +0 -81
  197. package/public/jasmine/boot0.js +0 -66
  198. package/public/jasmine/boot1.js +0 -134
  199. package/public/jasmine/jasmine-html.js +0 -970
  200. package/public/jasmine/jasmine.css +0 -323
  201. package/public/jasmine/jasmine.js +0 -11406
  202. package/public/public/README.md +0 -1
  203. package/public/public/circle.html +0 -1
  204. package/public/public/jasmine-helper.css +0 -9
  205. package/public/public/my_child_directive.html +0 -1
  206. package/public/public/my_directive.html +0 -1
  207. package/public/public/my_other_directive.html +0 -1
  208. package/public/public/test.html +0 -1
  209. package/rollup.config.js +0 -51
  210. package/src/angular.js +0 -286
  211. package/src/angular.spec.js +0 -1191
  212. package/src/animations/animate-cache.js +0 -80
  213. package/src/animations/animate-children-directive.js +0 -32
  214. package/src/animations/animate-children-directive.md +0 -80
  215. package/src/animations/animate-css-driver.js +0 -284
  216. package/src/animations/animate-css.html +0 -58
  217. package/src/animations/animate-css.js +0 -915
  218. package/src/animations/animate-css.md +0 -263
  219. package/src/animations/animate-js-driver.js +0 -60
  220. package/src/animations/animate-js.html +0 -47
  221. package/src/animations/animate-js.js +0 -371
  222. package/src/animations/animate-queue.js +0 -859
  223. package/src/animations/animate-runner.js +0 -193
  224. package/src/animations/animate-swap.js +0 -33
  225. package/src/animations/animate-swap.md +0 -88
  226. package/src/animations/animate.html +0 -19
  227. package/src/animations/animate.js +0 -546
  228. package/src/animations/animate.md +0 -933
  229. package/src/animations/animate.spec.js +0 -490
  230. package/src/animations/animation.js +0 -519
  231. package/src/animations/animations.test.js +0 -10
  232. package/src/animations/interface.ts +0 -19
  233. package/src/animations/raf-scheduler.html +0 -19
  234. package/src/animations/raf-scheduler.js +0 -92
  235. package/src/animations/raf-scheduler.spec.js +0 -98
  236. package/src/animations/shared.js +0 -341
  237. package/src/binding.html +0 -19
  238. package/src/binding.spec.js +0 -474
  239. package/src/binding.test.js +0 -10
  240. package/src/core/compile/attributes.js +0 -337
  241. package/src/core/compile/compile.html +0 -19
  242. package/src/core/compile/compile.js +0 -3271
  243. package/src/core/compile/compile.md +0 -1128
  244. package/src/core/compile/compile.spec.js +0 -15574
  245. package/src/core/compile/compile.test.js +0 -12
  246. package/src/core/controller/controller.html +0 -22
  247. package/src/core/controller/controller.js +0 -193
  248. package/src/core/controller/controller.spec.js +0 -334
  249. package/src/core/controller/controller.test.js +0 -12
  250. package/src/core/controller/interface.ts +0 -6
  251. package/src/core/core.html +0 -20
  252. package/src/core/core.test.js +0 -12
  253. package/src/core/di/injector.html +0 -19
  254. package/src/core/di/injector.js +0 -307
  255. package/src/core/di/injector.md +0 -740
  256. package/src/core/di/injector.spec.js +0 -2310
  257. package/src/core/di/injector.test.js +0 -12
  258. package/src/core/di/internal-injector.js +0 -286
  259. package/src/core/di/ng-module.html +0 -19
  260. package/src/core/di/ng-module.js +0 -229
  261. package/src/core/di/ng-module.spec.js +0 -263
  262. package/src/core/di/ng-module.test.js +0 -12
  263. package/src/core/filter/filter.html +0 -19
  264. package/src/core/filter/filter.js +0 -55
  265. package/src/core/filter/filter.md +0 -132
  266. package/src/core/filter/filter.spec.js +0 -149
  267. package/src/core/filter/filter.test.js +0 -12
  268. package/src/core/interpolate/interface.ts +0 -14
  269. package/src/core/interpolate/interpolate.html +0 -22
  270. package/src/core/interpolate/interpolate.js +0 -410
  271. package/src/core/interpolate/interpolate.spec.js +0 -601
  272. package/src/core/interpolate/interpolate.test.js +0 -12
  273. package/src/core/parse/ast/ast-node.ts +0 -81
  274. package/src/core/parse/ast/ast.html +0 -19
  275. package/src/core/parse/ast/ast.js +0 -574
  276. package/src/core/parse/ast/ast.spec.js +0 -1453
  277. package/src/core/parse/ast/ast.test.js +0 -10
  278. package/src/core/parse/ast-type.js +0 -23
  279. package/src/core/parse/interface.ts +0 -84
  280. package/src/core/parse/interpreter.js +0 -915
  281. package/src/core/parse/lexer/lexer.html +0 -19
  282. package/src/core/parse/lexer/lexer.js +0 -338
  283. package/src/core/parse/lexer/lexer.spec.js +0 -303
  284. package/src/core/parse/lexer/lexer.test.js +0 -10
  285. package/src/core/parse/lexer/token.ts +0 -22
  286. package/src/core/parse/parse.html +0 -19
  287. package/src/core/parse/parse.js +0 -337
  288. package/src/core/parse/parse.md +0 -57
  289. package/src/core/parse/parse.spec.js +0 -2107
  290. package/src/core/parse/parse.test.js +0 -10
  291. package/src/core/parse/parser/parser.html +0 -19
  292. package/src/core/parse/parser/parser.js +0 -64
  293. package/src/core/parse/parser/parser.spec.js +0 -8
  294. package/src/core/parse/parser/parser.test.js +0 -10
  295. package/src/core/prop.spec.js +0 -775
  296. package/src/core/root-element.spec.js +0 -14
  297. package/src/core/sanitize/interface.ts +0 -10
  298. package/src/core/sanitize/sanitize-uri.js +0 -75
  299. package/src/core/sanitize/sanitize-uri.spec.js +0 -249
  300. package/src/core/sanitize/sanitize-uri.test.js +0 -12
  301. package/src/core/sanitize/sanitize.html +0 -22
  302. package/src/core/scope/scope.html +0 -19
  303. package/src/core/scope/scope.js +0 -1252
  304. package/src/core/scope/scope.spec.js +0 -3000
  305. package/src/core/scope/scope.test.js +0 -12
  306. package/src/directive/aria/aria.html +0 -19
  307. package/src/directive/aria/aria.js +0 -382
  308. package/src/directive/aria/aria.md +0 -145
  309. package/src/directive/aria/aria.spec.js +0 -1241
  310. package/src/directive/aria/aria.test.js +0 -12
  311. package/src/directive/attrs/attrs.html +0 -19
  312. package/src/directive/attrs/attrs.js +0 -106
  313. package/src/directive/attrs/attrs.md +0 -224
  314. package/src/directive/attrs/attrs.spec.js +0 -71
  315. package/src/directive/attrs/attrs.test.js +0 -12
  316. package/src/directive/attrs/boolean.html +0 -19
  317. package/src/directive/attrs/boolean.spec.js +0 -137
  318. package/src/directive/attrs/boolean.test.js +0 -12
  319. package/src/directive/attrs/element-style.html +0 -22
  320. package/src/directive/attrs/element-style.spec.js +0 -85
  321. package/src/directive/attrs/element-style.test.js +0 -12
  322. package/src/directive/attrs/src.html +0 -19
  323. package/src/directive/attrs/src.spec.js +0 -163
  324. package/src/directive/attrs/src.test.js +0 -12
  325. package/src/directive/bind/bind-html.spec.js +0 -36
  326. package/src/directive/bind/bind.html +0 -20
  327. package/src/directive/bind/bind.js +0 -78
  328. package/src/directive/bind/bind.md +0 -142
  329. package/src/directive/bind/bind.spec.js +0 -314
  330. package/src/directive/bind/bind.test.js +0 -12
  331. package/src/directive/channel/channel.html +0 -19
  332. package/src/directive/channel/channel.js +0 -30
  333. package/src/directive/channel/channel.spec.js +0 -67
  334. package/src/directive/channel/channel.test.js +0 -10
  335. package/src/directive/class/class-test.html +0 -23
  336. package/src/directive/class/class.html +0 -19
  337. package/src/directive/class/class.js +0 -184
  338. package/src/directive/class/class.spec.js +0 -704
  339. package/src/directive/class/class.test.js +0 -12
  340. package/src/directive/cloak/cloak.html +0 -19
  341. package/src/directive/cloak/cloak.js +0 -11
  342. package/src/directive/cloak/cloak.spec.js +0 -44
  343. package/src/directive/cloak/cloak.test.js +0 -12
  344. package/src/directive/controller/controller.html +0 -22
  345. package/src/directive/controller/controller.js +0 -11
  346. package/src/directive/controller/controller.md +0 -46
  347. package/src/directive/controller/controller.spec.js +0 -175
  348. package/src/directive/controller/controller.test.js +0 -12
  349. package/src/directive/events/click.spec.js +0 -35
  350. package/src/directive/events/event.spec.js +0 -267
  351. package/src/directive/events/events-test.html +0 -36
  352. package/src/directive/events/events.html +0 -20
  353. package/src/directive/events/events.js +0 -65
  354. package/src/directive/events/events.md +0 -125
  355. package/src/directive/events/events.test.js +0 -12
  356. package/src/directive/form/form.html +0 -19
  357. package/src/directive/form/form.js +0 -669
  358. package/src/directive/form/form.spec.js +0 -1515
  359. package/src/directive/form/form.test.js +0 -12
  360. package/src/directive/http/delete.spec.js +0 -23
  361. package/src/directive/http/form-router-test.html +0 -44
  362. package/src/directive/http/form-test.html +0 -18
  363. package/src/directive/http/get.spec.js +0 -488
  364. package/src/directive/http/http.html +0 -22
  365. package/src/directive/http/http.js +0 -342
  366. package/src/directive/http/http.test.js +0 -12
  367. package/src/directive/http/interface.ts +0 -36
  368. package/src/directive/http/post-example.html +0 -30
  369. package/src/directive/http/post.spec.js +0 -521
  370. package/src/directive/http/put.spec.js +0 -23
  371. package/src/directive/if/if-animate-css.html +0 -57
  372. package/src/directive/if/if-animate-svg.html +0 -25
  373. package/src/directive/if/if.html +0 -19
  374. package/src/directive/if/if.js +0 -72
  375. package/src/directive/if/if.md +0 -76
  376. package/src/directive/if/if.spec.js +0 -293
  377. package/src/directive/if/if.test.js +0 -114
  378. package/src/directive/include/include.html +0 -19
  379. package/src/directive/include/include.js +0 -151
  380. package/src/directive/include/include.md +0 -87
  381. package/src/directive/include/include.spec.js +0 -734
  382. package/src/directive/include/include.test.js +0 -12
  383. package/src/directive/init/init.html +0 -19
  384. package/src/directive/init/init.js +0 -22
  385. package/src/directive/init/init.md +0 -41
  386. package/src/directive/init/init.spec.js +0 -68
  387. package/src/directive/init/init.test.js +0 -12
  388. package/src/directive/inject/inject.html +0 -19
  389. package/src/directive/inject/inject.js +0 -35
  390. package/src/directive/inject/inject.spec.js +0 -108
  391. package/src/directive/inject/inject.test.js +0 -12
  392. package/src/directive/input/input-example.html +0 -15
  393. package/src/directive/input/input.html +0 -19
  394. package/src/directive/input/input.js +0 -1078
  395. package/src/directive/input/input.md +0 -706
  396. package/src/directive/input/input.spec.js +0 -3700
  397. package/src/directive/input/input.test.js +0 -12
  398. package/src/directive/messages/messages.html +0 -22
  399. package/src/directive/messages/messages.js +0 -349
  400. package/src/directive/messages/messages.md +0 -543
  401. package/src/directive/messages/messages.spec.js +0 -1083
  402. package/src/directive/messages/messages.test.js +0 -12
  403. package/src/directive/model/change.md +0 -25
  404. package/src/directive/model/model.html +0 -19
  405. package/src/directive/model/model.js +0 -1170
  406. package/src/directive/model/model.spec.js +0 -1976
  407. package/src/directive/model/model.test.js +0 -12
  408. package/src/directive/model-options/model-option.test.js +0 -12
  409. package/src/directive/model-options/model-options.html +0 -22
  410. package/src/directive/model-options/model-options.js +0 -142
  411. package/src/directive/model-options/model-options.md +0 -407
  412. package/src/directive/model-options/model-options.spec.js +0 -1022
  413. package/src/directive/non-bindable/non-bindable.html +0 -22
  414. package/src/directive/non-bindable/non-bindable.js +0 -9
  415. package/src/directive/non-bindable/non-bindable.spec.js +0 -59
  416. package/src/directive/non-bindable/non-bindable.test.js +0 -12
  417. package/src/directive/observe/observe-demo.html +0 -184
  418. package/src/directive/observe/observe.html +0 -19
  419. package/src/directive/observe/observe.js +0 -41
  420. package/src/directive/observe/observe.spec.js +0 -106
  421. package/src/directive/observe/observe.test.js +0 -10
  422. package/src/directive/on/on.html +0 -19
  423. package/src/directive/on/on.spec.js +0 -215
  424. package/src/directive/on/on.test.js +0 -12
  425. package/src/directive/options/options-example.html +0 -17
  426. package/src/directive/options/options.html +0 -22
  427. package/src/directive/options/options.js +0 -542
  428. package/src/directive/options/options.md +0 -179
  429. package/src/directive/options/options.spec.js +0 -3554
  430. package/src/directive/options/options.test.js +0 -12
  431. package/src/directive/ref/href.html +0 -19
  432. package/src/directive/ref/href.spec.js +0 -141
  433. package/src/directive/ref/href.test.js +0 -19
  434. package/src/directive/ref/ref.html +0 -19
  435. package/src/directive/ref/ref.js +0 -89
  436. package/src/directive/ref/ref.spec.js +0 -546
  437. package/src/directive/repeat/repeat.html +0 -19
  438. package/src/directive/repeat/repeat.js +0 -333
  439. package/src/directive/repeat/repeat.md +0 -330
  440. package/src/directive/repeat/repeat.spec.js +0 -1209
  441. package/src/directive/repeat/repeat.test.js +0 -12
  442. package/src/directive/script/script.html +0 -19
  443. package/src/directive/script/script.js +0 -17
  444. package/src/directive/script/script.md +0 -11
  445. package/src/directive/script/script.spec.js +0 -47
  446. package/src/directive/script/script.test.js +0 -12
  447. package/src/directive/select/select.html +0 -19
  448. package/src/directive/select/select.js +0 -594
  449. package/src/directive/select/select.md +0 -74
  450. package/src/directive/select/select.spec.js +0 -2566
  451. package/src/directive/select/select.test.js +0 -12
  452. package/src/directive/setter/setter.html +0 -19
  453. package/src/directive/setter/setter.js +0 -59
  454. package/src/directive/setter/setter.spec.js +0 -100
  455. package/src/directive/setter/setter.test.js +0 -12
  456. package/src/directive/show-hide/show-hide.html +0 -22
  457. package/src/directive/show-hide/show-hide.js +0 -65
  458. package/src/directive/show-hide/show-hide.md +0 -255
  459. package/src/directive/show-hide/show-hide.spec.js +0 -268
  460. package/src/directive/show-hide/show-hide.test.js +0 -12
  461. package/src/directive/style/style.html +0 -19
  462. package/src/directive/style/style.js +0 -27
  463. package/src/directive/style/style.md +0 -23
  464. package/src/directive/style/style.spec.js +0 -183
  465. package/src/directive/style/style.test.js +0 -12
  466. package/src/directive/switch/switch.html +0 -19
  467. package/src/directive/switch/switch.js +0 -133
  468. package/src/directive/switch/switch.md +0 -66
  469. package/src/directive/switch/switch.spec.js +0 -509
  470. package/src/directive/switch/switch.test.js +0 -12
  471. package/src/directive/transclude/transclude.js +0 -122
  472. package/src/directive/validators/validators.html +0 -22
  473. package/src/directive/validators/validators.js +0 -346
  474. package/src/directive/validators/validators.spec.js +0 -740
  475. package/src/directive/validators/validators.test.js +0 -12
  476. package/src/filters/filter.js +0 -213
  477. package/src/filters/filter.spec.js +0 -719
  478. package/src/filters/filters.html +0 -22
  479. package/src/filters/filters.js +0 -239
  480. package/src/filters/filters.spec.js +0 -36
  481. package/src/filters/filters.test.js +0 -12
  482. package/src/filters/interface.ts +0 -9
  483. package/src/filters/limit-to.js +0 -55
  484. package/src/filters/limit-to.spec.js +0 -252
  485. package/src/filters/order-by.js +0 -181
  486. package/src/filters/order-by.spec.js +0 -883
  487. package/src/index.js +0 -6
  488. package/src/index.spec.js +0 -11
  489. package/src/injection-tokens.js +0 -81
  490. package/src/interface.ts +0 -430
  491. package/src/ng.js +0 -291
  492. package/src/ng.spec.js +0 -45
  493. package/src/router/common/trace.js +0 -240
  494. package/src/router/directives/component-example.html +0 -37
  495. package/src/router/directives/state-directives.html +0 -22
  496. package/src/router/directives/state-directives.js +0 -393
  497. package/src/router/directives/state-directives.md +0 -435
  498. package/src/router/directives/state-directives.spec.js +0 -1091
  499. package/src/router/directives/state-directives.test.js +0 -10
  500. package/src/router/directives/view-directive.js +0 -489
  501. package/src/router/directives/view-directive.spec.js +0 -1921
  502. package/src/router/directives/view-directive.test.js +0 -10
  503. package/src/router/directives/view-directives.html +0 -22
  504. package/src/router/glob/glob.html +0 -19
  505. package/src/router/glob/glob.js +0 -102
  506. package/src/router/glob/glob.spec.js +0 -108
  507. package/src/router/glob/glob.test.js +0 -12
  508. package/src/router/hooks/core-resolvables.js +0 -38
  509. package/src/router/hooks/ignored-transition.js +0 -25
  510. package/src/router/hooks/invalid-transition.js +0 -14
  511. package/src/router/hooks/lazy-load.js +0 -104
  512. package/src/router/hooks/on-enter-exit-retain.js +0 -55
  513. package/src/router/hooks/redirect-to.js +0 -38
  514. package/src/router/hooks/resolve.js +0 -57
  515. package/src/router/hooks/update-globals.js +0 -34
  516. package/src/router/hooks/url.js +0 -34
  517. package/src/router/hooks/views.js +0 -41
  518. package/src/router/params/interface.ts +0 -626
  519. package/src/router/params/param-factory.js +0 -23
  520. package/src/router/params/param-type.js +0 -133
  521. package/src/router/params/param-types.js +0 -153
  522. package/src/router/params/param.js +0 -243
  523. package/src/router/params/state-params.js +0 -36
  524. package/src/router/path/path-node.js +0 -78
  525. package/src/router/path/path-utils.js +0 -207
  526. package/src/router/resolve/interface.ts +0 -208
  527. package/src/router/resolve/resolvable.js +0 -123
  528. package/src/router/resolve/resolve-context.js +0 -190
  529. package/src/router/router-test-hashbang.html +0 -45
  530. package/src/router/router-test.html +0 -41
  531. package/src/router/router.html +0 -22
  532. package/src/router/router.js +0 -54
  533. package/src/router/router.test.js +0 -12
  534. package/src/router/services.spec.js +0 -52
  535. package/src/router/state/interface.ts +0 -1007
  536. package/src/router/state/state-builder.js +0 -376
  537. package/src/router/state/state-builder.spec.js +0 -86
  538. package/src/router/state/state-matcher.js +0 -64
  539. package/src/router/state/state-object.js +0 -118
  540. package/src/router/state/state-queue-manager.js +0 -95
  541. package/src/router/state/state-registry.js +0 -262
  542. package/src/router/state/state-service.js +0 -687
  543. package/src/router/state/state.html +0 -23
  544. package/src/router/state/state.spec.js +0 -1002
  545. package/src/router/state/state.test.js +0 -12
  546. package/src/router/state/target-state.js +0 -162
  547. package/src/router/state/views.js +0 -195
  548. package/src/router/state-filter.spec.js +0 -139
  549. package/src/router/state-filters.js +0 -46
  550. package/src/router/template-factory.html +0 -19
  551. package/src/router/template-factory.js +0 -249
  552. package/src/router/template-factory.spec.js +0 -146
  553. package/src/router/template-factory.test.js +0 -12
  554. package/src/router/transition/hook-builder.js +0 -137
  555. package/src/router/transition/hook-registry.js +0 -181
  556. package/src/router/transition/interface.js +0 -18
  557. package/src/router/transition/interface.ts +0 -922
  558. package/src/router/transition/reject-factory.js +0 -122
  559. package/src/router/transition/transition-event-type.js +0 -26
  560. package/src/router/transition/transition-hook.js +0 -199
  561. package/src/router/transition/transition-service.js +0 -297
  562. package/src/router/transition/transition.js +0 -653
  563. package/src/router/url/url-config.js +0 -155
  564. package/src/router/url/url-matcher.js +0 -532
  565. package/src/router/url/url-rule.js +0 -231
  566. package/src/router/url/url-rules.js +0 -350
  567. package/src/router/url/url-service.js +0 -446
  568. package/src/router/url/url-service.spec.js +0 -1288
  569. package/src/router/url/url.html +0 -19
  570. package/src/router/url/url.test.js +0 -12
  571. package/src/router/view/interface.ts +0 -51
  572. package/src/router/view/view.html +0 -19
  573. package/src/router/view/view.js +0 -262
  574. package/src/router/view/view.spec.js +0 -100
  575. package/src/router/view/view.test.js +0 -12
  576. package/src/router/view-hook.spec.js +0 -215
  577. package/src/router/view-scroll.js +0 -33
  578. package/src/router/view-scroll.spec.js +0 -72
  579. package/src/services/anchor-scroll/anchor-scroll.html +0 -76
  580. package/src/services/anchor-scroll/anchor-scroll.js +0 -147
  581. package/src/services/exception/exception-handler.js +0 -75
  582. package/src/services/exception/interface.ts +0 -7
  583. package/src/services/http/http.html +0 -23
  584. package/src/services/http/http.js +0 -1109
  585. package/src/services/http/http.spec.js +0 -4320
  586. package/src/services/http/http.test.js +0 -11
  587. package/src/services/http/interface.ts +0 -256
  588. package/src/services/http/template-request.spec.js +0 -220
  589. package/src/services/location/interface.ts +0 -70
  590. package/src/services/location/location.html +0 -22
  591. package/src/services/location/location.js +0 -1006
  592. package/src/services/location/location.spec.js +0 -3792
  593. package/src/services/location/location.test.js +0 -12
  594. package/src/services/log/interface.ts +0 -39
  595. package/src/services/log/log.html +0 -19
  596. package/src/services/log/log.js +0 -74
  597. package/src/services/log/log.spec.js +0 -64
  598. package/src/services/log/log.test.js +0 -12
  599. package/src/services/pubsub/pubsub.html +0 -19
  600. package/src/services/pubsub/pubsub.js +0 -349
  601. package/src/services/pubsub/pubsub.spec.js +0 -400
  602. package/src/services/pubsub/pubsub.test.js +0 -12
  603. package/src/services/sce/sce.html +0 -19
  604. package/src/services/sce/sce.js +0 -852
  605. package/src/services/sce/sce.spec.js +0 -617
  606. package/src/services/sce/sce.test.js +0 -12
  607. package/src/services/template-cache/template-cache.html +0 -22
  608. package/src/services/template-cache/template-cache.js +0 -15
  609. package/src/services/template-cache/template-cache.spec.js +0 -134
  610. package/src/services/template-cache/template-cache.test.js +0 -12
  611. package/src/services/template-request/interface.ts +0 -23
  612. package/src/services/template-request/template-request.js +0 -142
  613. package/src/shared/cache.js +0 -7
  614. package/src/shared/common.js +0 -365
  615. package/src/shared/common.spec.js +0 -294
  616. package/src/shared/constants.js +0 -21
  617. package/src/shared/dom.js +0 -716
  618. package/src/shared/hof.js +0 -157
  619. package/src/shared/hof.spec.js +0 -60
  620. package/src/shared/interface.ts +0 -21
  621. package/src/shared/min-err.spec.js +0 -178
  622. package/src/shared/noderef.js +0 -225
  623. package/src/shared/predicates.js +0 -34
  624. package/src/shared/queue.js +0 -105
  625. package/src/shared/queue.spec.js +0 -80
  626. package/src/shared/shared.html +0 -24
  627. package/src/shared/shared.test.js +0 -12
  628. package/src/shared/strings.js +0 -142
  629. package/src/shared/strings.spec.js +0 -40
  630. package/src/shared/test-utils.js +0 -47
  631. package/src/shared/url-utils/interface.ts +0 -54
  632. package/src/shared/url-utils/url-utils.html +0 -22
  633. package/src/shared/url-utils/url-utils.js +0 -122
  634. package/src/shared/url-utils/url-utils.spec.js +0 -148
  635. package/src/shared/url-utils/url-utils.test.js +0 -12
  636. package/src/shared/utils.js +0 -1255
  637. package/src/shared/utils.spec.js +0 -178
  638. package/src/src.html +0 -21
  639. package/src/src.test.js +0 -10
  640. package/tsconfig.json +0 -19
  641. package/tsconfig.types.json +0 -14
  642. package/typedoc.json +0 -8
  643. package/utils/express.js +0 -203
  644. package/utils/version.cjs +0 -23
  645. package/vite.config.js +0 -14
@@ -1,3554 +0,0 @@
1
- import { createInjector } from "../../core/di/injector.js";
2
- import { dealoc, getController } from "../../shared/dom.js";
3
- import { Angular } from "../../angular.js";
4
- import {
5
- isBoolean,
6
- hashKey,
7
- equals,
8
- isString,
9
- isFunction,
10
- } from "../../shared/utils.js";
11
- import { browserTrigger, wait } from "../../shared/test-utils.js";
12
-
13
- describe("ngOptions", () => {
14
- let scope;
15
- let formElement;
16
- let element;
17
- let $compile;
18
- let linkLog;
19
- let childListMutationObserver;
20
- let ngModelCtrl;
21
- let injector;
22
- let errors = [];
23
-
24
- async function compile(html) {
25
- element.innerHTML = `<form name="form">${html}</form>`;
26
- formElement = $compile(element)(scope);
27
- await wait();
28
- element = formElement.querySelector("select");
29
- ngModelCtrl = getController(element, "ngModel");
30
- }
31
-
32
- function setSelectValue(selectElement, optionIndex) {
33
- const option = selectElement.querySelector("option")[optionIndex];
34
- selectElement.value = option.value;
35
- browserTrigger(element, "change");
36
- }
37
-
38
- beforeEach(() => {
39
- jasmine.addMatchers({
40
- toEqualSelectValue() {
41
- return {
42
- compare(_actual_, value, multiple) {
43
- const errors = [];
44
- let actual = _actual_.value;
45
-
46
- if (multiple) {
47
- value = value.map((val) => hashKey(val));
48
- actual = actual || [];
49
- } else {
50
- value = hashKey(value);
51
- }
52
-
53
- if (!equals(actual, value)) {
54
- errors.push(
55
- `Expected select value "${actual}" to equal "${value}"`,
56
- );
57
- }
58
- const message = function () {
59
- return errors.join("\n");
60
- };
61
-
62
- return { pass: errors.length === 0, message };
63
- },
64
- };
65
- },
66
- toEqualOption() {
67
- return {
68
- compare(actual, value, text, label) {
69
- const errors = [];
70
- const hash = hashKey(value);
71
- if (actual.getAttribute("value") !== hash) {
72
- errors.push(
73
- `Expected option value "${actual.getAttribute("value")}" to equal "${hash}"`,
74
- );
75
- }
76
- if (text && actual.textContent !== text) {
77
- errors.push(
78
- `Expected option text "${actual.textContent}" to equal "${text}"`,
79
- );
80
- }
81
- if (label && actual.getAttribute("label") !== label) {
82
- errors.push(
83
- `Expected option label "${actual.getAttribute("label")}" to equal "${label}"`,
84
- );
85
- }
86
-
87
- const message = function () {
88
- return errors.join("\n");
89
- };
90
-
91
- return { pass: errors.length === 0, message };
92
- },
93
- };
94
- },
95
- toEqualTrackedOption() {
96
- return {
97
- compare(actual, value, text, label) {
98
- const errors = [];
99
- if (actual.getAttribute("value") !== `${value}`) {
100
- errors.push(
101
- `Expected option value "${actual.getAttribute("value")}" to equal "${value}"`,
102
- );
103
- }
104
- if (text && actual.textContent !== text) {
105
- errors.push(
106
- `Expected option text "${actual.textContent}" to equal "${text}"`,
107
- );
108
- }
109
- if (label && actual.getAttribute("label") !== label) {
110
- errors.push(
111
- `Expected option label "${actual.getAttribute("label")}" to equal "${label}"`,
112
- );
113
- }
114
-
115
- const message = function () {
116
- return errors.join("\n");
117
- };
118
-
119
- return { pass: errors.length === 0, message };
120
- },
121
- };
122
- },
123
- toEqualUnknownOption() {
124
- return {
125
- compare(actual) {
126
- const errors = [];
127
- if (actual.getAttribute("value") !== "?") {
128
- errors.push(
129
- `Expected option value "${actual.getAttribute("value")}" to equal "?"`,
130
- );
131
- }
132
-
133
- const message = function () {
134
- return errors.join("\n");
135
- };
136
-
137
- return { pass: errors.length === 0, message };
138
- },
139
- };
140
- },
141
- toEqualUnknownValue() {
142
- return {
143
- compare(actual, value) {
144
- const errors = [];
145
- if (actual !== "?") {
146
- errors.push(`Expected select value "${actual}" to equal "?"`);
147
- }
148
-
149
- const message = function () {
150
- return errors.join("\n");
151
- };
152
-
153
- return { pass: errors.length === 0, message };
154
- },
155
- };
156
- },
157
- });
158
- });
159
-
160
- beforeEach(() => {
161
- errors = [];
162
- element = document.getElementById("app");
163
- element.innerHTML = "test";
164
- dealoc(document.getElementById("app"));
165
- window.angular = new Angular();
166
- window.angular
167
- .module("myModule", ["ng"])
168
- .decorator("$exceptionHandler", function () {
169
- return (exception) => {
170
- console.error(exception.message);
171
- errors.push(exception.message);
172
- };
173
- });
174
- injector = createInjector([
175
- "myModule",
176
- ($compileProvider, $provide) => {
177
- linkLog = [];
178
-
179
- $compileProvider
180
- .directive("customSelect", () => ({
181
- restrict: "E",
182
- replace: true,
183
- scope: {
184
- ngModel: "=",
185
- options: "=",
186
- },
187
- templateUrl: "select_template.html",
188
- link(scope) {
189
- scope.selectable_options = scope.options;
190
- },
191
- }))
192
-
193
- .directive("oCompileContents", () => ({
194
- link(scope, element) {
195
- linkLog.push("linkCompileContents");
196
- $compile(element.childNodes)(scope);
197
- },
198
- }))
199
-
200
- .directive("observeChildList", () => ({
201
- link(scope, element) {
202
- const config = { childList: true };
203
-
204
- childListMutationObserver = new window.MutationObserver(() => {});
205
- childListMutationObserver.observe(element, config);
206
- },
207
- }));
208
-
209
- $provide.decorator("ngOptionsDirective", ($delegate) => {
210
- const origPreLink = $delegate[0].link.pre;
211
- const origPostLink = $delegate[0].link.post;
212
-
213
- $delegate[0].compile = function () {
214
- return {
215
- pre: origPreLink,
216
- post() {
217
- linkLog.push("linkNgOptions");
218
- origPostLink.apply(this, arguments);
219
- },
220
- };
221
- };
222
-
223
- return $delegate;
224
- });
225
- },
226
- ]);
227
- $compile = injector.get("$compile");
228
- scope = injector.get("$rootScope").$new(); // create a child scope because the root scope can't be $destroy-ed
229
- });
230
-
231
- afterEach(() => {
232
- // scope.$destroy(); // disables unknown option work during destruction
233
- // dealoc(formElement);
234
- // ngModelCtrl = null;
235
- });
236
-
237
- async function createSelect(attrs, blank, unknown) {
238
- let html = "<select";
239
- Object.entries(attrs).forEach(([key, value]) => {
240
- if (isBoolean(value)) {
241
- if (value) html += ` ${key}`;
242
- } else {
243
- html += ` ${key}="${value}"`;
244
- }
245
- });
246
- html += `>${
247
- blank ? (isString(blank) ? blank : '<option value="">blank</option>') : ""
248
- }${
249
- unknown
250
- ? isString(unknown)
251
- ? unknown
252
- : '<option value="?">unknown</option>'
253
- : ""
254
- }</select>`;
255
- element.innerHTML = html;
256
-
257
- await compile(element);
258
- }
259
-
260
- function createSingleSelect(blank, unknown) {
261
- createSelect(
262
- {
263
- "ng-model": "selected",
264
- "ng-options": "value.name for value in values",
265
- },
266
- blank,
267
- unknown,
268
- );
269
- }
270
-
271
- function createMultiSelect(blank, unknown) {
272
- createSelect(
273
- {
274
- "ng-model": "selected",
275
- multiple: true,
276
- "ng-options": "value.name for value in values",
277
- },
278
- blank,
279
- unknown,
280
- );
281
- }
282
-
283
- fit('should throw when not formated "? for ? in ?"', async () => {
284
- compile('<select ng-model="selected" ng-options="i dont parse"></select>');
285
- await wait();
286
- expect(errors[0]).toMatch("iexp");
287
- });
288
-
289
- fit("should have a dependency on ngModel", async () => {
290
- try {
291
- await compile('<select ng-options="item in items"></select>');
292
- await wait();
293
- } catch (error) {
294
- expect(error.message).toMatch("ngModel");
295
- }
296
- });
297
-
298
- fit("should render a list", async () => {
299
- compile(
300
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
301
- );
302
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
303
- scope.selected = scope.values[1];
304
- await wait();
305
- const options = element.querySelectorAll("option");
306
- expect(options.length).toEqual(3);
307
- expect(options[0]).toEqualOption(scope.values[0], "A");
308
- expect(options[1]).toEqualOption(scope.values[1], "B");
309
- expect(options[2]).toEqualOption(scope.values[2], "C");
310
- expect(options[1].selected).toEqual(true);
311
- });
312
-
313
- fit("should not include properties with non-numeric keys in array-like collections when using array syntax", async () => {
314
- compile(
315
- '<select ng-model="selected" ng-options="value for value in values"></select>',
316
- );
317
- scope.values = { 0: "X", 1: "Y", 2: "Z", a: "A", length: 3 };
318
- await wait();
319
- scope.selected = scope.values[1];
320
- await wait();
321
- const options = element.querySelectorAll("option");
322
- expect(options.length).toEqual(3);
323
- expect(options[0]).toEqualOption("X");
324
- expect(options[1]).toEqualOption("Y");
325
- expect(options[2]).toEqualOption("Z");
326
- });
327
-
328
- fit("should include properties with non-numeric keys in array-like collections when using object syntax", async () => {
329
- compile(
330
- '<select ng-model="selected" ng-options="value for (key, value) in values"></select>',
331
- );
332
- scope.values = { 0: "X", 1: "Y", 2: "Z", a: "A", length: 3 };
333
- scope.selected = scope.values[1];
334
- await wait();
335
- const options = element.querySelectorAll("option");
336
- expect(options.length).toEqual(5);
337
- expect(options[0]).toEqualOption("X");
338
- expect(options[1]).toEqualOption("Y");
339
- expect(options[2]).toEqualOption("Z");
340
- expect(options[3]).toEqualOption("A");
341
- expect(options[4]).toEqualOption(3);
342
- });
343
-
344
- fit("should render an object", async () => {
345
- compile(
346
- '<select ng-model="selected" ng-options="value as key for (key, value) in object"></select>',
347
- );
348
- scope.object = { red: "FF0000", green: "00FF00", blue: "0000FF" };
349
- scope.selected = scope.object.green;
350
- await wait();
351
-
352
- let options = element.querySelectorAll("option");
353
- expect(options.length).toEqual(3);
354
- expect(options[0]).toEqualOption("FF0000", "red");
355
- expect(options[1]).toEqualOption("00FF00", "green");
356
- expect(options[2]).toEqualOption("0000FF", "blue");
357
- expect(options[1].selected).toEqual(true);
358
- scope.$apply('object.azur = "8888FF"');
359
- await wait();
360
- options = element.querySelectorAll("option");
361
- expect(options[1].selected).toEqual(true);
362
- await wait();
363
- scope.$apply("selected = object.azur");
364
- await wait();
365
- options = element.querySelectorAll("option");
366
- expect(options[3].selected).toEqual(true);
367
- });
368
-
369
- fit('should set the "selected" attribute and property on selected options', async () => {
370
- compile(
371
- '<select ng-model="selected" ng-options="option.id as option.display for option in values"></select>',
372
- );
373
- scope.values = [
374
- {
375
- id: "FF0000",
376
- display: "red",
377
- },
378
- {
379
- id: "0000FF",
380
- display: "blue",
381
- },
382
- ];
383
- scope.selected = "FF0000";
384
- await wait();
385
-
386
- const options = element.querySelectorAll("option");
387
- expect(options.length).toEqual(2);
388
- expect(options[0]).toEqualOption("FF0000", "red");
389
- expect(options[1]).toEqualOption("0000FF", "blue");
390
-
391
- expect(options[0].getAttribute("selected")).toBe("selected");
392
- expect(options[0].getAttribute("selected")).toBe("selected");
393
- expect(options[0].selected).toBe(true);
394
- expect(options[0].selected).toBe(true);
395
-
396
- scope.selected = "0000FF";
397
- await wait();
398
- expect(options[1].getAttribute("selected")).toBe("selected");
399
- expect(options[1].getAttribute("selected")).toBe("selected");
400
- expect(options[1].selected).toBe(true);
401
- expect(options[1].selected).toBe(true);
402
- });
403
-
404
- fit("should render zero as a valid display value", async () => {
405
- compile(
406
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
407
- );
408
-
409
- scope.values = [{ name: 0 }, { name: 1 }, { name: 2 }];
410
- await wait();
411
-
412
- scope.selected = scope.values[0];
413
- await wait();
414
-
415
- const options = element.querySelectorAll("option");
416
- expect(options.length).toEqual(3);
417
- expect(options[0]).toEqualOption(scope.values[0], "0");
418
- expect(options[1]).toEqualOption(scope.values[1], "1");
419
- expect(options[2]).toEqualOption(scope.values[2], "2");
420
- });
421
-
422
- fit("should not be set when an option is selected and options are set asynchronously", async () => {
423
- compile(
424
- '<select ng-model="model" ng-options="opt.id as opt.label for opt in options"></select>',
425
- );
426
- await wait();
427
- scope.model = 0;
428
- scope.options = [
429
- { id: 0, label: "x" },
430
- { id: 1, label: "y" },
431
- ];
432
- await wait();
433
- const options = element.querySelectorAll("option");
434
- expect(options.length).toEqual(2);
435
- expect(options[0]).toEqualOption(0, "x");
436
- expect(options[1]).toEqualOption(1, "y");
437
- });
438
-
439
- fit("should grow list", async () => {
440
- compile(
441
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
442
- );
443
- await wait();
444
- scope.values = [];
445
- await wait();
446
- expect(element.querySelectorAll("option").length).toEqual(1); // because we add special unknown option
447
- expect(element.querySelectorAll("option")[0]).toEqualUnknownOption();
448
-
449
- scope.values.push({ name: "A" });
450
- scope.selected = scope.values[0];
451
- await wait();
452
- expect(element.querySelectorAll("option").length).toEqual(1);
453
- expect(element.querySelectorAll("option")[0]).toEqualOption(
454
- scope.values[0],
455
- "A",
456
- );
457
-
458
- scope.values.push({ name: "B" });
459
- await wait();
460
- expect(element.querySelectorAll("option").length).toEqual(2);
461
- expect(element.querySelectorAll("option")[0]).toEqualOption(
462
- scope.values[0],
463
- "A",
464
- );
465
- expect(element.querySelectorAll("option")[1]).toEqualOption(
466
- scope.values[1],
467
- "B",
468
- );
469
- });
470
-
471
- fit("should shrink list", async () => {
472
- compile(
473
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
474
- );
475
- await wait();
476
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
477
- scope.selected = scope.values[0];
478
- await wait();
479
- expect(element.querySelectorAll("option").length).toEqual(3);
480
-
481
- scope.values.pop();
482
- await wait();
483
- expect(element.querySelectorAll("option").length).toEqual(2);
484
- expect(element.querySelectorAll("option")[0]).toEqualOption(
485
- scope.values[0],
486
- "A",
487
- );
488
- expect(element.querySelectorAll("option")[1]).toEqualOption(
489
- scope.values[1],
490
- "B",
491
- );
492
- scope.values.pop();
493
- await wait();
494
-
495
- expect(element.querySelectorAll("option").length).toEqual(1);
496
- expect(element.querySelectorAll("option")[0]).toEqualOption(
497
- scope.values[0],
498
- "A",
499
- );
500
-
501
- scope.values.pop();
502
- scope.selected = null;
503
- await wait();
504
-
505
- expect(element.querySelectorAll("option").length).toEqual(1); // we add back the special empty option
506
- });
507
-
508
- it("should shrink and then grow list", async () => {
509
- element.innerHTML =
510
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
511
- injector = window.angular.bootstrap(element, ["myModule"]);
512
- scope = injector.get("$rootScope");
513
- await wait();
514
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
515
- await wait();
516
- scope.selected = scope.values[0];
517
- await wait();
518
- expect(element.querySelectorAll("option").length).toEqual(3);
519
-
520
- scope.values = [{ name: "1" }, { name: "2" }];
521
- await wait();
522
- scope.selected = scope.values[0];
523
- await wait();
524
- expect(element.querySelectorAll("option").length).toEqual(2);
525
-
526
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
527
- await wait();
528
- scope.selected = scope.values[0];
529
- await wait();
530
- expect(element.querySelectorAll("option").length).toEqual(3);
531
- });
532
-
533
- it("should update list", async () => {
534
- element.innerHTML =
535
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
536
- injector = window.angular.bootstrap(element, ["myModule"]);
537
- scope = injector.get("$rootScope");
538
-
539
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
540
- await wait();
541
- scope.selected = scope.values[0];
542
- await wait();
543
- scope.values = [{ name: "B" }, { name: "C" }, { name: "D" }];
544
- await wait();
545
- scope.selected = scope.values[0];
546
- await wait();
547
- const options = element.querySelectorAll("option");
548
- expect(options.length).toEqual(3);
549
- expect(options[0]).toEqualOption(scope.values[0], "B");
550
- expect(options[1]).toEqualOption(scope.values[1], "C");
551
- expect(options[2]).toEqualOption(scope.values[2], "D");
552
- });
553
-
554
- it("should preserve pre-existing empty option", async () => {
555
- element.innerHTML =
556
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
557
- injector = window.angular.bootstrap(element, ["myModule"]);
558
- scope = injector.get("$rootScope");
559
- await wait();
560
- scope.values = [];
561
- await wait();
562
- expect(element.querySelectorAll("option").length).toEqual(1);
563
- scope.values = [{ name: "A" }];
564
- await wait();
565
- scope.selected = scope.values[0];
566
- await wait();
567
- expect(element.querySelectorAll("option").length).toEqual(2);
568
- expect(element.querySelectorAll("option")[0].textContent).toEqual("blank");
569
- expect(element.querySelectorAll("option")[1].textContent).toEqual("A");
570
-
571
- scope.values = [];
572
- await wait();
573
- scope.selected = null;
574
- await wait();
575
- expect(element.querySelectorAll("option").length).toEqual(1);
576
- expect(element.querySelectorAll("option")[0].textContent).toEqual("blank");
577
- });
578
-
579
- it("should ignore $ and $$ properties", async () => {
580
- element.innerHTML =
581
- '<select ng-model="selected" ng-options="key as value for (key, value) in object"></select>';
582
- injector = window.angular.bootstrap(element, ["myModule"]);
583
- scope = injector.get("$rootScope");
584
-
585
- scope.object = {
586
- regularProperty: "visible",
587
- $$private: "invisible",
588
- $property: "invisible",
589
- };
590
- scope.selected = "regularProperty";
591
- await wait();
592
- const options = element.querySelectorAll("option");
593
- expect(options.length).toEqual(1);
594
- expect(options[0]).toEqualOption("regularProperty", "visible");
595
- });
596
-
597
- it("should not watch non-numeric array properties", async () => {
598
- element.innerHTML = $compile(
599
- '<select ng-model="selected" ng-options="value as createLabel(value) for value in array"></select>',
600
- )(scope);
601
- scope.createLabel = jasmine
602
- .createSpy("createLabel")
603
- .and.callFake((value) => value);
604
- scope.array = ["a", "b", "c"];
605
- scope.array.$$private = "do not watch";
606
- scope.array.$property = "do not watch";
607
- scope.array.other = "do not watch";
608
- scope.array.fn = function () {};
609
- scope.selected = "b";
610
- await wait();
611
- expect(scope.createLabel).toHaveBeenCalledWith("a");
612
- expect(scope.createLabel).toHaveBeenCalledWith("b");
613
- expect(scope.createLabel).toHaveBeenCalledWith("c");
614
- expect(scope.createLabel).not.toHaveBeenCalledWith("do not watch");
615
- expect(scope.createLabel).not.toHaveBeenCalledWith(jasmine.any(Function));
616
- });
617
-
618
- it("should not watch object properties that start with $ or $$", async () => {
619
- element.innerHTML = $compile(
620
- '<select ng-model="selected" ng-options="key as createLabel(key) for (key, value) in object"></select>',
621
- )(scope);
622
- scope.createLabel = jasmine
623
- .createSpy("createLabel")
624
- .and.callFake((value) => value);
625
- scope.object = {
626
- regularProperty: "visible",
627
- $$private: "invisible",
628
- $property: "invisible",
629
- };
630
- scope.selected = "regularProperty";
631
- await wait();
632
- expect(scope.createLabel).toHaveBeenCalledWith("regularProperty");
633
- expect(scope.createLabel).not.toHaveBeenCalledWith("$$private");
634
- expect(scope.createLabel).not.toHaveBeenCalledWith("$property");
635
- });
636
-
637
- xit("should allow expressions over multiple lines", async () => {
638
- scope.isNotFoo = function (item) {
639
- return item.name !== "Foo";
640
- };
641
- scope.values = [
642
- { id: 1, name: "Foo" },
643
- { id: 2, name: "Bar" },
644
- { id: 3, name: "Baz" },
645
- ];
646
- element.innerHTML = $compile(
647
- '<select ng-model="selected" ng-options="key.id for key in values | filter:isNotFoo"></select>',
648
- )(scope);
649
-
650
- await wait();
651
-
652
- scope.selected = scope.values[0];
653
- await wait();
654
- const options = element.querySelectorAll("option");
655
- expect(options.length).toEqual(3);
656
- expect(options[1]).toEqualOption(scope.values[1], "2");
657
- expect(options[2]).toEqualOption(scope.values[2], "3");
658
- });
659
-
660
- xit("should not update selected property of an option element on digest with no change event", async () => {
661
- // ng-options="value.name for value in values"
662
- // ng-model="selected"
663
- element.innerHTML = $compile(
664
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
665
- )(scope);
666
- await wait();
667
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
668
- scope.selected = scope.values[0];
669
- await wait();
670
- const options = element.querySelectorAll("option");
671
-
672
- expect(scope.selected).toEqual(jasmine.objectContaining({ name: "A" }));
673
- expect(options[0][0].selected).toBe(true);
674
- expect(options[1][0].selected).toBe(false);
675
-
676
- const optionToSelect = options[1];
677
- await wait();
678
- expect(optionToSelect.textContent).toBe("B");
679
-
680
- optionToSelect[0].selected = true;
681
- await wait();
682
- expect(optionToSelect[0].selected).toBe(true);
683
- expect(scope.selected).toBe(scope.values[0]);
684
- });
685
-
686
- // bug fix #9621
687
- xit("should update the label property", async () => {
688
- // ng-options="value.name for value in values"
689
- // ng-model="selected"
690
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
691
- scope.selected = scope.values[0];
692
- await wait();
693
- element.innerHTML = $compile(
694
- '<select ng-model="selected" ng-options="value.name for value in values"></select>',
695
- )(scope);
696
- await wait();
697
- const options = element.querySelectorAll("option");
698
- expect(options[0][0].label).toEqual("A");
699
- expect(options[1][0].label).toEqual("B");
700
- expect(options[2][0].label).toEqual("C");
701
- });
702
-
703
- it("should update the label if only the property has changed", async () => {
704
- // ng-options="value.name for value in values"
705
- // ng-model="selected"
706
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
707
- // scope.selected = scope.values[0];
708
- element.innerHTML = $compile(
709
- '<div><select ng-model="selected" ng-options="value.name for value in values"></select>',
710
- )(scope);
711
- await wait();
712
- // let options = element.querySelectorAll("option");
713
- // expect(options[0][0].label).toEqual("A");
714
- // expect(options[1][0].label).toEqual("B");
715
- // expect(options[2][0].label).toEqual("C");
716
-
717
- // scope.$apply('values[0].name = "X"');
718
-
719
- // options = element.querySelectorAll("option");
720
- // expect(options[0][0].label).toEqual("X");
721
- });
722
-
723
- // bug fix #9714
724
- it("should select the matching option when the options are updated", () => {
725
- // first set up a select with no options
726
- scope.selected = "";
727
- createSelect({
728
- "ng-options": "val.id as val.label for val in values",
729
- "ng-model": "selected",
730
- });
731
- let options = element.querySelectorAll("option");
732
- // we expect the selected option to be the "unknown" option
733
- expect(options[0]).toEqualUnknownOption("");
734
- expect(options[0][0].selected).toEqual(true);
735
-
736
- // now add some real options - one of which matches the selected value
737
- scope.$apply(
738
- 'values = [{id:"",label:"A"},{id:"1",label:"B"},{id:"2",label:"C"}]',
739
- );
740
-
741
- // we expect the selected option to be the one that matches the correct item
742
- // and for the unknown option to have been removed
743
- options = element.querySelectorAll("option");
744
- expect(element).toEqualSelectValue("");
745
- expect(options[0]).toEqualOption("", "A");
746
- });
747
-
748
- it('should remove the "selected" attribute from the previous option when the model changes', () => {
749
- scope.values = [
750
- { id: 10, label: "ten" },
751
- { id: 20, label: "twenty" },
752
- ];
753
-
754
- createSelect(
755
- {
756
- "ng-model": "selected",
757
- "ng-options": "item.label for item in values",
758
- },
759
- true,
760
- );
761
-
762
- let options = element.querySelectorAll("option");
763
- expect(options[0].selected).toBe(true);
764
- expect(options[1].selected).not.toBe(true);
765
- expect(options[2].selected).not.toBe(true);
766
-
767
- scope.selected = scope.values[0];
768
- expect(options[0].selected).not.toBe(true);
769
- expect(options[1].selected).toBe(true);
770
- expect(options[2].selected).not.toBe(true);
771
-
772
- scope.selected = scope.values[1];
773
- expect(options[0].selected).not.toBe(true);
774
- expect(options[1].selected).not.toBe(true);
775
- expect(options[2].selected).toBe(true);
776
-
777
- // This will select the empty option
778
- scope.selected = null;
779
- expect(options[0].selected).toBe(true);
780
- expect(options[1].selected).not.toBe(true);
781
- expect(options[2].selected).not.toBe(true);
782
-
783
- // This will add and select the unknown option
784
- scope.selected = "unmatched value";
785
- options = element.querySelectorAll("option");
786
-
787
- expect(options[0].selected).toBe(true);
788
- expect(options[1].selected).not.toBe(true);
789
- expect(options[2].selected).not.toBe(true);
790
- expect(options[3].selected).not.toBe(true);
791
-
792
- // Back to matched value
793
- scope.selected = scope.values[1];
794
- options = element.querySelectorAll("option");
795
-
796
- expect(options[0].selected).not.toBe(true);
797
- expect(options[1].selected).not.toBe(true);
798
- expect(options[2].selected).toBe(true);
799
- });
800
-
801
- if (window.MutationObserver) {
802
- // IE9 and IE10 do not support MutationObserver
803
- // Since the feature is only needed for a test, it's okay to skip these browsers
804
- it("should render the initial options only one time", () => {
805
- scope.value = "black";
806
- scope.values = ["black", "white", "red"];
807
- // observe-child-list adds a MutationObserver that we will read out after ngOptions
808
- // has been compiled
809
- createSelect({
810
- "ng-model": "value",
811
- "ng-options": "value.name for value in values",
812
- "observe-child-list": "",
813
- });
814
-
815
- const optionEls = element.querySelectorAll("option");
816
- const records = childListMutationObserver.takeRecords();
817
-
818
- expect(records.length).toBe(1);
819
- expect(records[0].addedNodes).toEqual(optionEls);
820
- });
821
- }
822
-
823
- describe("disableWhen expression", () => {
824
- describe("on single select", () => {
825
- it("should disable options", () => {
826
- scope.selected = "";
827
- scope.options = [
828
- { name: "white", value: "#FFFFFF" },
829
- { name: "one", value: 1, unavailable: true },
830
- { name: "notTrue", value: false },
831
- { name: "thirty", value: 30, unavailable: false },
832
- ];
833
- createSelect({
834
- "ng-options":
835
- "o.value as o.name disable when o.unavailable for o in options",
836
- "ng-model": "selected",
837
- });
838
- const options = element.querySelectorAll("option");
839
-
840
- expect(options.length).toEqual(5);
841
- expect(options[1][0].disabled).toEqual(false);
842
- expect(options[2][0].disabled).toEqual(true);
843
- expect(options.eq(3)[0].disabled).toEqual(false);
844
- expect(options.eq(4)[0].disabled).toEqual(false);
845
- });
846
-
847
- it("should select disabled options when model changes", () => {
848
- scope.options = [
849
- { name: "white", value: "#FFFFFF" },
850
- { name: "one", value: 1, unavailable: true },
851
- { name: "notTrue", value: false },
852
- { name: "thirty", value: 30, unavailable: false },
853
- ];
854
- createSelect({
855
- "ng-options":
856
- "o.value as o.name disable when o.unavailable for o in options",
857
- "ng-model": "selected",
858
- });
859
-
860
- // Initially the model is set to an enabled option
861
- scope.$apply("selected = 30");
862
- let options = element.querySelectorAll("option");
863
- expect(options.eq(3)[0].selected).toEqual(true);
864
-
865
- // Now set the model to a disabled option
866
- scope.$apply("selected = 1");
867
- options = element.querySelectorAll("option");
868
-
869
- // jQuery returns null for val() when the option is disabled, see
870
- // https://bugs.jquery.com/ticket/13097
871
- expect(element.value).toBe("number:1");
872
- expect(options.length).toEqual(4);
873
- expect(options[0][0].selected).toEqual(false);
874
- expect(options[1][0].selected).toEqual(true);
875
- expect(options[2][0].selected).toEqual(false);
876
- expect(options.eq(3)[0].selected).toEqual(false);
877
- });
878
-
879
- it("should select options in model when they become enabled", () => {
880
- scope.options = [
881
- { name: "white", value: "#FFFFFF" },
882
- { name: "one", value: 1, unavailable: true },
883
- { name: "notTrue", value: false },
884
- { name: "thirty", value: 30, unavailable: false },
885
- ];
886
- createSelect({
887
- "ng-options":
888
- "o.value as o.name disable when o.unavailable for o in options",
889
- "ng-model": "selected",
890
- });
891
-
892
- // Set the model to a disabled option
893
- scope.$apply("selected = 1");
894
- let options = element.querySelectorAll("option");
895
-
896
- // jQuery returns null for val() when the option is disabled, see
897
- // https://bugs.jquery.com/ticket/13097
898
- expect(element.value).toBe("number:1");
899
- expect(options.length).toEqual(4);
900
- expect(options[0][0].selected).toEqual(false);
901
- expect(options[1][0].selected).toEqual(true);
902
- expect(options[2][0].selected).toEqual(false);
903
- expect(options.eq(3)[0].selected).toEqual(false);
904
-
905
- // Now enable that option
906
- scope.$apply(() => {
907
- scope.options[1].unavailable = false;
908
- });
909
-
910
- expect(element).toEqualSelectValue(1);
911
- options = element.querySelectorAll("option");
912
- expect(options.length).toEqual(4);
913
- expect(options[1][0].selected).toEqual(true);
914
- expect(options.eq(3)[0].selected).toEqual(false);
915
- });
916
- });
917
-
918
- describe("on multi select", () => {
919
- it("should disable options", () => {
920
- scope.selected = [];
921
- scope.options = [
922
- { name: "a", value: 0 },
923
- { name: "b", value: 1, unavailable: true },
924
- { name: "c", value: 2 },
925
- { name: "d", value: 3, unavailable: false },
926
- ];
927
- createSelect({
928
- "ng-options":
929
- "o.value as o.name disable when o.unavailable for o in options",
930
- multiple: true,
931
- "ng-model": "selected",
932
- });
933
- const options = element.querySelectorAll("option");
934
-
935
- expect(options[0][0].disabled).toEqual(false);
936
- expect(options[1][0].disabled).toEqual(true);
937
- expect(options[2][0].disabled).toEqual(false);
938
- expect(options.eq(3)[0].disabled).toEqual(false);
939
- });
940
-
941
- it("should select disabled options when model changes", () => {
942
- scope.options = [
943
- { name: "a", value: 0 },
944
- { name: "b", value: 1, unavailable: true },
945
- { name: "c", value: 2 },
946
- { name: "d", value: 3, unavailable: false },
947
- ];
948
- createSelect({
949
- "ng-options":
950
- "o.value as o.name disable when o.unavailable for o in options",
951
- multiple: true,
952
- "ng-model": "selected",
953
- });
954
-
955
- // Initially the model is set to an enabled option
956
- scope.$apply("selected = [3]");
957
- let options = element.querySelectorAll("option");
958
- expect(options[0][0].selected).toEqual(false);
959
- expect(options[1][0].selected).toEqual(false);
960
- expect(options[2][0].selected).toEqual(false);
961
- expect(options.eq(3)[0].selected).toEqual(true);
962
-
963
- // Now add a disabled option
964
- scope.$apply("selected = [1,3]");
965
- options = element.querySelectorAll("option");
966
- expect(options[0][0].selected).toEqual(false);
967
- expect(options[1][0].selected).toEqual(true);
968
- expect(options[2][0].selected).toEqual(false);
969
- expect(options.eq(3)[0].selected).toEqual(true);
970
-
971
- // Now only select the disabled option
972
- scope.$apply("selected = [1]");
973
- expect(options[0][0].selected).toEqual(false);
974
- expect(options[1][0].selected).toEqual(true);
975
- expect(options[2][0].selected).toEqual(false);
976
- expect(options.eq(3)[0].selected).toEqual(false);
977
- });
978
-
979
- it("should select options in model when they become enabled", () => {
980
- scope.options = [
981
- { name: "a", value: 0 },
982
- { name: "b", value: 1, unavailable: true },
983
- { name: "c", value: 2 },
984
- { name: "d", value: 3, unavailable: false },
985
- ];
986
- createSelect({
987
- "ng-options":
988
- "o.value as o.name disable when o.unavailable for o in options",
989
- multiple: true,
990
- "ng-model": "selected",
991
- });
992
-
993
- // Set the model to a disabled option
994
- scope.$apply("selected = [1]");
995
- let options = element.querySelectorAll("option");
996
-
997
- expect(options[0][0].selected).toEqual(false);
998
- expect(options[1][0].selected).toEqual(true);
999
- expect(options[2][0].selected).toEqual(false);
1000
- expect(options.eq(3)[0].selected).toEqual(false);
1001
-
1002
- // Now enable that option
1003
- scope.$apply(() => {
1004
- scope.options[1].unavailable = false;
1005
- });
1006
-
1007
- expect(element).toEqualSelectValue([1], true);
1008
- options = element.querySelectorAll("option");
1009
- expect(options[0][0].selected).toEqual(false);
1010
- expect(options[1][0].selected).toEqual(true);
1011
- expect(options[2][0].selected).toEqual(false);
1012
- expect(options.eq(3)[0].selected).toEqual(false);
1013
- });
1014
- });
1015
- });
1016
-
1017
- describe("selectAs expression", () => {
1018
- beforeEach(() => {
1019
- scope.arr = [
1020
- { id: 10, label: "ten" },
1021
- { id: 20, label: "twenty" },
1022
- ];
1023
- scope.obj = {
1024
- 10: { score: 10, label: "ten" },
1025
- 20: { score: 20, label: "twenty" },
1026
- };
1027
- });
1028
-
1029
- it("should support single select with array source", () => {
1030
- createSelect({
1031
- "ng-model": "selected",
1032
- "ng-options": "item.id as item.label for item in arr",
1033
- });
1034
-
1035
- scope.$apply(() => {
1036
- scope.selected = 10;
1037
- });
1038
- expect(element).toEqualSelectValue(10);
1039
-
1040
- setSelectValue(element, 1);
1041
- expect(scope.selected).toBe(20);
1042
- });
1043
-
1044
- it("should support multi select with array source", () => {
1045
- createSelect({
1046
- "ng-model": "selected",
1047
- multiple: true,
1048
- "ng-options": "item.id as item.label for item in arr",
1049
- });
1050
-
1051
- scope.$apply(() => {
1052
- scope.selected = [10, 20];
1053
- });
1054
- expect(element).toEqualSelectValue([10, 20], true);
1055
- expect(scope.selected).toEqual([10, 20]);
1056
-
1057
- element.children()[0].selected = false;
1058
- browserTrigger(element, "change");
1059
- expect(scope.selected).toEqual([20]);
1060
- expect(element).toEqualSelectValue([20], true);
1061
- });
1062
-
1063
- it("should re-render if an item in an array source is added/removed", () => {
1064
- createSelect({
1065
- "ng-model": "selected",
1066
- multiple: true,
1067
- "ng-options": "item.id as item.label for item in arr",
1068
- });
1069
-
1070
- scope.$apply(() => {
1071
- scope.selected = [10];
1072
- });
1073
- expect(element).toEqualSelectValue([10], true);
1074
-
1075
- scope.$apply(() => {
1076
- scope.selected.push(20);
1077
- });
1078
- expect(element).toEqualSelectValue([10, 20], true);
1079
-
1080
- scope.$apply(() => {
1081
- scope.selected.shift();
1082
- });
1083
- expect(element).toEqualSelectValue([20], true);
1084
- });
1085
-
1086
- it("should handle a options containing circular references", () => {
1087
- scope.arr[0].ref = scope.arr[0];
1088
- scope.selected = [scope.arr[0]];
1089
- createSelect({
1090
- "ng-model": "selected",
1091
- multiple: true,
1092
- "ng-options": "item as item.label for item in arr",
1093
- });
1094
- expect(element).toEqualSelectValue([scope.arr[0]], true);
1095
-
1096
- scope.$apply(() => {
1097
- scope.selected.push(scope.arr[1]);
1098
- });
1099
- expect(element).toEqualSelectValue([scope.arr[0], scope.arr[1]], true);
1100
-
1101
- scope.$apply(() => {
1102
- scope.selected.pop();
1103
- });
1104
- expect(element).toEqualSelectValue([scope.arr[0]], true);
1105
- });
1106
-
1107
- it("should support single select with object source", () => {
1108
- createSelect({
1109
- "ng-model": "selected",
1110
- "ng-options": "val.score as val.label for (key, val) in obj",
1111
- });
1112
-
1113
- scope.$apply(() => {
1114
- scope.selected = 10;
1115
- });
1116
- expect(element).toEqualSelectValue(10);
1117
-
1118
- setSelectValue(element, 1);
1119
- expect(scope.selected).toBe(20);
1120
- });
1121
-
1122
- it("should support multi select with object source", () => {
1123
- createSelect({
1124
- "ng-model": "selected",
1125
- multiple: true,
1126
- "ng-options": "val.score as val.label for (key, val) in obj",
1127
- });
1128
-
1129
- scope.$apply(() => {
1130
- scope.selected = [10, 20];
1131
- });
1132
- expect(element).toEqualSelectValue([10, 20], true);
1133
-
1134
- element.children()[0].selected = false;
1135
- browserTrigger(element, "change");
1136
- expect(scope.selected).toEqual([20]);
1137
- expect(element).toEqualSelectValue([20], true);
1138
- });
1139
- });
1140
-
1141
- describe("trackBy expression", () => {
1142
- beforeEach(() => {
1143
- scope.arr = [
1144
- { id: 10, label: "ten" },
1145
- { id: 20, label: "twenty" },
1146
- ];
1147
- scope.obj = {
1148
- 1: { score: 10, label: "ten" },
1149
- 2: { score: 20, label: "twenty" },
1150
- };
1151
- });
1152
-
1153
- it("should set the result of track by expression to element value", () => {
1154
- createSelect({
1155
- "ng-model": "selected",
1156
- "ng-options": "item.label for item in arr track by item.id",
1157
- });
1158
-
1159
- expect(element.value).toEqualUnknownValue();
1160
-
1161
- scope.$apply(() => {
1162
- scope.selected = scope.arr[0];
1163
- });
1164
- expect(element.value).toBe("10");
1165
-
1166
- scope.$apply(() => {
1167
- scope.arr[0] = { id: 10, label: "new ten" };
1168
- });
1169
- expect(element.value).toBe("10");
1170
-
1171
- element.children()[1].selected = "selected";
1172
- browserTrigger(element, "change");
1173
- expect(scope.selected).toEqual(scope.arr[1]);
1174
- });
1175
-
1176
- it("should use the tracked expression as option value", () => {
1177
- createSelect({
1178
- "ng-model": "selected",
1179
- "ng-options": "item.label for item in arr track by item.id",
1180
- });
1181
-
1182
- const options = element.querySelectorAll("option");
1183
- expect(options.length).toEqual(3);
1184
- expect(options[0]).toEqualUnknownOption();
1185
- expect(options[1]).toEqualTrackedOption(10, "ten");
1186
- expect(options[2]).toEqualTrackedOption(20, "twenty");
1187
- });
1188
-
1189
- it("should update the selected option even if only the tracked property on the selected object changes (single)", () => {
1190
- createSelect({
1191
- "ng-model": "selected",
1192
- "ng-options": "item.label for item in arr track by item.id",
1193
- });
1194
-
1195
- scope.$apply(() => {
1196
- scope.selected = { id: 10, label: "ten" };
1197
- });
1198
-
1199
- expect(element.value).toEqual("10");
1200
-
1201
- // Update the properties on the selected object, rather than replacing the whole object
1202
- scope.$apply(() => {
1203
- scope.selected.id = 20;
1204
- scope.selected.label = "new twenty";
1205
- });
1206
-
1207
- // The value of the select should change since the id property changed
1208
- expect(element.value).toEqual("20");
1209
-
1210
- // But the label of the selected option does not change
1211
- const option = element.querySelectorAll("option")[1];
1212
- expect(option[0].selected).toEqual(true);
1213
- expect(option.textContent).toEqual("twenty"); // not 'new twenty'
1214
- });
1215
-
1216
- it(
1217
- "should update the selected options even if only the tracked properties on the objects in the " +
1218
- "selected collection change (multi)",
1219
- () => {
1220
- createSelect({
1221
- "ng-model": "selected",
1222
- multiple: true,
1223
- "ng-options": "item.label for item in arr track by item.id",
1224
- });
1225
-
1226
- scope.$apply(() => {
1227
- scope.selected = [{ id: 10, label: "ten" }];
1228
- });
1229
-
1230
- expect(element.value).toEqual(["10"]);
1231
-
1232
- // Update the tracked property on the object in the selected array, rather than replacing the whole object
1233
- scope.$apply(() => {
1234
- scope.selected[0].id = 20;
1235
- });
1236
-
1237
- // The value of the select should change since the id property changed
1238
- expect(element.value).toEqual(["20"]);
1239
-
1240
- // But the label of the selected option does not change
1241
- const option = element.querySelectorAll("option")[1];
1242
- expect(option[0].selected).toEqual(true);
1243
- expect(option.textContent).toEqual("twenty"); // not 'new twenty'
1244
- },
1245
- );
1246
-
1247
- it("should prevent changes to the selected object from modifying the options objects (single)", () => {
1248
- createSelect({
1249
- "ng-model": "selected",
1250
- "ng-options": "item.label for item in arr track by item.id",
1251
- });
1252
-
1253
- element.value = "10";
1254
- browserTrigger(element, "change");
1255
-
1256
- expect(scope.selected).toEqual(scope.arr[0]);
1257
-
1258
- scope.$apply(() => {
1259
- scope.selected.id = 20;
1260
- });
1261
-
1262
- expect(scope.selected).not.toEqual(scope.arr[0]);
1263
- expect(element.value).toEqual("20");
1264
- expect(scope.arr).toEqual([
1265
- { id: 10, label: "ten" },
1266
- { id: 20, label: "twenty" },
1267
- ]);
1268
- });
1269
-
1270
- it("should preserve value even when reference has changed (single&array)", () => {
1271
- createSelect({
1272
- "ng-model": "selected",
1273
- "ng-options": "item.label for item in arr track by item.id",
1274
- });
1275
-
1276
- scope.$apply(() => {
1277
- scope.selected = scope.arr[0];
1278
- });
1279
- expect(element.value).toBe("10");
1280
-
1281
- scope.$apply(() => {
1282
- scope.arr[0] = { id: 10, label: "new ten" };
1283
- });
1284
- expect(element.value).toBe("10");
1285
-
1286
- element.children()[1].selected = 1;
1287
- browserTrigger(element, "change");
1288
- expect(scope.selected).toEqual(scope.arr[1]);
1289
- });
1290
-
1291
- it("should preserve value even when reference has changed (multi&array)", () => {
1292
- createSelect({
1293
- "ng-model": "selected",
1294
- multiple: true,
1295
- "ng-options": "item.label for item in arr track by item.id",
1296
- });
1297
-
1298
- scope.$apply(() => {
1299
- scope.selected = scope.arr;
1300
- });
1301
- expect(element.value).toEqual(["10", "20"]);
1302
-
1303
- scope.$apply(() => {
1304
- scope.arr[0] = { id: 10, label: "new ten" };
1305
- });
1306
- expect(element.value).toEqual(["10", "20"]);
1307
-
1308
- element.children()[0].selected = false;
1309
- browserTrigger(element, "change");
1310
- expect(scope.selected).toEqual([scope.arr[1]]);
1311
- });
1312
-
1313
- it("should preserve value even when reference has changed (single&object)", () => {
1314
- createSelect({
1315
- "ng-model": "selected",
1316
- "ng-options": "val.label for (key, val) in obj track by val.score",
1317
- });
1318
-
1319
- scope.$apply(() => {
1320
- scope.selected = scope.obj["1"];
1321
- });
1322
- expect(element.value).toBe("10");
1323
-
1324
- scope.$apply(() => {
1325
- scope.obj["1"] = { score: 10, label: "ten" };
1326
- });
1327
- expect(element.value).toBe("10");
1328
-
1329
- setSelectValue(element, 1);
1330
- expect(scope.selected).toEqual(scope.obj["2"]);
1331
- });
1332
-
1333
- it("should preserve value even when reference has changed (multi&object)", () => {
1334
- createSelect({
1335
- "ng-model": "selected",
1336
- multiple: true,
1337
- "ng-options": "val.label for (key, val) in obj track by val.score",
1338
- });
1339
-
1340
- scope.$apply(() => {
1341
- scope.selected = [scope.obj["1"]];
1342
- });
1343
- expect(element.value).toEqual(["10"]);
1344
-
1345
- scope.$apply(() => {
1346
- scope.obj["1"] = { score: 10, label: "ten" };
1347
- });
1348
- expect(element.value).toEqual(["10"]);
1349
-
1350
- element.children()[1].selected = "selected";
1351
- browserTrigger(element, "change");
1352
- expect(scope.selected).toEqual([scope.obj["1"], scope.obj["2"]]);
1353
- });
1354
-
1355
- it("should prevent infinite digest if track by expression is stable", () => {
1356
- scope.makeOptions = function () {
1357
- const options = [];
1358
- for (let i = 0; i < 5; i++) {
1359
- options.push({ label: `Value = ${i}`, value: i });
1360
- }
1361
- return options;
1362
- };
1363
- scope.selected = { label: "Value = 1", value: 1 };
1364
- expect(() => {
1365
- createSelect({
1366
- "ng-model": "selected",
1367
- "ng-options":
1368
- "item.label for item in makeOptions() track by item.value",
1369
- });
1370
- }).not.toThrow();
1371
- });
1372
-
1373
- it("should re-render if the tracked property of the model is changed when using trackBy", () => {
1374
- createSelect({
1375
- "ng-model": "selected",
1376
- "ng-options": "item for item in arr track by item.id",
1377
- });
1378
-
1379
- scope.$apply(() => {
1380
- scope.selected = { id: 10, label: "ten" };
1381
- });
1382
-
1383
- spyOn(element.controller("ngModel"), "$render");
1384
-
1385
- scope.$apply(() => {
1386
- scope.arr[0].id = 20;
1387
- });
1388
-
1389
- // update render due to equality watch
1390
- expect(element.controller("ngModel").$render).toHaveBeenCalled();
1391
- });
1392
-
1393
- it("should not set view value again if the tracked property of the model has not changed when using trackBy", () => {
1394
- createSelect({
1395
- "ng-model": "selected",
1396
- "ng-options": "item for item in arr track by item.id",
1397
- });
1398
-
1399
- scope.$apply(() => {
1400
- scope.selected = { id: 10, label: "ten" };
1401
- });
1402
-
1403
- spyOn(element.controller("ngModel"), "$setViewValue");
1404
-
1405
- scope.$apply(() => {
1406
- scope.arr[0] = { id: 10, label: "ten" };
1407
- });
1408
-
1409
- expect(
1410
- element.controller("ngModel").$setViewValue,
1411
- ).not.toHaveBeenCalled();
1412
- });
1413
-
1414
- it("should not re-render if a property of the model is changed when not using trackBy", () => {
1415
- createSelect({
1416
- "ng-model": "selected",
1417
- "ng-options": "item for item in arr",
1418
- });
1419
-
1420
- scope.$apply(() => {
1421
- scope.selected = scope.arr[0];
1422
- });
1423
-
1424
- spyOn(element.controller("ngModel"), "$render");
1425
-
1426
- scope.$apply(() => {
1427
- scope.selected.label = "changed";
1428
- });
1429
-
1430
- // no render update as no equality watch
1431
- expect(element.controller("ngModel").$render).not.toHaveBeenCalled();
1432
- });
1433
-
1434
- it("should handle options containing circular references (single)", () => {
1435
- scope.arr[0].ref = scope.arr[0];
1436
- createSelect({
1437
- "ng-model": "selected",
1438
- "ng-options": "item for item in arr track by item.id",
1439
- });
1440
-
1441
- expect(() => {
1442
- scope.$apply(() => {
1443
- scope.selected = scope.arr[0];
1444
- });
1445
- }).not.toThrow();
1446
- });
1447
-
1448
- it("should handle options containing circular references (multiple)", () => {
1449
- scope.arr[0].ref = scope.arr[0];
1450
- createSelect({
1451
- "ng-model": "selected",
1452
- multiple: true,
1453
- "ng-options": "item for item in arr track by item.id",
1454
- });
1455
-
1456
- expect(() => {
1457
- scope.$apply(() => {
1458
- scope.selected = [scope.arr[0]];
1459
- });
1460
-
1461
- scope.$apply(() => {
1462
- scope.selected.push(scope.arr[1]);
1463
- });
1464
- }).not.toThrow();
1465
- });
1466
-
1467
- it('should remove the "selected" attribute when the model changes', () => {
1468
- createSelect({
1469
- "ng-model": "selected",
1470
- "ng-options": "item.label for item in arr track by item.id",
1471
- });
1472
-
1473
- const options = element.querySelectorAll("option");
1474
- element.selectedIndex = 2;
1475
- element.dispatchEvent(new Event("change"));
1476
- expect(scope.selected).toEqual(scope.arr[1]);
1477
-
1478
- scope.selected = {};
1479
- expect(options[0].selected).toBeTrue();
1480
- expect(options[1].selected).not.toBeTrue();
1481
- expect(options[2].selected).not.toBeTrue();
1482
- });
1483
- });
1484
-
1485
- /**
1486
- * This behavior is broken and should probably be cleaned up later as track by and select as
1487
- * aren't compatible.
1488
- */
1489
- describe("selectAs+trackBy expression", () => {
1490
- beforeEach(() => {
1491
- scope.arr = [
1492
- { subItem: { label: "ten", id: 10 } },
1493
- { subItem: { label: "twenty", id: 20 } },
1494
- ];
1495
- scope.obj = {
1496
- 10: { subItem: { id: 10, label: "ten" } },
1497
- 20: { subItem: { id: 20, label: "twenty" } },
1498
- };
1499
- });
1500
-
1501
- it(
1502
- 'It should use the "value" variable to represent items in the array as well as for the ' +
1503
- "selected values in track by expression (single&array)",
1504
- () => {
1505
- createSelect({
1506
- "ng-model": "selected",
1507
- "ng-options":
1508
- "item.subItem as item.subItem.label for item in arr track by (item.id || item.subItem.id)",
1509
- });
1510
-
1511
- // First test model -> view
1512
-
1513
- scope.$apply(() => {
1514
- scope.selected = scope.arr[0].subItem;
1515
- });
1516
- expect(element.value).toEqual("10");
1517
-
1518
- scope.$apply(() => {
1519
- scope.selected = scope.arr[1].subItem;
1520
- });
1521
- expect(element.value).toEqual("20");
1522
-
1523
- // Now test view -> model
1524
-
1525
- element.value = "10";
1526
- browserTrigger(element, "change");
1527
- expect(scope.selected).toEqual(scope.arr[0].subItem);
1528
-
1529
- // Now reload the array
1530
- scope.$apply(() => {
1531
- scope.arr = [
1532
- {
1533
- subItem: { label: "new ten", id: 10 },
1534
- },
1535
- {
1536
- subItem: { label: "new twenty", id: 20 },
1537
- },
1538
- ];
1539
- });
1540
- expect(element.value).toBe("10");
1541
- expect(scope.selected.id).toBe(10);
1542
- },
1543
- );
1544
-
1545
- it(
1546
- 'It should use the "value" variable to represent items in the array as well as for the ' +
1547
- "selected values in track by expression (multiple&array)",
1548
- () => {
1549
- createSelect({
1550
- "ng-model": "selected",
1551
- multiple: true,
1552
- "ng-options":
1553
- "item.subItem as item.subItem.label for item in arr track by (item.id || item.subItem.id)",
1554
- });
1555
-
1556
- // First test model -> view
1557
-
1558
- scope.$apply(() => {
1559
- scope.selected = [scope.arr[0].subItem];
1560
- });
1561
- expect(element.value).toEqual(["10"]);
1562
-
1563
- scope.$apply(() => {
1564
- scope.selected = [scope.arr[1].subItem];
1565
- });
1566
- expect(element.value).toEqual(["20"]);
1567
-
1568
- // Now test view -> model
1569
-
1570
- element.querySelectorAll("option")[0].selected = true;
1571
- element.querySelectorAll("option")[1].selected = false;
1572
- browserTrigger(element, "change");
1573
- expect(scope.selected).toEqual([scope.arr[0].subItem]);
1574
-
1575
- // Now reload the array
1576
- scope.$apply(() => {
1577
- scope.arr = [
1578
- {
1579
- subItem: { label: "new ten", id: 10 },
1580
- },
1581
- {
1582
- subItem: { label: "new twenty", id: 20 },
1583
- },
1584
- ];
1585
- });
1586
- expect(element.value).toEqual(["10"]);
1587
- expect(scope.selected[0].id).toEqual(10);
1588
- expect(scope.selected.length).toBe(1);
1589
- },
1590
- );
1591
-
1592
- it(
1593
- 'It should use the "value" variable to represent items in the array as well as for the ' +
1594
- "selected values in track by expression (multiple&object)",
1595
- () => {
1596
- createSelect({
1597
- "ng-model": "selected",
1598
- multiple: true,
1599
- "ng-options":
1600
- "val.subItem as val.subItem.label for (key, val) in obj track by (val.id || val.subItem.id)",
1601
- });
1602
-
1603
- // First test model -> view
1604
-
1605
- scope.$apply(() => {
1606
- scope.selected = [scope.obj["10"].subItem];
1607
- });
1608
- expect(element.value).toEqual(["10"]);
1609
-
1610
- scope.$apply(() => {
1611
- scope.selected = [scope.obj["10"].subItem];
1612
- });
1613
- expect(element.value).toEqual(["10"]);
1614
-
1615
- // Now test view -> model
1616
-
1617
- element.querySelectorAll("option")[0].selected = true;
1618
- element.querySelectorAll("option")[1].selected = false;
1619
- browserTrigger(element, "change");
1620
- expect(scope.selected).toEqual([scope.obj["10"].subItem]);
1621
-
1622
- // Now reload the object
1623
- scope.$apply(() => {
1624
- scope.obj = {
1625
- 10: {
1626
- subItem: { label: "new ten", id: 10 },
1627
- },
1628
- 20: {
1629
- subItem: { label: "new twenty", id: 20 },
1630
- },
1631
- };
1632
- });
1633
- expect(element.value).toEqual(["10"]);
1634
- expect(scope.selected[0].id).toBe(10);
1635
- expect(scope.selected.length).toBe(1);
1636
- },
1637
- );
1638
-
1639
- it(
1640
- 'It should use the "value" variable to represent items in the array as well as for the ' +
1641
- "selected values in track by expression (single&object)",
1642
- () => {
1643
- createSelect({
1644
- "ng-model": "selected",
1645
- "ng-options":
1646
- "val.subItem as val.subItem.label for (key, val) in obj track by (val.id || val.subItem.id)",
1647
- });
1648
-
1649
- // First test model -> view
1650
-
1651
- scope.$apply(() => {
1652
- scope.selected = scope.obj["10"].subItem;
1653
- });
1654
- expect(element.value).toEqual("10");
1655
-
1656
- scope.$apply(() => {
1657
- scope.selected = scope.obj["10"].subItem;
1658
- });
1659
- expect(element.value).toEqual("10");
1660
-
1661
- // Now test view -> model
1662
-
1663
- element.querySelectorAll("option")[0].selected = true;
1664
- browserTrigger(element, "change");
1665
- expect(scope.selected).toEqual(scope.obj["10"].subItem);
1666
-
1667
- // Now reload the object
1668
- scope.$apply(() => {
1669
- scope.obj = {
1670
- 10: {
1671
- subItem: { label: "new ten", id: 10 },
1672
- },
1673
- 20: {
1674
- subItem: { label: "new twenty", id: 20 },
1675
- },
1676
- };
1677
- });
1678
- expect(element.value).toEqual("10");
1679
- expect(scope.selected.id).toBe(10);
1680
- },
1681
- );
1682
- });
1683
-
1684
- describe("binding", () => {
1685
- it("should bind to scope value", () => {
1686
- element.innerHTML =
1687
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
1688
- injector = window.angular.bootstrap(element, ["myModule"]);
1689
- scope = injector.get("$rootScope");
1690
-
1691
- scope.$apply(() => {
1692
- scope.values = [{ name: "A" }, { name: "B" }];
1693
- scope.selected = scope.values[0];
1694
- });
1695
-
1696
- expect(element).toEqualSelectValue(scope.selected);
1697
-
1698
- scope.$apply(() => {
1699
- scope.selected = scope.values[1];
1700
- });
1701
-
1702
- expect(element).toEqualSelectValue(scope.selected);
1703
- });
1704
-
1705
- it("should bind to scope value and group", () => {
1706
- createSelect({
1707
- "ng-model": "selected",
1708
- "ng-options": "item.name group by item.group for item in values",
1709
- });
1710
-
1711
- scope.$apply(() => {
1712
- scope.values = [
1713
- { name: "A" },
1714
- { name: "B", group: 0 },
1715
- { name: "C", group: "first" },
1716
- { name: "D", group: "second" },
1717
- { name: "E", group: 0 },
1718
- { name: "F", group: "first" },
1719
- { name: "G", group: "second" },
1720
- ];
1721
- scope.selected = scope.values[3];
1722
- });
1723
-
1724
- expect(element).toEqualSelectValue(scope.selected);
1725
-
1726
- const optgroups = element.querySelectorAll("optgroup");
1727
- expect(optgroups.length).toBe(3);
1728
-
1729
- const zero = optgroups[0];
1730
- const b = zero.querySelector("option")[0];
1731
- const e = zero.querySelector("option")[1];
1732
- expect(zero.getAttribute("label")).toEqual("0");
1733
- expect(b.textContent).toEqual("B");
1734
- expect(e.textContent).toEqual("E");
1735
-
1736
- const first = optgroups[1];
1737
- const c = first.querySelector("option")[0];
1738
- const f = first.querySelector("option")[1];
1739
- expect(first.getAttribute("label")).toEqual("first");
1740
- expect(c.textContent).toEqual("C");
1741
- expect(f.textContent).toEqual("F");
1742
-
1743
- const second = optgroups[2];
1744
- const d = second.querySelector("option")[0];
1745
- const g = second.querySelector("option")[1];
1746
- expect(second.getAttribute("label")).toEqual("second");
1747
- expect(d.textContent).toEqual("D");
1748
- expect(g.textContent).toEqual("G");
1749
-
1750
- scope.$apply(() => {
1751
- scope.selected = scope.values[0];
1752
- });
1753
-
1754
- expect(element).toEqualSelectValue(scope.selected);
1755
- });
1756
-
1757
- it("should group when the options are available on compile time", () => {
1758
- scope.values = [
1759
- { name: "C", group: "first" },
1760
- { name: "D", group: "second" },
1761
- { name: "F", group: "first" },
1762
- { name: "G", group: "second" },
1763
- ];
1764
- scope.selected = scope.values[3];
1765
-
1766
- createSelect({
1767
- "ng-model": "selected",
1768
- "ng-options":
1769
- "item as item.name group by item.group for item in values",
1770
- });
1771
-
1772
- expect(element).toEqualSelectValue(scope.selected);
1773
-
1774
- const optgroups = element.querySelectorAll("optgroup");
1775
- expect(optgroups.length).toBe(2);
1776
-
1777
- const first = optgroups[0];
1778
- const c = first.querySelector("option")[0];
1779
- const f = first.querySelector("option")[1];
1780
- expect(first.getAttribute("label")).toEqual("first");
1781
- expect(c.textContent).toEqual("C");
1782
- expect(f.textContent).toEqual("F");
1783
-
1784
- const second = optgroups[1];
1785
- const d = second.querySelector("option")[0];
1786
- const g = second.querySelector("option")[1];
1787
- expect(second.getAttribute("label")).toEqual("second");
1788
- expect(d.textContent).toEqual("D");
1789
- expect(g.textContent).toEqual("G");
1790
-
1791
- scope.$apply(() => {
1792
- scope.selected = scope.values[0];
1793
- });
1794
-
1795
- expect(element).toEqualSelectValue(scope.selected);
1796
- });
1797
-
1798
- it("should group when the options are updated", () => {
1799
- let optgroups;
1800
- let one;
1801
- let two;
1802
- let three;
1803
- let alpha;
1804
- let beta;
1805
- let gamma;
1806
- let delta;
1807
- let epsilon;
1808
-
1809
- createSelect({
1810
- "ng-model": "selected",
1811
- "ng-options": "i.name group by i.cls for i in list",
1812
- });
1813
-
1814
- scope.list = [
1815
- { cls: "one", name: "Alpha" },
1816
- { cls: "one", name: "Beta" },
1817
- { cls: "two", name: "Gamma" },
1818
- ];
1819
- optgroups = element.querySelectorAll("optgroup");
1820
- expect(optgroups.length).toBe(2);
1821
-
1822
- one = optgroups[0];
1823
- expect(one.children("option").length).toBe(2);
1824
-
1825
- alpha = one.querySelector("option")[0];
1826
- beta = one.querySelector("option")[1];
1827
- expect(one.getAttribute("label")).toEqual("one");
1828
- expect(alpha.textContent).toEqual("Alpha");
1829
- expect(beta.textContent).toEqual("Beta");
1830
-
1831
- two = optgroups[1];
1832
- expect(two.children("option").length).toBe(1);
1833
-
1834
- gamma = two.querySelector("option")[0];
1835
- expect(two.getAttribute("label")).toEqual("two");
1836
- expect(gamma.textContent).toEqual("Gamma");
1837
-
1838
- // Remove item from first group, add item to second group, add new group
1839
- scope.list.shift();
1840
- scope.list.push(
1841
- { cls: "two", name: "Delta" },
1842
- { cls: "three", name: "Epsilon" },
1843
- );
1844
- optgroups = element.querySelectorAll("optgroup");
1845
- expect(optgroups.length).toBe(3);
1846
-
1847
- // Group with removed item
1848
- one = optgroups[0];
1849
- expect(one.children("option").length).toBe(1);
1850
-
1851
- beta = one.querySelector("option")[0];
1852
- expect(one.getAttribute("label")).toEqual("one");
1853
- expect(beta.textContent).toEqual("Beta");
1854
-
1855
- // Group with new item
1856
- two = optgroups[1];
1857
- expect(two.children("option").length).toBe(2);
1858
-
1859
- gamma = two.querySelector("option")[0];
1860
- expect(two.getAttribute("label")).toEqual("two");
1861
- expect(gamma.textContent).toEqual("Gamma");
1862
- delta = two.querySelector("option")[1];
1863
- expect(two.getAttribute("label")).toEqual("two");
1864
- expect(delta.textContent).toEqual("Delta");
1865
-
1866
- // New group
1867
- three = optgroups[2];
1868
- expect(three.children("option").length).toBe(1);
1869
-
1870
- epsilon = three.querySelector("option")[0];
1871
- expect(three.getAttribute("label")).toEqual("three");
1872
- expect(epsilon.textContent).toEqual("Epsilon");
1873
- });
1874
-
1875
- it("should place non-grouped items in the list where they appear", () => {
1876
- createSelect({
1877
- "ng-model": "selected",
1878
- "ng-options": "item.name group by item.group for item in values",
1879
- });
1880
-
1881
- scope.$apply(() => {
1882
- scope.values = [
1883
- { name: "A" },
1884
- { name: "B", group: "first" },
1885
- { name: "C", group: "second" },
1886
- { name: "D" },
1887
- { name: "E", group: "first" },
1888
- { name: "F" },
1889
- { name: "G" },
1890
- { name: "H", group: "second" },
1891
- ];
1892
- scope.selected = scope.values[0];
1893
- });
1894
-
1895
- const children = element.children();
1896
- expect(children.length).toEqual(6);
1897
-
1898
- expect(children[0].nodeName.toLowerCase()).toEqual("option");
1899
- expect(children[1].nodeName.toLowerCase()).toEqual("optgroup");
1900
- expect(children[2].nodeName.toLowerCase()).toEqual("optgroup");
1901
- expect(children[3].nodeName.toLowerCase()).toEqual("option");
1902
- expect(children[4].nodeName.toLowerCase()).toEqual("option");
1903
- expect(children[5].nodeName.toLowerCase()).toEqual("option");
1904
- });
1905
-
1906
- it("should group if the group has a falsy value (except undefined)", () => {
1907
- createSelect({
1908
- "ng-model": "selected",
1909
- "ng-options": "item.name group by item.group for item in values",
1910
- });
1911
-
1912
- scope.$apply(() => {
1913
- scope.values = [
1914
- { name: "A" },
1915
- { name: "B", group: "" },
1916
- { name: "C", group: null },
1917
- { name: "D", group: false },
1918
- { name: "E", group: 0 },
1919
- ];
1920
- scope.selected = scope.values[0];
1921
- });
1922
-
1923
- const optgroups = element.querySelectorAll("optgroup");
1924
- const options = element.querySelectorAll("option");
1925
-
1926
- expect(optgroups.length).toEqual(4);
1927
- expect(options.length).toEqual(5);
1928
-
1929
- expect(optgroups[0].label).toBe("");
1930
- expect(optgroups[1].label).toBe("null");
1931
- expect(optgroups[2].label).toBe("false");
1932
- expect(optgroups[3].label).toBe("0");
1933
-
1934
- expect(options[0].textContent).toBe("A");
1935
- expect(options[0].parentNode).toBe(element);
1936
-
1937
- expect(options[1].textContent).toBe("B");
1938
- expect(options[1].parentNode).toBe(optgroups[0]);
1939
-
1940
- expect(options[2].textContent).toBe("C");
1941
- expect(options[2].parentNode).toBe(optgroups[1]);
1942
-
1943
- expect(options[3].textContent).toBe("D");
1944
- expect(options[3].parentNode).toBe(optgroups[2]);
1945
-
1946
- expect(options[4].textContent).toBe("E");
1947
- expect(options[4].parentNode).toBe(optgroups[3]);
1948
- });
1949
-
1950
- it("should not duplicate a group with a falsy value when the options are updated", () => {
1951
- scope.$apply(() => {
1952
- scope.values = [
1953
- { value: "A", group: "" },
1954
- { value: "B", group: "First" },
1955
- ];
1956
- scope.selected = scope.values[0];
1957
- });
1958
-
1959
- createSelect({
1960
- "ng-model": "selected",
1961
- "ng-options": "item.value group by item.group for item in values",
1962
- });
1963
-
1964
- scope.$apply(() => {
1965
- scope.values.push({ value: "C", group: false });
1966
- });
1967
-
1968
- const optgroups = element.querySelectorAll("optgroup");
1969
- const options = element.querySelectorAll("option");
1970
-
1971
- expect(optgroups.length).toEqual(3);
1972
- expect(options.length).toEqual(3);
1973
-
1974
- expect(optgroups[0].label).toBe("");
1975
- expect(optgroups[1].label).toBe("First");
1976
- expect(optgroups[2].label).toBe("false");
1977
-
1978
- expect(options[0].textContent).toBe("A");
1979
- expect(options[0].parentNode).toBe(optgroups[0]);
1980
-
1981
- expect(options[1].textContent).toBe("B");
1982
- expect(options[1].parentNode).toBe(optgroups[1]);
1983
-
1984
- expect(options[2].textContent).toBe("C");
1985
- expect(options[2].parentNode).toBe(optgroups[2]);
1986
- });
1987
-
1988
- it("should bind to scope value and track/identify objects", () => {
1989
- createSelect({
1990
- "ng-model": "selected",
1991
- "ng-options": "item.name for item in values track by item.id",
1992
- });
1993
-
1994
- scope.$apply(() => {
1995
- scope.values = [
1996
- { id: 1, name: "first" },
1997
- { id: 2, name: "second" },
1998
- { id: 3, name: "third" },
1999
- { id: 4, name: "forth" },
2000
- ];
2001
- scope.selected = scope.values[1];
2002
- });
2003
-
2004
- expect(element.value).toEqual("2");
2005
-
2006
- const first = element.querySelectorAll("option")[0];
2007
- expect(first.textContent).toEqual("first");
2008
- expect(first.getAttribute("value")).toEqual("1");
2009
- const forth = element.querySelectorAll("option")[3];
2010
- expect(forth.textContent).toEqual("forth");
2011
- expect(forth.getAttribute("value")).toEqual("4");
2012
-
2013
- scope.$apply(() => {
2014
- scope.selected = scope.values[3];
2015
- });
2016
-
2017
- expect(element.value).toEqual("4");
2018
- });
2019
-
2020
- it("should bind to scope value through expression", () => {
2021
- createSelect({
2022
- "ng-model": "selected",
2023
- "ng-options": "item.id as item.name for item in values",
2024
- });
2025
-
2026
- scope.$apply(() => {
2027
- scope.values = [
2028
- { id: 10, name: "A" },
2029
- { id: 20, name: "B" },
2030
- ];
2031
- scope.selected = scope.values[0].id;
2032
- });
2033
-
2034
- expect(element).toEqualSelectValue(scope.selected);
2035
-
2036
- scope.$apply(() => {
2037
- scope.selected = scope.values[1].id;
2038
- });
2039
-
2040
- expect(element).toEqualSelectValue(scope.selected);
2041
- });
2042
-
2043
- it("should update options in the DOM", () => {
2044
- compile(
2045
- '<select ng-model="selected" ng-options="item.id as item.name for item in values"></select>',
2046
- );
2047
-
2048
- scope.$apply(() => {
2049
- scope.values = [
2050
- { id: 10, name: "A" },
2051
- { id: 20, name: "B" },
2052
- ];
2053
- scope.selected = scope.values[0].id;
2054
- });
2055
-
2056
- scope.$apply(() => {
2057
- scope.values[0].name = "C";
2058
- });
2059
-
2060
- const options = element.querySelectorAll("option");
2061
- expect(options.length).toEqual(2);
2062
- expect(options[0]).toEqualOption(10, "C");
2063
- expect(options[1]).toEqualOption(20, "B");
2064
- });
2065
-
2066
- it("should update options in the DOM from object source", () => {
2067
- compile(
2068
- '<select ng-model="selected" ng-options="val.id as val.name for (key, val) in values"></select>',
2069
- );
2070
-
2071
- scope.$apply(() => {
2072
- scope.values = { a: { id: 10, name: "A" }, b: { id: 20, name: "B" } };
2073
- scope.selected = scope.values.a.id;
2074
- });
2075
-
2076
- scope.$apply(() => {
2077
- scope.values.a.name = "C";
2078
- });
2079
-
2080
- const options = element.querySelectorAll("option");
2081
- expect(options.length).toEqual(2);
2082
- expect(options[0]).toEqualOption(10, "C");
2083
- expect(options[1]).toEqualOption(20, "B");
2084
- });
2085
-
2086
- it("should bind to object key", () => {
2087
- createSelect({
2088
- "ng-model": "selected",
2089
- "ng-options": "key as value for (key, value) in object",
2090
- });
2091
-
2092
- scope.$apply(() => {
2093
- scope.object = { red: "FF0000", green: "00FF00", blue: "0000FF" };
2094
- scope.selected = "green";
2095
- });
2096
-
2097
- expect(element).toEqualSelectValue(scope.selected);
2098
-
2099
- scope.$apply(() => {
2100
- scope.selected = "blue";
2101
- });
2102
-
2103
- expect(element).toEqualSelectValue(scope.selected);
2104
- });
2105
-
2106
- it("should bind to object value", () => {
2107
- createSelect({
2108
- "ng-model": "selected",
2109
- "ng-options": "value as key for (key, value) in object",
2110
- });
2111
-
2112
- scope.$apply(() => {
2113
- scope.object = { red: "FF0000", green: "00FF00", blue: "0000FF" };
2114
- scope.selected = "00FF00";
2115
- });
2116
-
2117
- expect(element).toEqualSelectValue(scope.selected);
2118
-
2119
- scope.$apply(() => {
2120
- scope.selected = "0000FF";
2121
- });
2122
-
2123
- expect(element).toEqualSelectValue(scope.selected);
2124
- });
2125
-
2126
- it("should bind to object disabled", () => {
2127
- scope.selected = 30;
2128
- scope.options = [
2129
- { name: "white", value: "#FFFFFF" },
2130
- { name: "one", value: 1, unavailable: true },
2131
- { name: "notTrue", value: false },
2132
- { name: "thirty", value: 30, unavailable: false },
2133
- ];
2134
- createSelect({
2135
- "ng-options":
2136
- "o.value as o.name disable when o.unavailable for o in options",
2137
- "ng-model": "selected",
2138
- });
2139
-
2140
- let options = element.querySelectorAll("option");
2141
-
2142
- expect(scope.options[1].unavailable).toEqual(true);
2143
- expect(options[1][0].disabled).toEqual(true);
2144
-
2145
- scope.$apply(() => {
2146
- scope.options[1].unavailable = false;
2147
- });
2148
-
2149
- options = element.querySelectorAll("option");
2150
-
2151
- expect(scope.options[1].unavailable).toEqual(false);
2152
- expect(options[1][0].disabled).toEqual(false);
2153
- });
2154
-
2155
- it("should insert the unknown option if bound to null", () => {
2156
- element.innerHTML =
2157
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
2158
- injector = window.angular.bootstrap(element, ["myModule"]);
2159
- scope = injector.get("$rootScope");
2160
-
2161
- scope.$apply(() => {
2162
- scope.values = [{ name: "A" }];
2163
- scope.selected = null;
2164
- });
2165
-
2166
- expect(element.querySelectorAll("option").length).toEqual(2);
2167
- expect(element.value).toEqual("?");
2168
- expect(element.querySelectorAll("option")[0].value).toEqual("?");
2169
-
2170
- scope.$apply(() => {
2171
- scope.selected = scope.values[0];
2172
- });
2173
-
2174
- expect(element).toEqualSelectValue(scope.selected);
2175
- expect(element.querySelectorAll("option").length).toEqual(1);
2176
- });
2177
-
2178
- it("should select the provided empty option if bound to null", () => {
2179
- element.innerHTML =
2180
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2181
- injector = window.angular.bootstrap(element, ["myModule"]);
2182
- scope = injector.get("$rootScope");
2183
-
2184
- scope.$apply(() => {
2185
- scope.values = [{ name: "A" }];
2186
- scope.selected = null;
2187
- });
2188
-
2189
- expect(element.querySelectorAll("option").length).toEqual(2);
2190
- expect(element.value).toEqual("");
2191
- expect(element.querySelectorAll("option")[0].value).toEqual("");
2192
-
2193
- scope.$apply(() => {
2194
- scope.selected = scope.values[0];
2195
- });
2196
-
2197
- expect(element).toEqualSelectValue(scope.selected);
2198
- expect(element.querySelectorAll("option")[0].value).toEqual("");
2199
- expect(element.querySelectorAll("option").length).toEqual(2);
2200
- });
2201
-
2202
- it("should reuse blank option if bound to null", () => {
2203
- element.innerHTML =
2204
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2205
- injector = window.angular.bootstrap(element, ["myModule"]);
2206
- scope = injector.get("$rootScope");
2207
-
2208
- scope.$apply(() => {
2209
- scope.values = [{ name: "A" }];
2210
- scope.selected = null;
2211
- });
2212
-
2213
- expect(element.querySelectorAll("option").length).toEqual(2);
2214
- expect(element.value).toEqual("");
2215
- expect(element.querySelectorAll("option")[0].value).toEqual("");
2216
-
2217
- scope.$apply(() => {
2218
- scope.selected = scope.values[0];
2219
- });
2220
-
2221
- expect(element).toEqualSelectValue(scope.selected);
2222
- expect(element.querySelectorAll("option").length).toEqual(2);
2223
- });
2224
-
2225
- it("should not insert a blank option if one of the options maps to null", () => {
2226
- createSelect({
2227
- "ng-model": "myColor",
2228
- "ng-options": "color.shade as color.name for color in colors",
2229
- });
2230
-
2231
- scope.$apply(() => {
2232
- scope.colors = [
2233
- { name: "nothing", shade: null },
2234
- { name: "red", shade: "dark" },
2235
- ];
2236
- scope.myColor = null;
2237
- });
2238
-
2239
- expect(element.querySelectorAll("option").length).toEqual(2);
2240
- expect(element.querySelectorAll("option")[0]).toEqualOption(null);
2241
- expect(element.value).not.toEqualUnknownValue(null);
2242
- expect(element.querySelectorAll("option")[0]).not.toEqualUnknownOption(
2243
- null,
2244
- );
2245
- });
2246
-
2247
- it("should insert a unknown option if bound to something not in the list", () => {
2248
- element.innerHTML =
2249
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
2250
- injector = window.angular.bootstrap(element, ["myModule"]);
2251
- scope = injector.get("$rootScope");
2252
-
2253
- scope.$apply(() => {
2254
- scope.values = [{ name: "A" }];
2255
- scope.selected = {};
2256
- });
2257
-
2258
- expect(element.querySelectorAll("option").length).toEqual(2);
2259
- expect(element.value).toEqualUnknownValue(scope.selected);
2260
- expect(element.querySelectorAll("option")[0]).toEqualUnknownOption(
2261
- scope.selected,
2262
- );
2263
-
2264
- scope.$apply(() => {
2265
- scope.selected = scope.values[0];
2266
- });
2267
-
2268
- expect(element).toEqualSelectValue(scope.selected);
2269
- expect(element.querySelectorAll("option").length).toEqual(1);
2270
- });
2271
-
2272
- it(
2273
- "should insert and select temporary unknown option when no options-model match, empty " +
2274
- "option is present and model is defined",
2275
- () => {
2276
- scope.selected = "C";
2277
- scope.values = [{ name: "A" }, { name: "B" }];
2278
- element.innerHTML =
2279
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2280
- injector = window.angular.bootstrap(element, ["myModule"]);
2281
- scope = injector.get("$rootScope");
2282
-
2283
- expect(element.value).toBe("?");
2284
- expect(element.length).toBe(4);
2285
-
2286
- scope.$apply("selected = values[1]");
2287
-
2288
- expect(element.value).not.toBe("");
2289
- expect(element.length).toBe(3);
2290
- },
2291
- );
2292
-
2293
- it('should select correct input if previously selected option was "?"', () => {
2294
- element.innerHTML =
2295
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
2296
- injector = window.angular.bootstrap(element, ["myModule"]);
2297
- scope = injector.get("$rootScope");
2298
-
2299
- scope.$apply(() => {
2300
- scope.values = [{ name: "A" }, { name: "B" }];
2301
- scope.selected = {};
2302
- });
2303
-
2304
- expect(element.querySelectorAll("option").length).toEqual(3);
2305
- expect(element.value).toEqualUnknownValue();
2306
- expect(element.querySelectorAll("option")[0]).toEqualUnknownOption();
2307
-
2308
- setSelectValue(element, 1);
2309
-
2310
- expect(element.querySelectorAll("option").length).toEqual(2);
2311
- expect(element).toEqualSelectValue(scope.selected);
2312
- expect(element.querySelectorAll("option")[0][0].selected).toBeTruthy();
2313
- });
2314
-
2315
- it("should remove unknown option when empty option exists and model is undefined", () => {
2316
- scope.selected = "C";
2317
- scope.values = [{ name: "A" }, { name: "B" }];
2318
- element.innerHTML =
2319
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2320
- injector = window.angular.bootstrap(element, ["myModule"]);
2321
- scope = injector.get("$rootScope");
2322
-
2323
- expect(element.value).toBe("?");
2324
-
2325
- scope.selected = undefined;
2326
- expect(element.value).toBe("");
2327
- });
2328
-
2329
- it('should ensure that at least one option element has the "selected" attribute', () => {
2330
- createSelect({
2331
- "ng-model": "selected",
2332
- "ng-options": "item.id as item.name for item in values",
2333
- });
2334
-
2335
- scope.$apply(() => {
2336
- scope.values = [
2337
- { id: 10, name: "A" },
2338
- { id: 20, name: "B" },
2339
- ];
2340
- });
2341
- expect(element.value).toEqualUnknownValue();
2342
- expect(
2343
- element.querySelectorAll("option")[0].getAttribute("selected"),
2344
- ).toEqual("selected");
2345
-
2346
- scope.$apply(() => {
2347
- scope.selected = 10;
2348
- });
2349
- // Here the ? option should disappear and the first real option should have selected attribute
2350
- expect(element).toEqualSelectValue(scope.selected);
2351
- expect(
2352
- element.querySelectorAll("option")[0].getAttribute("selected"),
2353
- ).toEqual("selected");
2354
-
2355
- // Here the selected value is changed and we change the selected attribute
2356
- scope.$apply(() => {
2357
- scope.selected = 20;
2358
- });
2359
- expect(element).toEqualSelectValue(scope.selected);
2360
- expect(
2361
- element.querySelectorAll("option")[1].getAttribute("selected"),
2362
- ).toEqual("selected");
2363
-
2364
- scope.$apply(() => {
2365
- scope.values.push({ id: 30, name: "C" });
2366
- });
2367
- expect(element).toEqualSelectValue(scope.selected);
2368
- expect(
2369
- element.querySelectorAll("option")[1].getAttribute("selected"),
2370
- ).toEqual("selected");
2371
-
2372
- // Here the ? option should reappear and have selected attribute
2373
- scope.$apply(() => {
2374
- scope.selected = undefined;
2375
- });
2376
- expect(element.value).toEqualUnknownValue();
2377
- expect(
2378
- element.querySelectorAll("option")[0].getAttribute("selected"),
2379
- ).toEqual("selected");
2380
- });
2381
-
2382
- it("should select the correct option for selectAs and falsy values", () => {
2383
- scope.values = [
2384
- { value: 0, label: "zero" },
2385
- { value: 1, label: "one" },
2386
- ];
2387
- scope.selected = "";
2388
- createSelect({
2389
- "ng-model": "selected",
2390
- "ng-options": "option.value as option.label for option in values",
2391
- });
2392
-
2393
- const option = element.querySelectorAll("option")[0];
2394
- expect(option).toEqualUnknownOption();
2395
- });
2396
-
2397
- it("should update the model if the selected option is removed", () => {
2398
- scope.values = [
2399
- { value: 0, label: "zero" },
2400
- { value: 1, label: "one" },
2401
- ];
2402
- scope.selected = 1;
2403
- createSelect({
2404
- "ng-model": "selected",
2405
- "ng-options": "option.value as option.label for option in values",
2406
- });
2407
- expect(element).toEqualSelectValue(1);
2408
-
2409
- // Check after initial option update
2410
- scope.$apply(() => {
2411
- scope.values.pop();
2412
- });
2413
-
2414
- expect(element.value).toEqual("?");
2415
- expect(scope.selected).toEqual(null);
2416
-
2417
- // Check after model change
2418
- scope.$apply(() => {
2419
- scope.selected = 0;
2420
- });
2421
-
2422
- expect(element).toEqualSelectValue(0);
2423
-
2424
- scope.$apply(() => {
2425
- scope.values.pop();
2426
- });
2427
-
2428
- expect(element.value).toEqual("?");
2429
- expect(scope.selected).toEqual(null);
2430
- });
2431
-
2432
- it("should update the model if all the selected (multiple) options are removed", () => {
2433
- scope.values = [
2434
- { value: 0, label: "zero" },
2435
- { value: 1, label: "one" },
2436
- { value: 2, label: "two" },
2437
- ];
2438
- scope.selected = [1, 2];
2439
- createSelect({
2440
- "ng-model": "selected",
2441
- multiple: true,
2442
- "ng-options": "option.value as option.label for option in values",
2443
- });
2444
-
2445
- expect(element).toEqualSelectValue([1, 2], true);
2446
-
2447
- // Check after initial option update
2448
- scope.$apply(() => {
2449
- scope.values.pop();
2450
- });
2451
-
2452
- expect(element).toEqualSelectValue([1], true);
2453
- expect(scope.selected).toEqual([1]);
2454
-
2455
- scope.$apply(() => {
2456
- scope.values.pop();
2457
- });
2458
-
2459
- expect(element).toEqualSelectValue([], true);
2460
- expect(scope.selected).toEqual([]);
2461
-
2462
- // Check after model change
2463
- scope.$apply(() => {
2464
- scope.selected = [0];
2465
- });
2466
-
2467
- expect(element).toEqualSelectValue([0], true);
2468
-
2469
- scope.$apply(() => {
2470
- scope.values.pop();
2471
- });
2472
-
2473
- expect(element).toEqualSelectValue([], true);
2474
- expect(scope.selected).toEqual([]);
2475
- });
2476
- });
2477
-
2478
- describe("empty option", () => {
2479
- it("should be compiled as template, be watched and updated", () => {
2480
- let option;
2481
- createSingleSelect('<option value="">blank is {{blankVal}}</option>');
2482
-
2483
- scope.$apply(() => {
2484
- scope.blankVal = "so blank";
2485
- scope.values = [{ name: "A" }];
2486
- });
2487
-
2488
- // check blank option is first and is compiled
2489
- expect(element.querySelectorAll("option").length).toBe(2);
2490
- option = element.querySelectorAll("option")[0];
2491
- expect(option.value).toBe("");
2492
- expect(option.textContent).toBe("blank is so blank");
2493
-
2494
- scope.$apply(() => {
2495
- scope.blankVal = "not so blank";
2496
- });
2497
-
2498
- // check blank option is first and is compiled
2499
- expect(element.querySelectorAll("option").length).toBe(2);
2500
- option = element.querySelectorAll("option")[0];
2501
- expect(option.value).toBe("");
2502
- expect(option.textContent).toBe("blank is not so blank");
2503
- });
2504
-
2505
- it("should support binding via ngBindTemplate directive", () => {
2506
- let option;
2507
- createSingleSelect(
2508
- '<option value="" ng-bind-template="blank is {{blankVal}}"></option>',
2509
- );
2510
-
2511
- scope.$apply(() => {
2512
- scope.blankVal = "so blank";
2513
- scope.values = [{ name: "A" }];
2514
- });
2515
-
2516
- // check blank option is first and is compiled
2517
- expect(element.querySelectorAll("option").length).toBe(2);
2518
- option = element.querySelectorAll("option")[0];
2519
- expect(option.value).toBe("");
2520
- expect(option.textContent).toBe("blank is so blank");
2521
- });
2522
-
2523
- it("should support binding via ngBind attribute", () => {
2524
- let option;
2525
- createSingleSelect('<option value="" ng-bind="blankVal"></option>');
2526
-
2527
- scope.$apply(() => {
2528
- scope.blankVal = "is blank";
2529
- scope.values = [{ name: "A" }];
2530
- });
2531
-
2532
- // check blank option is first and is compiled
2533
- expect(element.querySelectorAll("option").length).toBe(2);
2534
- option = element.querySelectorAll("option")[0];
2535
- expect(option.value).toBe("");
2536
- expect(option.textContent).toBe("is blank");
2537
- });
2538
-
2539
- it("should be ignored when it has no value attribute", () => {
2540
- // The option value is set to the textContent if there's no value attribute,
2541
- // so in that case it doesn't count as a blank option
2542
- createSingleSelect("<option>--select--</option>");
2543
- scope.$apply(() => {
2544
- scope.values = [{ name: "A" }, { name: "B" }, { name: "C" }];
2545
- });
2546
-
2547
- const options = element.querySelectorAll("option");
2548
-
2549
- expect(options[0]).toEqualUnknownOption();
2550
- expect(options[1]).toEqualOption(scope.values[0], "A");
2551
- expect(options[2]).toEqualOption(scope.values[1], "B");
2552
- expect(options.eq(3)).toEqualOption(scope.values[2], "C");
2553
- });
2554
-
2555
- it("should be rendered with the attributes preserved", () => {
2556
- let option;
2557
- createSingleSelect(
2558
- '<option value="" class="coyote" id="road-runner" ' +
2559
- 'custom-attr="custom-attr">{{blankVal}}</option>',
2560
- );
2561
-
2562
- scope.$apply(() => {
2563
- scope.blankVal = "is blank";
2564
- });
2565
-
2566
- // check blank option is first and is compiled
2567
- option = element.querySelectorAll("option")[0];
2568
- expect(option[0].classList.contains("coyote")).toBeTruthy();
2569
- expect(option.getAttribute("id")).toBe("road-runner");
2570
- expect(option.getAttribute("custom-attr")).toBe("custom-attr");
2571
- });
2572
-
2573
- it("should be selected, if it is available and no other option is selected", () => {
2574
- // selectedIndex is used here because JQLite incorrectly reports element.value
2575
- scope.$apply(() => {
2576
- scope.values = [{ name: "A" }];
2577
- });
2578
- element.innerHTML =
2579
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2580
- injector = window.angular.bootstrap(element, ["myModule"]);
2581
- scope = injector.get("$rootScope");
2582
- // ensure the first option (the blank option) is selected
2583
- expect(element.selectedIndex).toEqual(0);
2584
- // ensure the option has not changed following the digest
2585
- expect(element.selectedIndex).toEqual(0);
2586
- });
2587
-
2588
- it("should be selectable if select is multiple", () => {
2589
- createMultiSelect(true);
2590
-
2591
- // select the empty option
2592
- setSelectValue(element, 0);
2593
-
2594
- // ensure selection and correct binding
2595
- expect(element.selectedIndex).toEqual(0);
2596
- expect(scope.selected).toEqual([]);
2597
- });
2598
-
2599
- it("should be possible to use ngIf in the blank option", () => {
2600
- let option;
2601
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2602
-
2603
- scope.$apply(() => {
2604
- scope.values = [{ name: "A" }];
2605
- scope.isBlank = true;
2606
- });
2607
-
2608
- expect(element.value).toBe("");
2609
-
2610
- scope.$apply("isBlank = false");
2611
-
2612
- expect(element.value).toBe("?");
2613
-
2614
- scope.$apply("isBlank = true");
2615
-
2616
- expect(element.value).toBe("");
2617
- });
2618
-
2619
- it("should be possible to use ngIf in the blank option when values are available upon linking", () => {
2620
- let options;
2621
-
2622
- scope.values = [{ name: "A" }];
2623
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2624
-
2625
- scope.$apply("isBlank = true");
2626
-
2627
- options = element.querySelectorAll("option");
2628
- expect(options.length).toBe(2);
2629
- expect(options[0].value).toBe("");
2630
- expect(options[0].textContent).toBe("blank");
2631
-
2632
- scope.$apply("isBlank = false");
2633
-
2634
- expect(element.value).toBe("?");
2635
- });
2636
-
2637
- it("should select the correct option after linking when the ngIf expression is initially falsy", () => {
2638
- scope.values = [{ name: "black" }, { name: "white" }, { name: "red" }];
2639
- scope.selected = scope.values[2];
2640
-
2641
- expect(() => {
2642
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2643
- scope.$apply();
2644
- }).not.toThrow();
2645
-
2646
- expect(element.querySelectorAll("option")[2].selected).toBe(true);
2647
- expect(linkLog).toEqual(["linkNgOptions"]);
2648
- });
2649
-
2650
- it('should add / remove the "selected" attribute on empty option which has an initially falsy ngIf expression', () => {
2651
- scope.values = [{ name: "black" }, { name: "white" }, { name: "red" }];
2652
- scope.selected = scope.values[2];
2653
-
2654
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2655
- scope.$apply();
2656
-
2657
- expect(element.querySelectorAll("option")[2].selected).toBe(true);
2658
-
2659
- scope.$apply("isBlank = true");
2660
- expect(element.querySelectorAll("option")[0].value).toBe("");
2661
- expect(element.querySelectorAll("option")[0].selected).toBe(false);
2662
-
2663
- scope.$apply("selected = null");
2664
- expect(element.querySelectorAll("option")[0].value).toBe("");
2665
- expect(element.querySelectorAll("option")[0].selected).toBe(true);
2666
-
2667
- scope.selected = scope.values[1];
2668
- scope.$apply();
2669
- expect(element.querySelectorAll("option")[0].value).toBe("");
2670
- expect(element.querySelectorAll("option")[0].selected).toBe(false);
2671
- expect(element.querySelectorAll("option")[2].selected).toBe(true);
2672
- });
2673
-
2674
- it('should add / remove the "selected" attribute on empty option which has an initially truthy ngIf expression when no option is selected', () => {
2675
- scope.values = [{ name: "black" }, { name: "white" }, { name: "red" }];
2676
- scope.isBlank = true;
2677
-
2678
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2679
- scope.$apply();
2680
-
2681
- expect(element.querySelectorAll("option")[0].value).toBe("");
2682
- expect(element.querySelectorAll("option")[0].selected).toBe(true);
2683
- scope.selected = scope.values[2];
2684
- scope.$apply();
2685
- expect(element.querySelectorAll("option")[0].selected).toBe(false);
2686
- expect(element.querySelectorAll("option")[3].selected).toBe(true);
2687
- });
2688
-
2689
- it('should add the "selected" attribute on empty option which has an initially falsy ngIf expression when no option is selected', () => {
2690
- scope.values = [{ name: "black" }, { name: "white" }, { name: "red" }];
2691
-
2692
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
2693
- scope.$apply();
2694
-
2695
- expect(element.querySelectorAll("option")[0].selected).toBe(false);
2696
-
2697
- scope.isBlank = true;
2698
- scope.$apply();
2699
-
2700
- expect(element.querySelectorAll("option")[0].value).toBe("");
2701
- expect(element.querySelectorAll("option")[0].selected).toBe(true);
2702
- expect(element.querySelectorAll("option")[1].selected).toBe(false);
2703
- });
2704
-
2705
- it("should not throw when a directive compiles the blank option before ngOptions is linked", () => {
2706
- expect(() => {
2707
- createSelect(
2708
- {
2709
- "o-compile-contents": "",
2710
- name: "select",
2711
- "ng-model": "value",
2712
- "ng-options": "item for item in items",
2713
- },
2714
- true,
2715
- );
2716
- }).not.toThrow();
2717
-
2718
- expect(linkLog).toEqual(["linkCompileContents", "linkNgOptions"]);
2719
- });
2720
-
2721
- it("should not throw with a directive that replaces", () => {
2722
- let $templateCache = injector.get("$templateCache");
2723
- $templateCache.set(
2724
- "select_template.html",
2725
- '<select ng-options="option as option for option in selectable_options"> <option value="">This is a test</option> </select>',
2726
- );
2727
-
2728
- scope.options = ["a", "b", "c", "d"];
2729
-
2730
- expect(() => {
2731
- element = $compile(
2732
- '<custom-select ng-model="value" options="options"></custom-select>',
2733
- )(scope);
2734
- }).not.toThrow();
2735
-
2736
- dealoc(element);
2737
- });
2738
- });
2739
-
2740
- describe("on change", () => {
2741
- it("should update model on change", () => {
2742
- element.innerHTML =
2743
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
2744
- injector = window.angular.bootstrap(element, ["myModule"]);
2745
- scope = injector.get("$rootScope");
2746
-
2747
- scope.$apply(() => {
2748
- scope.values = [{ name: "A" }, { name: "B" }];
2749
- scope.selected = scope.values[0];
2750
- });
2751
-
2752
- expect(element).toEqualSelectValue(scope.selected);
2753
-
2754
- setSelectValue(element, 1);
2755
- expect(scope.selected).toEqual(scope.values[1]);
2756
- });
2757
-
2758
- it("should update model on change through expression", () => {
2759
- createSelect({
2760
- "ng-model": "selected",
2761
- "ng-options": "item.id as item.name for item in values",
2762
- });
2763
-
2764
- scope.$apply(() => {
2765
- scope.values = [
2766
- { id: 10, name: "A" },
2767
- { id: 20, name: "B" },
2768
- ];
2769
- scope.selected = scope.values[0].id;
2770
- });
2771
-
2772
- expect(element).toEqualSelectValue(scope.selected);
2773
-
2774
- setSelectValue(element, 1);
2775
- expect(scope.selected).toEqual(scope.values[1].id);
2776
- });
2777
-
2778
- it("should update model to null on change", () => {
2779
- element.innerHTML =
2780
- '<select ng-model="selected" ng-options="value.name for value in values"><option value="">blank</option></select>';
2781
- injector = window.angular.bootstrap(element, ["myModule"]);
2782
- scope = injector.get("$rootScope");
2783
-
2784
- scope.$apply(() => {
2785
- scope.values = [{ name: "A" }, { name: "B" }];
2786
- scope.selected = scope.values[0];
2787
- });
2788
-
2789
- element.value = "";
2790
- browserTrigger(element, "change");
2791
- expect(scope.selected).toEqual(null);
2792
- });
2793
-
2794
- // Regression https://github.com/angular/angular.js/issues/7855
2795
- it("should update the model with ng-change", () => {
2796
- createSelect({
2797
- "ng-change": "change()",
2798
- "ng-model": "selected",
2799
- "ng-options": "value for value in values",
2800
- });
2801
-
2802
- scope.$apply(() => {
2803
- scope.values = ["A", "B"];
2804
- scope.selected = "A";
2805
- });
2806
-
2807
- scope.change = function () {
2808
- scope.selected = "A";
2809
- };
2810
-
2811
- element.querySelectorAll("option")[1].selected = true;
2812
-
2813
- browserTrigger(element, "change");
2814
- expect(element.querySelectorAll("option")[0].selected).toBeTruthy();
2815
- expect(scope.selected).toEqual("A");
2816
- });
2817
- });
2818
-
2819
- describe("disabled blank", () => {
2820
- it("should select disabled blank by default", () => {
2821
- const html =
2822
- '<select ng-model="someModel" ng-options="c for c in choices">' +
2823
- '<option value="" disabled>Choose One</option>' +
2824
- "</select>";
2825
- scope.$apply(() => {
2826
- scope.choices = ["A", "B", "C"];
2827
- });
2828
-
2829
- compile(html);
2830
-
2831
- const options = element.querySelectorAll("option");
2832
- const optionToSelect = options[0];
2833
- expect(optionToSelect.textContent).toBe("Choose One");
2834
- expect(optionToSelect[0].selected).toBe(true);
2835
- expect(element.value).toBe("");
2836
-
2837
- dealoc(element);
2838
- });
2839
-
2840
- it("should select disabled blank by default when select is required", () => {
2841
- const html =
2842
- '<select ng-model="someModel" ng-options="c for c in choices" required>' +
2843
- '<option value="" disabled>Choose One</option>' +
2844
- "</select>";
2845
- scope.$apply(() => {
2846
- scope.choices = ["A", "B", "C"];
2847
- });
2848
-
2849
- compile(html);
2850
-
2851
- const options = element.querySelectorAll("option");
2852
- const optionToSelect = options[0];
2853
- expect(optionToSelect.textContent).toBe("Choose One");
2854
- expect(optionToSelect[0].selected).toBe(true);
2855
- expect(element.value).toBe("");
2856
-
2857
- dealoc(element);
2858
- });
2859
- });
2860
-
2861
- describe("select-many", () => {
2862
- it("should read multiple selection", () => {
2863
- createMultiSelect();
2864
-
2865
- scope.$apply(() => {
2866
- scope.values = [{ name: "A" }, { name: "B" }];
2867
- scope.selected = [];
2868
- });
2869
-
2870
- expect(element.querySelectorAll("option").length).toEqual(2);
2871
- expect(element.querySelectorAll("option")[0].selected).toBeFalsy();
2872
- expect(element.querySelectorAll("option")[1].selected).toBeFalsy();
2873
-
2874
- scope.$apply(() => {
2875
- scope.selected.push(scope.values[1]);
2876
- });
2877
-
2878
- expect(element.querySelectorAll("option").length).toEqual(2);
2879
- expect(element.querySelectorAll("option")[0].selected).toBeFalsy();
2880
- expect(element.querySelectorAll("option")[1].selected).toBeTruthy();
2881
-
2882
- scope.$apply(() => {
2883
- scope.selected.push(scope.values[0]);
2884
- });
2885
-
2886
- expect(element.querySelectorAll("option").length).toEqual(2);
2887
- expect(element.querySelectorAll("option")[0].selected).toBeTruthy();
2888
- expect(element.querySelectorAll("option")[1].selected).toBeTruthy();
2889
- });
2890
-
2891
- it("should update model on change", () => {
2892
- createMultiSelect();
2893
-
2894
- scope.$apply(() => {
2895
- scope.values = [{ name: "A" }, { name: "B" }];
2896
- scope.selected = [];
2897
- });
2898
-
2899
- element.querySelectorAll("option")[0].selected = true;
2900
-
2901
- browserTrigger(element, "change");
2902
- expect(scope.selected).toEqual([scope.values[0]]);
2903
- });
2904
-
2905
- it("should select from object", () => {
2906
- createSelect({
2907
- "ng-model": "selected",
2908
- multiple: true,
2909
- "ng-options": "key as value for (key,value) in values",
2910
- });
2911
- scope.values = { 0: "A", 1: "B" };
2912
-
2913
- scope.selected = ["1"];
2914
- expect(element.querySelectorAll("option")[1].selected).toBe(true);
2915
-
2916
- element.querySelectorAll("option")[0].selected = true;
2917
- browserTrigger(element, "change");
2918
- expect(scope.selected).toEqual(["0", "1"]);
2919
-
2920
- element.querySelectorAll("option")[1].selected = false;
2921
- browserTrigger(element, "change");
2922
- expect(scope.selected).toEqual(["0"]);
2923
- });
2924
-
2925
- it("should deselect all options when model is emptied", () => {
2926
- createMultiSelect();
2927
- scope.$apply(() => {
2928
- scope.values = [{ name: "A" }, { name: "B" }];
2929
- scope.selected = [scope.values[0]];
2930
- });
2931
- expect(element.querySelectorAll("option")[0].selected).toEqual(true);
2932
-
2933
- scope.$apply(() => {
2934
- scope.selected.pop();
2935
- });
2936
-
2937
- expect(element.querySelectorAll("option")[0].selected).toEqual(false);
2938
- });
2939
-
2940
- // Support: Safari 9+
2941
- // This test relies defining a getter/setter `selected` property on either `<option>` elements
2942
- // or their prototype. Some browsers (including Safari 9) are very flakey when the
2943
- // getter/setter is not defined on the prototype (probably due to some bug). On Safari 9, the
2944
- // getter/setter that is already defined on the `<option>` element's prototype is not
2945
- // configurable, so we can't overwrite it with our spy.
2946
- if (
2947
- !/\b(9|\d{2})(?:\.\d+)+[\s\S]*safari/i.test(window.navigator.userAgent)
2948
- ) {
2949
- it("should not re-set the `selected` property if it already has the correct value", () => {
2950
- scope.values = [{ name: "A" }, { name: "B" }];
2951
- createMultiSelect();
2952
-
2953
- const options = element.querySelectorAll("option");
2954
- const optionsSetSelected = [];
2955
- const _selected = [];
2956
-
2957
- // Set up spies
2958
- const optionProto = Object.getPrototypeOf(options[0]);
2959
- const originalSelectedDescriptor =
2960
- isFunction(Object.getOwnPropertyDescriptor) &&
2961
- Object.getOwnPropertyDescriptor(optionProto, "selected");
2962
- const addSpiesOnProto =
2963
- originalSelectedDescriptor && originalSelectedDescriptor.configurable;
2964
-
2965
- Object.entries(options).forEach(([i, option]) => {
2966
- const setSelected = function (value) {
2967
- _selected[i] = value;
2968
- };
2969
- optionsSetSelected[i] = jasmine
2970
- .createSpy(`optionSetSelected${i}`)
2971
- .and.callFake(setSelected);
2972
- setSelected(option.selected);
2973
- });
2974
-
2975
- if (!addSpiesOnProto) {
2976
- Object.entries(options).forEach(([i, option]) => {
2977
- Object.defineProperty(option, "selected", {
2978
- get() {
2979
- return _selected[i];
2980
- },
2981
- set: optionsSetSelected[i],
2982
- });
2983
- });
2984
- } else {
2985
- // Support: Firefox 54+
2986
- // We cannot use the above (simpler) method on all browsers because of Firefox 54+, which
2987
- // is very flaky when the getter/setter property is defined on the element itself and not
2988
- // the prototype. (Possibly the result of some (buggy?) optimization.)
2989
- const getSelected = function (index) {
2990
- return _selected[index];
2991
- };
2992
- const setSelected = function (index, value) {
2993
- optionsSetSelected[index](value);
2994
- };
2995
- const getSelectedOriginal = function (option) {
2996
- return originalSelectedDescriptor.get.call(option);
2997
- };
2998
- const setSelectedOriginal = function (option, value) {
2999
- originalSelectedDescriptor.set.call(option, value);
3000
- };
3001
- const getIndexAndCall = function (
3002
- option,
3003
- foundFn,
3004
- notFoundFn,
3005
- value,
3006
- ) {
3007
- for (let i = 0, ii = options.length; i < ii; ++i) {
3008
- if (options[i] === option) return foundFn(i, value);
3009
- }
3010
- return notFoundFn(option, value);
3011
- };
3012
-
3013
- Object.defineProperty(optionProto, "selected", {
3014
- get() {
3015
- return getIndexAndCall(this, getSelected, getSelectedOriginal);
3016
- },
3017
- set(value) {
3018
- return getIndexAndCall(
3019
- this,
3020
- setSelected,
3021
- setSelectedOriginal,
3022
- value,
3023
- );
3024
- },
3025
- });
3026
- }
3027
-
3028
- // Select `optionA`
3029
- scope.$apply("selected = [values[0]]");
3030
-
3031
- expect(optionsSetSelected[0]).toHaveBeenCalledOnceWith(true);
3032
- expect(optionsSetSelected[1]).not.toHaveBeenCalled();
3033
- expect(options[0].selected).toBe(true);
3034
- expect(options[1].selected).toBe(false);
3035
- optionsSetSelected[0].calls.reset();
3036
- optionsSetSelected[1].calls.reset();
3037
-
3038
- // Select `optionB` (`optionA` remains selected)
3039
- scope.$apply("selected.push(values[1])");
3040
-
3041
- expect(optionsSetSelected[0]).not.toHaveBeenCalled();
3042
- expect(optionsSetSelected[1]).toHaveBeenCalledOnceWith(true);
3043
- expect(options[0].selected).toBe(true);
3044
- expect(options[1].selected).toBe(true);
3045
- optionsSetSelected[0].calls.reset();
3046
- optionsSetSelected[1].calls.reset();
3047
-
3048
- // Unselect `optionA` (`optionB` remains selected)
3049
- scope.$apply("selected.shift()");
3050
-
3051
- expect(optionsSetSelected[0]).toHaveBeenCalledOnceWith(false);
3052
- expect(optionsSetSelected[1]).not.toHaveBeenCalled();
3053
- expect(options[0].selected).toBe(false);
3054
- expect(options[1].selected).toBe(true);
3055
- optionsSetSelected[0].calls.reset();
3056
- optionsSetSelected[1].calls.reset();
3057
-
3058
- // Reselect `optionA` (`optionB` remains selected)
3059
- scope.$apply("selected.push(values[0])");
3060
-
3061
- expect(optionsSetSelected[0]).toHaveBeenCalledOnceWith(true);
3062
- expect(optionsSetSelected[1]).not.toHaveBeenCalled();
3063
- expect(options[0].selected).toBe(true);
3064
- expect(options[1].selected).toBe(true);
3065
- optionsSetSelected[0].calls.reset();
3066
- optionsSetSelected[1].calls.reset();
3067
-
3068
- // Unselect `optionB` (`optionA` remains selected)
3069
- scope.$apply("selected.shift()");
3070
-
3071
- expect(optionsSetSelected[0]).not.toHaveBeenCalled();
3072
- expect(optionsSetSelected[1]).toHaveBeenCalledOnceWith(false);
3073
- expect(options[0].selected).toBe(true);
3074
- expect(options[1].selected).toBe(false);
3075
- optionsSetSelected[0].calls.reset();
3076
- optionsSetSelected[1].calls.reset();
3077
-
3078
- // Unselect `optionA`
3079
- scope.$apply("selected.length = 0");
3080
-
3081
- expect(optionsSetSelected[0]).toHaveBeenCalledOnceWith(false);
3082
- expect(optionsSetSelected[1]).not.toHaveBeenCalled();
3083
- expect(options[0].selected).toBe(false);
3084
- expect(options[1].selected).toBe(false);
3085
- optionsSetSelected[0].calls.reset();
3086
- optionsSetSelected[1].calls.reset();
3087
-
3088
- // Support: Firefox 54+
3089
- // Restore `originalSelectedDescriptor`
3090
- if (addSpiesOnProto) {
3091
- Object.defineProperty(
3092
- optionProto,
3093
- "selected",
3094
- originalSelectedDescriptor,
3095
- );
3096
- }
3097
- });
3098
- }
3099
-
3100
- if (window.MutationObserver) {
3101
- // IE9 and IE10 do not support MutationObserver
3102
- // Since the feature is only needed for a test, it's okay to skip these browsers
3103
- it("should render the initial options only one time", () => {
3104
- scope.value = ["black"];
3105
- scope.values = ["black", "white", "red"];
3106
- // observe-child-list adds a MutationObserver that we will read out after ngOptions
3107
- // has been compiled
3108
- createSelect({
3109
- "ng-model": "selected",
3110
- "ng-options": "value.name for value in values",
3111
- multiple: "true",
3112
- "observe-child-list": "",
3113
- });
3114
-
3115
- const optionEls = element.querySelectorAll("option");
3116
- const records = childListMutationObserver.takeRecords();
3117
-
3118
- expect(records.length).toBe(1);
3119
- expect(records[0].addedNodes).toEqual(optionEls);
3120
- });
3121
- }
3122
- });
3123
-
3124
- describe("required state", () => {
3125
- it("should set the error if the empty option is selected", () => {
3126
- createSelect(
3127
- {
3128
- "ng-model": "selection",
3129
- "ng-options": "item for item in values",
3130
- required: "",
3131
- },
3132
- true,
3133
- );
3134
-
3135
- scope.$apply(() => {
3136
- scope.values = ["a", "b"];
3137
- scope.selection = scope.values[0];
3138
- });
3139
- expect(element.classList.contains("ng-valid")).toBeTrue();
3140
- expect(ngModelCtrl.$error.required).toBeFalsy();
3141
-
3142
- const options = element.querySelectorAll("option");
3143
-
3144
- // // view -> model
3145
- setSelectValue(element, 0);
3146
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3147
- expect(ngModelCtrl.$error.required).toBeTruthy();
3148
-
3149
- setSelectValue(element, 1);
3150
- expect(element.classList.contains("ng-valid")).toBeTrue();
3151
- expect(ngModelCtrl.$error.required).toBeFalsy();
3152
-
3153
- // // model -> view
3154
- scope.$apply("selection = null");
3155
- expect(options[0].selected).toBe(true);
3156
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3157
- expect(ngModelCtrl.$error.required).toBeTruthy();
3158
- });
3159
-
3160
- it("should validate with empty option and bound ngRequired", () => {
3161
- createSelect(
3162
- {
3163
- "ng-model": "value",
3164
- "ng-options": "item.name for item in values",
3165
- "ng-required": "required",
3166
- },
3167
- true,
3168
- );
3169
-
3170
- scope.$apply(() => {
3171
- scope.values = [
3172
- { name: "A", id: 1 },
3173
- { name: "B", id: 2 },
3174
- ];
3175
- scope.required = false;
3176
- });
3177
-
3178
- const options = element.querySelectorAll("option");
3179
-
3180
- setSelectValue(element, 0);
3181
- expect(element.classList.contains("ng-valid")).toBeTrue();
3182
-
3183
- scope.$apply("required = true");
3184
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3185
-
3186
- scope.$apply("value = values[0]");
3187
- expect(element.classList.contains("ng-valid")).toBeTrue();
3188
-
3189
- setSelectValue(element, 0);
3190
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3191
-
3192
- scope.$apply("required = false");
3193
- expect(element.classList.contains("ng-valid")).toBeTrue();
3194
- });
3195
-
3196
- it("should treat an empty array as invalid when `multiple` attribute used", () => {
3197
- createSelect(
3198
- {
3199
- "ng-model": "value",
3200
- "ng-options": "item.name for item in values",
3201
- "ng-required": "required",
3202
- multiple: "",
3203
- },
3204
- true,
3205
- );
3206
-
3207
- scope.$apply(() => {
3208
- scope.value = [];
3209
- scope.values = [
3210
- { name: "A", id: 1 },
3211
- { name: "B", id: 2 },
3212
- ];
3213
- scope.required = true;
3214
- });
3215
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3216
-
3217
- scope.$apply(() => {
3218
- // ngModelWatch does not set objectEquality flag
3219
- // array must be replaced in order to trigger $formatters
3220
- scope.value = [scope.values[0]];
3221
- });
3222
- expect(element.classList.contains("ng-valid")).toBeTrue();
3223
- });
3224
-
3225
- it("should NOT set the error if the empty option is present but required attribute is not", () => {
3226
- scope.$apply(() => {
3227
- scope.values = ["a", "b"];
3228
- });
3229
-
3230
- element.innerHTML =
3231
- '<select ng-model="selected" ng-options="value.name for value in values"></select>';
3232
- injector = window.angular.bootstrap(element, ["myModule"]);
3233
- scope = injector.get("$rootScope");
3234
-
3235
- expect(element.classList.contains("ng-valid")).toBeTrue();
3236
- expect(element.classList.contains("ng-pristine")).toBeTrue();
3237
- expect(ngModelCtrl.$error.required).toBeFalsy();
3238
- });
3239
-
3240
- it("should NOT set the error if the unknown option is selected", () => {
3241
- createSelect({
3242
- "ng-model": "selection",
3243
- "ng-options": "item for item in values",
3244
- required: "",
3245
- });
3246
-
3247
- scope.$apply(() => {
3248
- scope.values = ["a", "b"];
3249
- scope.selection = "a";
3250
- });
3251
-
3252
- expect(element.classList.contains("ng-valid")).toBeTrue();
3253
- expect(ngModelCtrl.$error.required).toBeFalsy();
3254
-
3255
- scope.$apply('selection = "c"');
3256
- expect(element.value).toBe("?");
3257
- expect(element.classList.contains("ng-valid")).toBeTrue();
3258
- expect(ngModelCtrl.$error.required).toBeFalsy();
3259
- });
3260
-
3261
- it("should allow falsy values as values", () => {
3262
- createSelect(
3263
- {
3264
- "ng-model": "value",
3265
- "ng-options": "item.value as item.name for item in values",
3266
- "ng-required": "required",
3267
- },
3268
- true,
3269
- );
3270
-
3271
- scope.$apply(() => {
3272
- scope.values = [
3273
- { name: "True", value: true },
3274
- { name: "False", value: false },
3275
- ];
3276
- scope.required = false;
3277
- });
3278
-
3279
- setSelectValue(element, 2);
3280
- expect(element.classList.contains("ng-valid")).toBeTrue();
3281
- expect(scope.value).toBe(false);
3282
-
3283
- scope.$apply("required = true");
3284
- expect(element.classList.contains("ng-valid")).toBeTrue();
3285
- expect(scope.value).toBe(false);
3286
- });
3287
-
3288
- it("should validate after option list was updated", () => {
3289
- createSelect(
3290
- {
3291
- "ng-model": "selection",
3292
- "ng-options": "item for item in values",
3293
- required: "",
3294
- },
3295
- true,
3296
- );
3297
-
3298
- scope.$apply(() => {
3299
- scope.values = ["A", "B"];
3300
- scope.selection = scope.values[0];
3301
- });
3302
-
3303
- expect(element.value).toBe("string:A");
3304
- expect(element.classList.contains("ng-valid")).toBeTrue();
3305
- expect(ngModelCtrl.$error.required).toBeFalsy();
3306
-
3307
- scope.$apply(() => {
3308
- scope.values = ["C", "D"];
3309
- });
3310
-
3311
- expect(element.value).toBe("");
3312
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3313
- expect(ngModelCtrl.$error.required).toBeTruthy();
3314
- // ngModel sets undefined for invalid values
3315
- expect(scope.selection).toBeUndefined();
3316
- });
3317
- });
3318
-
3319
- describe("required and empty option", () => {
3320
- it("should select the empty option after compilation", () => {
3321
- createSelect(
3322
- {
3323
- name: "select",
3324
- "ng-model": "value",
3325
- "ng-options": "item for item in ['first', 'second', 'third']",
3326
- required: "required",
3327
- },
3328
- true,
3329
- );
3330
-
3331
- expect(element.value).toBe("");
3332
- const emptyOption = element.querySelectorAll("option")[0];
3333
- expect(emptyOption[0].selected).toBe(true);
3334
- expect(emptyOption.value).toBe("");
3335
- });
3336
- });
3337
-
3338
- describe("ngModelCtrl", () => {
3339
- it('should prefix the model value with the word "the" using $parsers', () => {
3340
- createSelect({
3341
- name: "select",
3342
- "ng-model": "value",
3343
- "ng-options": "item for item in ['first', 'second', 'third', 'fourth']",
3344
- });
3345
-
3346
- scope.form.select.$parsers.push((value) => `the ${value}`);
3347
-
3348
- setSelectValue(element, 3);
3349
- expect(scope.value).toBe("the third");
3350
- expect(element).toEqualSelectValue("third");
3351
- });
3352
-
3353
- it('should prefix the view value with the word "the" using $formatters', () => {
3354
- createSelect({
3355
- name: "select",
3356
- "ng-model": "value",
3357
- "ng-options":
3358
- "item for item in ['the first', 'the second', 'the third', 'the fourth']",
3359
- });
3360
-
3361
- scope.form.select.$formatters.push((value) => `the ${value}`);
3362
-
3363
- scope.$apply(() => {
3364
- scope.value = "third";
3365
- });
3366
- expect(element).toEqualSelectValue("the third");
3367
- });
3368
-
3369
- it("should fail validation when $validators fail", () => {
3370
- createSelect({
3371
- name: "select",
3372
- "ng-model": "value",
3373
- "ng-options": "item for item in ['first', 'second', 'third', 'fourth']",
3374
- });
3375
-
3376
- scope.form.select.$validators.fail = function () {
3377
- return false;
3378
- };
3379
-
3380
- setSelectValue(element, 3);
3381
- expect(element.classList.contains("ng-invalid")).toBeTrue();
3382
- expect(scope.value).toBeUndefined();
3383
- expect(element).toEqualSelectValue("third");
3384
- });
3385
-
3386
- it("should pass validation when $validators pass", () => {
3387
- createSelect({
3388
- name: "select",
3389
- "ng-model": "value",
3390
- "ng-options": "item for item in ['first', 'second', 'third', 'fourth']",
3391
- });
3392
-
3393
- scope.form.select.$validators.pass = function () {
3394
- return true;
3395
- };
3396
-
3397
- setSelectValue(element, 3);
3398
- expect(element.classList.contains("ng-valid")).toBeTrue();
3399
- expect(scope.value).toBe("third");
3400
- expect(element).toEqualSelectValue("third");
3401
- });
3402
-
3403
- it("should fail validation when $asyncValidators fail", () => {
3404
- let defer;
3405
- createSelect({
3406
- name: "select",
3407
- "ng-model": "value",
3408
- "ng-options": "item for item in ['first', 'second', 'third', 'fourth']",
3409
- });
3410
-
3411
- scope.form.select.$asyncValidators.async = function () {
3412
- defer = Promise.withResolvers();
3413
- return defer.promise;
3414
- };
3415
-
3416
- setSelectValue(element, 3);
3417
- expect(scope.form.select.$pending).toBeDefined();
3418
- expect(scope.value).toBeUndefined();
3419
- expect(element).toEqualSelectValue("third");
3420
-
3421
- defer.reject();
3422
- expect(scope.form.select.$pending).toBeUndefined();
3423
- expect(scope.value).toBeUndefined();
3424
- expect(element).toEqualSelectValue("third");
3425
- });
3426
-
3427
- it("should pass validation when $asyncValidators pass", () => {
3428
- let defer;
3429
- createSelect({
3430
- name: "select",
3431
- "ng-model": "value",
3432
- "ng-options": "item for item in ['first', 'second', 'third', 'fourth']",
3433
- });
3434
-
3435
- scope.form.select.$asyncValidators.async = function () {
3436
- defer = Promise.withResolvers();
3437
- return defer.promise;
3438
- };
3439
-
3440
- setSelectValue(element, 3);
3441
- expect(scope.form.select.$pending).toBeDefined();
3442
- expect(scope.value).toBeUndefined();
3443
- expect(element).toEqualSelectValue("third");
3444
-
3445
- defer.resolve();
3446
- expect(scope.form.select.$pending).toBeUndefined();
3447
- expect(scope.value).toBe("third");
3448
- expect(element).toEqualSelectValue("third");
3449
- });
3450
-
3451
- it("should not set $dirty with select-multiple after compilation", () => {
3452
- scope.values = ["a", "b"];
3453
- scope.selected = ["b"];
3454
-
3455
- createSelect({
3456
- "ng-model": "selected",
3457
- multiple: true,
3458
- "ng-options": "value for value in values",
3459
- name: "select",
3460
- });
3461
-
3462
- expect(element.querySelectorAll("option")[1].selected).toBe(true);
3463
- expect(scope.form.select.$pristine).toBe(true);
3464
- });
3465
- });
3466
-
3467
- describe("selectCtrl api", () => {
3468
- it("should reflect the status of empty and unknown option", () => {
3469
- createSingleSelect('<option ng-if="isBlank" value="">blank</option>');
3470
-
3471
- const selectCtrl = element.controller("select");
3472
-
3473
- scope.$apply(() => {
3474
- scope.values = [{ name: "A" }, { name: "B" }];
3475
- scope.isBlank = true;
3476
- });
3477
-
3478
- expect(element.value).toBe("");
3479
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3480
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(true);
3481
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3482
-
3483
- // empty -> selection
3484
- scope.$apply(() => {
3485
- scope.selected = scope.values[0];
3486
- });
3487
-
3488
- expect(element.value).not.toBe("");
3489
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3490
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3491
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3492
-
3493
- // remove empty
3494
- scope.$apply("isBlank = false");
3495
-
3496
- expect(element.value).not.toBe("");
3497
- expect(selectCtrl.$hasEmptyOption()).toBe(false);
3498
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3499
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3500
-
3501
- // selection -> unknown
3502
- scope.$apply('selected = "unmatched"');
3503
-
3504
- expect(element.value).toBe("?");
3505
- expect(selectCtrl.$hasEmptyOption()).toBe(false);
3506
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3507
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(true);
3508
-
3509
- // add empty
3510
- scope.$apply("isBlank = true");
3511
-
3512
- expect(element.value).toBe("?");
3513
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3514
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3515
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(true);
3516
-
3517
- // unknown -> empty
3518
- scope.$apply(() => {
3519
- scope.selected = null;
3520
- });
3521
-
3522
- expect(element.value).toBe("");
3523
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3524
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(true);
3525
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3526
-
3527
- // empty -> unknown
3528
- scope.$apply('selected = "unmatched"');
3529
-
3530
- expect(element.value).toBe("?");
3531
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3532
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3533
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(true);
3534
-
3535
- // unknown -> selection
3536
- scope.$apply(() => {
3537
- scope.selected = scope.values[1];
3538
- });
3539
-
3540
- expect(element.value).not.toBe("");
3541
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3542
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(false);
3543
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3544
-
3545
- // selection -> empty
3546
- scope.$apply("selected = null");
3547
-
3548
- expect(element.value).toBe("");
3549
- expect(selectCtrl.$hasEmptyOption()).toBe(true);
3550
- expect(selectCtrl.$isEmptyOptionSelected()).toBe(true);
3551
- expect(selectCtrl.$isUnknownOptionSelected()).toBe(false);
3552
- });
3553
- });
3554
- });