-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexamples.html
More file actions
620 lines (589 loc) · 30 KB
/
Copy pathexamples.html
File metadata and controls
620 lines (589 loc) · 30 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>llselect + AngularJS - examples</title>
<link rel="stylesheet" href="../style.css">
<link rel="stylesheet" href="../../dist/themes/vanilla.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css">
</head>
<body ng-app="demo" ng-controller="DemoCtrl as vm">
<nav class="demo-nav">
<a href="../../">← Home</a>
<a href="../../api/">API</a>
<a href="../examples.html">Examples</a>
<a href="../benchmark.html">Benchmark</a>
<a href="../../angularjs/" class="current">AngularJS</a>
</nav>
<nav class="demo-subnav">
<span class="subnav-label"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12,2.5L20.84,5.65L19.5,17.35L12,21.5L4.5,17.35L3.16,5.65L12,2.5M12,4.5L5,7L6.08,16.22L12,19.5L17.92,16.22L19,7L12,4.5M12,5.72L16.58,16H14.87L13.94,13.72H10.04L9.12,16H7.41L12,5.72M13.34,12.3L12,9.07L10.66,12.3H13.34Z"/></svg>AngularJS 1.x</span>
<a href="../../angularjs/">README</a>
<a href="../../angularjs/api.html">API</a>
<a href="examples.html" class="current">Examples</a>
<a href="benchmark.html">Benchmark</a>
</nav>
<!-- ../toc.js injects the TOC sidebar into .page-layout; without JS this
stays a plain single-column page. Content is intentionally not
re-indented for the wrappers. -->
<div class="page-layout">
<main>
<h1>llselect + AngularJS 1.x - examples</h1>
<p>
Example directives, not a supported wrapper. Copy
<code>llselect-angularjs.js</code> (or <code>llselect-ui-select.js</code>)
into your project and adapt it. The reasoning, the source references, and
the list of deliberate gaps are in
<a href="../../angularjs/">angularjs/README.md</a>.
</p>
<p class="hint">
Run <code>npm run build</code>, then <code>npm run serve:site</code>, and open
<code>/demo/angularjs/examples.html</code>. AngularJS itself comes from a CDN; nothing
AngularJS-related is in the package.
</p>
<section>
<h2>1. Basic: <llselect-single></h2>
<p>
<code>ll-options</code> takes an <code>ng-options</code> expression. Every
clause maps onto an llselect setting; see the table in the README.
</p>
<div class="demo-row" data-src="1a">
<llselect-single ll-aria-label="Country" ng-model="vm.country" ll-filterable="true" ll-clearable="true"
ll-placeholder="'Pick a country'"
ll-options="c for c in vm.countries">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.country || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="1a"><code></code></pre></details>
</section>
<section>
<h2>2. Basic: <llselect-multiple> - count / tags / choose-all</h2>
<p>
The trigger has two displays: the default <code>'count'</code> summary and
<code>ll-trigger-display="'tags'"</code> chips. Rows carry live checkbox
icons by default (<code>ll-checkboxes="false"</code> opts out), and
<code>ll-choose-all-row="true"</code> adds the tri-state row acting on the
visible enabled subset.
</p>
<article>
<h3>2a. Default trigger: count summary</h3>
<div class="demo-row" data-src="2a">
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langsCount" ll-filterable="true" ll-clearable="true"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langsCount | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="2a"><code></code></pre></details>
</article>
<article>
<h3>2b. Tags trigger</h3>
<div class="demo-row" data-src="2b">
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langs" ll-filterable="true"
ll-trigger-display="'tags'"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langs | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="2b"><code></code></pre></details>
</article>
<article>
<h3>2c. Choose-all row</h3>
<p>
<code>ll-checkboxes</code> (default true) draws SVG checkboxes on the
rows and this row; <code>ll-checkboxes="false"</code> strips them all,
leaving plain text - which is also the core's own default (core demo
5.7).
</p>
<div class="demo-row" data-src="2c">
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langsAll" ll-filterable="true" ll-choose-all-row="true"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langsAll | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="2c"><code></code></pre></details>
</article>
<article>
<h3>2d. Hide chosen rows: ll-hide-chosen-rows</h3>
<p>
Chosen items leave the popup; removing a tag puts them back, and the
clear button puts everything back at once. Pairs with the tags trigger,
and with <code>ll-checkboxes="false"</code> - a listed row here is
always unchecked, so checkboxes would say nothing.
</p>
<div class="demo-row" data-src="2d">
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langsHidden" ll-filterable="true" ll-clearable="true"
ll-trigger-display="'tags'" ll-hide-chosen-rows="true" ll-checkboxes="false"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langsHidden | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="2d"><code></code></pre></details>
</article>
</section>
<section>
<h2>3. Form validation: name + required + form.$valid</h2>
<p>
The point of this page. <code>myForm.fruit</code> resolves because
AngularJS reads <code>name</code> off <em>this element</em> as a plain
attribute - there is no native <code><select></code> and no hidden
input anywhere. Clear the selection to watch the form go invalid.
</p>
<form name="myForm" novalidate data-src="3">
<div class="demo-row">
<llselect-single ll-aria-label="Fruit" name="fruit" ng-model="vm.fruit" required ll-clearable="true"
ll-options="f for f in vm.fruits">
</llselect-single>
</div>
<div class="demo-row">
<llselect-multiple ll-aria-label="Toppings" name="toppings" ng-model="vm.toppings" required
ll-trigger-display="'tags'"
ll-options="t for t in vm.fruits">
</llselect-multiple>
</div>
<div class="out">
myForm.$valid = <b>{{ myForm.$valid }}</b> |
myForm.$dirty = <b>{{ myForm.$dirty }}</b><br>
myForm.fruit.$error = {{ myForm.fruit.$error | json }}<br>
myForm.toppings.$error = {{ myForm.toppings.$error | json }}
<span class="hint">(toppings shows the $isEmpty override: [] counts as empty)</span>
</div>
<div class="demo-row">
<button type="button" ng-click="vm.reloadFruits()">Reload list (drops the chosen one)</button>
<span class="hint">
$dirty must stay {{ myForm.$dirty }} - a data reload is not a user edit.
</span>
</div>
</form>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="3"><code></code></pre></details>
</section>
<section>
<h2>4. Ids in ng-model: select as</h2>
<p>
<code>select as</code> is the ngModel value projection. llselect has no
equivalent setting on purpose - the app declares it, exactly as
<code>ng-options</code> does.
</p>
<div class="demo-row" data-src="4">
<llselect-single ll-aria-label="User" ng-model="vm.userId" ll-filterable="true"
ll-options="u.id as u.name group by u.role disable when u.suspended for u in vm.users track by u.id">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.userId }} <span class="hint">(a number, not the object)</span></div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="4"><code></code></pre></details>
</section>
<section>
<h2>5. ll-disabled</h2>
<p>
Setting attributes are read once at construction; <code>ll-disabled</code> gets
a <code>$watch</code> because it maps onto the <code>setDisabled()</code> method.
</p>
<div class="demo-row" data-src="5">
<label><input type="checkbox" ng-model="vm.locked"> lock</label>
<llselect-single ll-aria-label="Country" ng-model="vm.country2" ll-disabled="vm.locked"
ll-options="c for c in vm.countries">
</llselect-single>
</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="5"><code></code></pre></details>
</section>
<section>
<h2>6. ll-arrow, and llselectConfigProvider defaults</h2>
<p>
<code>ll-arrow</code> takes llselect's two built-in arrows and nothing
else; a custom one means editing your copy of the file. The house style
comes from <code>llselectConfigProvider</code> in <code>.config()</code>
(see <code>app.js</code>) - this demo sets <code>arrow: 'chevron'</code>
app-wide, which is why the selects above have one without saying so. A
per-element <code>ll-arrow</code> wins over it.
</p>
<div class="demo-row" data-src="6">
<llselect-single ll-aria-label="Country" ng-model="vm.country3" ll-arrow="triangle"
ll-options="c for c in vm.countries">
</llselect-single>
</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="6"><code></code></pre></details>
</section>
<section>
<h2>7. Custom item HTML: ll-item-content-fn</h2>
<p>
An expression evaluating to a function <code>(item) => HTMLElement | null</code>,
passed straight to llselect's <code>createItemContentElFn</code>. It runs
per rendered row per render, outside any digest, and the element is never
<code>$compile</code>d - custom rows with zero per-row scope or watcher.
The accessible name and filter text stay the item text from
<code>ll-options</code> (icons and hints never reach a screen reader).
All renderers are in
<code>app.js</code>. For real per-row Angular templates, that is
<code><ui-llselect></code> below.
</p>
<article>
<h3>7a. Icon rows, mirrored into the trigger</h3>
<p>
<code>renderLangRow</code> builds the row with <code>createElement</code>;
feeding the SAME renderer to <code>ll-trigger-content-fn</code> is what
makes the trigger show the chosen row - there is no auto-projection.
</p>
<div class="demo-row" data-src="7a">
<llselect-single ll-aria-label="Language" ng-model="vm.lang" ll-filterable="true" ll-item-content-fn="vm.renderLangRow"
ll-trigger-content-fn="vm.renderLangTrigger"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.lang || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7a"><code></code></pre></details>
</article>
<article>
<h3>7b. Template-clone flavor, beside the checkboxes</h3>
<p>
<code>renderLangRowFromTpl</code> clones the <code><template></code>
and fills it - the row markup lives in HTML, still with no scope and no
<code>$compile</code>. On a multiple the element renders beside the
default checkbox.
</p>
<div class="demo-row" data-src="7b">
<template id="lang-row-tpl">
<span class="lang-row"><i class="mdi" aria-hidden="true"></i><span class="lang-name"></span></span>
</template>
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langsRich" ll-item-content-fn="vm.renderLangRowFromTpl"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langsRich | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7b"><code></code></pre></details>
</article>
<article>
<h3>7c. Faded hint text</h3>
<p>
<code>renderUserRow</code>: primary text plus a faded hint pushed to the
row's right edge (<code>.user-row</code>), with <code>disable when</code>
dimming suspended users on top. The name highlights the filter match
via the core <code>createHighlightedTextEl</code> (7f's pattern).
</p>
<div class="demo-row" data-src="7c">
<llselect-single ll-aria-label="User" ng-model="vm.user2" ll-filterable="true" demo-publish-api="vm.userApi"
ll-item-content-fn="vm.renderUserRow"
ll-options="u.name disable when u.suspended for u in vm.users track by u.id">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.user2 || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7c"><code></code></pre></details>
</article>
<article>
<h3>7d. Rich tag chips</h3>
<p>
ONE renderer feeds rows AND chips (<code>ll-tag-content-fn</code>);
<code>ll-tag-remove-button-content-fn</code> swaps the remove icon, else
the theme's CSS glyph draws the x.
</p>
<div class="demo-row" data-src="7d">
<llselect-multiple ll-aria-label="Languages" ng-model="vm.langsTags" ll-trigger-display="'tags'"
ll-item-content-fn="vm.renderLangRow" ll-tag-content-fn="vm.renderLangRow"
ll-tag-remove-button-content-fn="vm.renderTagRemoveIcon"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-multiple>
</div>
<div class="out">ng-model = {{ vm.langsTags | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7d"><code></code></pre></details>
</article>
<article>
<h3>7e. Per-item background tint</h3>
<p>
What <code><option style="background-color"></code> does on a
native select (Chromium only): <code>renderTintedLangRow</code> is 7a's
row tinted from its icon color, with <code>createCheckmarkSvgEl</code>
on the chosen row (rows re-render on chosen changes - never stale).
All inline styles, plus one demo CSS line (<code>lang-tinted</code>)
zeroing the option element's padding. The whole trigger takes the
chosen colors: <code>demo-tint-trigger</code> requires the published
controller and paints <code>instance().triggerEl</code> (API.md
"Reaching the instance from your own directive").
</p>
<div class="demo-row" data-src="7e">
<llselect-single ll-aria-label="Language" ng-model="vm.langTinted" class="lang-tinted"
demo-tint-trigger="vm.langTinted"
ll-item-content-fn="vm.renderTintedLangRow"
ll-trigger-content-fn="vm.renderLangTrigger"
ll-options="l.name for l in vm.languages track by l.name">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.langTinted || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7e"><code></code></pre></details>
</article>
<article>
<h3>7f. Highlight the filter matches: ll-highlight</h3>
<p>
<code>ll-highlight="true"</code> wraps each query match in the default
item text in <code><mark></code> (the core
<code>createHighlightedTextEl</code>); the marks follow the typing.
With a custom <code>ll-item-content-fn</code> call the helper yourself,
the way 7c does.
</p>
<div class="demo-row" data-src="7f">
<llselect-single ll-aria-label="Country" ng-model="vm.hlCountry" ll-filterable="true" ll-highlight="true"
ll-options="c for c in vm.countries">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.hlCountry || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="7f"><code></code></pre></details>
</article>
</section>
<section>
<h2>8. <ui-llselect>: the ui-select-compatible directive</h2>
<p>
A separate directive (<code>llselect-ui-select.js</code>, module
<code>llselect.uiCompat</code>) that takes
<a href="https://github.com/angular-ui/ui-select">ui-select</a>'s
call-site markup, so an existing ui-select codebase can migrate without
rewriting every call site. New code should use
<code><llselect-single></code> /
<code><llselect-multiple></code> above instead.
</p>
<p>
Migrating a call site: rename the elements
(<code>ui-select</code> family to <code>ui-llselect</code> family) and
add <code>ll-item-text</code> - ui-select has no item-to-string concept,
and llselect needs one for the option's accessible name. The template
content carries over untouched. CSS does not - llselect owns the DOM, so
this is styled by the llselect theme.
</p>
<article>
<h3>8a. Rich row template (highlight + ui-disable-choice)</h3>
<div data-src="8a">
<ui-llselect aria-label="Person" ng-model="vm.person" name="person" required>
<ui-llselect-match placeholder="Pick a person">{{$select.selected.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name"
ui-disable-choice="p.suspended">
<span ng-bind-html="p.name | highlight: $select.search"></span>
<small class="hint">{{p.role}}{{p.suspended ? ' - suspended' : ''}}</small>
</ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.person | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8a"><code></code></pre></details>
</article>
<article>
<h3>8b. Multiple: chips from the match template</h3>
<p>
As in real ui-select, a chosen person leaves the dropdown:
<code>remove-selected</code> defaults to true (8g shows the opt-out).
</p>
<div data-src="8b">
<ui-llselect aria-label="People" ng-model="vm.people" multiple>
<ui-llselect-match>{{$item.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name">
<span ng-bind-html="p.name | highlight: $select.search"></span>
</ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.people.length }} selected</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8b"><code></code></pre></details>
</article>
<article>
<h3>8c. allow-clear</h3>
<div data-src="8c">
<ui-llselect aria-label="Person" ng-model="vm.person2">
<ui-llselect-match placeholder="Pick a person" allow-clear="true">{{$select.selected.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name">
<span ng-bind-html="p.name | highlight: $select.search"></span>
</ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.person2.name || 'undefined' }} <span class="hint">(ui-select's own allow-clear carries over: the x clears back to undefined)</span></div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8c"><code></code></pre></details>
</article>
<article>
<h3>8d. Template shapes: bare text / none</h3>
<p>
The template has three shapes: elements (above), a bare text node, or
none at all - rows then render the <code>ll-item-text</code> string
itself, which ui-select cannot do (its template is its only source of
item text).
</p>
<div data-src="8d">
<ui-llselect aria-label="Person" ng-model="vm.person3">
<ui-llselect-match placeholder="Bare text template">{{$select.selected.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name">{{p.name}} ({{p.role}})</ui-llselect-choices>
</ui-llselect>
<ui-llselect aria-label="Person" ng-model="vm.person4">
<ui-llselect-match placeholder="No template at all"></ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name"></ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.person3.name || 'undefined' }} / {{ vm.person4.name || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8d"><code></code></pre></details>
</article>
<article>
<h3>8e. Custom filter, ui-select style</h3>
<p>
The <code>| filter:</code> chain IS the custom filter, re-evaluated once
per typed query. Try <code>vlan2</code> - the <code>ifaceMatch</code>
filter (app.js) ignores spaces.
</p>
<div class="demo-row" data-src="8e">
<ui-llselect aria-label="Interface" ng-model="vm.iface2">
<ui-llselect-match placeholder="Pick an interface">{{vm.ifaceText($select.selected)}}</ui-llselect-match>
<ui-llselect-choices repeat="i in vm.interfaces | ifaceMatch: $select.search" ll-item-text="vm.ifaceText(i)"></ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.iface2 | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8e"><code></code></pre></details>
</article>
<article>
<h3>8f. ng-disabled + uib-tooltip (angular-ui-bootstrap)</h3>
<p>
Interop with <code>uib-tooltip</code> from
<a href="https://angular-ui.github.io/bootstrap/">angular-ui-bootstrap</a>
- the component kit most AngularJS apps already carry: both directives
sit on the same element, no conflict. <code>ng-disabled</code> carries
over here (ui-select parity, via <code>attrs.$observe</code>; the main
directives use <code>ll-disabled</code>). The attribute is inert on
this host, so hover works in BOTH states - the tooltip keeps working
while disabled, which a native <code>disabled</code> control forbids.
</p>
<div class="demo-row" data-src="8f">
<label><input type="checkbox" ng-model="vm.quotaLocked"> quota lock</label>
<ui-llselect aria-label="Person" ng-model="vm.person5" ng-disabled="vm.quotaLocked"
uib-tooltip="{{vm.quotaLocked ? 'Locked: people quota exceeded' : 'Pick anyone you like'}}"
tooltip-placement="top">
<ui-llselect-match placeholder="Pick a person">{{$select.selected.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name"></ui-llselect-choices>
</ui-llselect>
</div>
<div class="out">ng-model = {{ vm.person5.name || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8f"><code></code></pre></details>
</article>
<article>
<h3>8g. remove-selected: hide or keep chosen rows</h3>
<p>
Top: the default. A chosen person leaves the list, exactly like
ui-select (<code>remove-selected</code> defaults to true; bridged onto
<code>hideChosenRows</code>). Its <code>allow-clear</code> puts everyone
back at once - the deviation the API page documents. Bottom:
<code>remove-selected="false"</code> keeps chosen rows listed.
</p>
<div data-src="8g">
<div class="demo-row">
<ui-llselect aria-label="People" multiple ng-model="vm.peopleHide">
<ui-llselect-match placeholder="Default: chosen leave the list" allow-clear="true">{{$item.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name">
<span>{{p.name}}</span>
</ui-llselect-choices>
</ui-llselect>
</div>
<div class="demo-row">
<ui-llselect aria-label="People" multiple remove-selected="false" ng-model="vm.peopleKeep">
<ui-llselect-match placeholder="remove-selected=false: rows stay">{{$item.name}}</ui-llselect-match>
<ui-llselect-choices repeat="p in vm.users | filter: $select.search" ll-item-text="p.name">
<span>{{p.name}}</span>
</ui-llselect-choices>
</ui-llselect>
</div>
</div>
<div class="out">ng-model = {{ vm.peopleHide.length }} / {{ vm.peopleKeep.length }} selected</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="8g"><code></code></pre></details>
</article>
<p class="hint">
Not bridged, by rule (llselect has no such concept, so it is ignored rather
than half-implemented): tagging, sortable, append-to-body, async refresh,
limit, themes.
</p>
</section>
<section>
<h2>9. ghiscoding/angular-validation</h2>
<p>
A third-party validation library, included because it is the case that
started this: it <b>throws</b> unless the field has a <code>name</code>
(<code>validation-common.js:460</code>). It reads that name off the
<code>ng-model</code> element like everything else in AngularJS, so it
needs no native <code><select></code> either. Its
<code>validation</code> directive is <code>restrict: 'A'</code>,
<code>require: 'ngModel'</code>, and it revalidates from a watch on
<code>ctrl.$modelValue</code> - all element-agnostic.
</p>
<form name="avForm" novalidate data-src="9">
<div class="demo-row">
<llselect-single ll-aria-label="Fruit" name="avFruit" ng-model="vm.avFruit" validation="required"
ll-clearable="true" ll-options="f for f in vm.fruits">
</llselect-single>
</div>
<div class="out">
avForm.$valid = <b>{{ avForm.$valid }}</b> |
avForm.avFruit.$error = {{ avForm.avFruit.$error | json }}
</div>
</form>
<p class="hint">
Three integration facts worth knowing: it hard-depends on
<code>pascalprecht.translate</code>; its messages need
<code>$translateProvider</code> pointed at its locale files or you get
"Could not translate: 'INVALID_REQUIRED'"; and validation is debounced by
<code>typingLimit</code> (default 1000 ms), so it is not instant. Its
<code>elm.bind('blur')</code> trigger is inert here - blur does not bubble
and the focusable element is llselect's inner trigger - but the
<code>$modelValue</code> watch is the path that matters for a select.
</p>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="9"><code></code></pre></details>
</section>
<section>
<h2>10. Label element: ll-label-el</h2>
<p>
Native <code><label for></code> cannot target these divs.
<code>ll-label-el</code> points at your label's id: the label names the
field, and clicking it focuses the trigger - focus only, like a native
label. (Core demo 12, as an attribute.)
</p>
<div class="demo-row" data-src="10">
<label id="fav-fruit-label" class="field-label">Favorite fruit</label>
<llselect-single ng-model="vm.labelFruit" ll-label-el="fav-fruit-label"
ll-clearable="true" ll-options="f for f in vm.fruits">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.labelFruit || 'undefined' }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="10"><code></code></pre></details>
</section>
<section>
<h2>11. Custom filter: ll-filter-fn</h2>
<p>
Items are <code>{interfaceType: 'vlan', interfaceNo: '2'}</code>, shown
as <code>VLAN 2</code>. The default filter matches the shown text
(<code>vlan 2</code> works out of the box); the custom fn also matches
the space-less <code>vlan2</code>.
</p>
<div class="demo-row" data-src="11">
<llselect-single ll-aria-label="Interface" ng-model="vm.iface" ll-filterable="true" ll-filter-fn="vm.ifaceMatch"
ll-options="vm.ifaceText(i) for i in vm.interfaces track by i.interfaceNo">
</llselect-single>
</div>
<div class="out">ng-model = {{ vm.iface | json }}</div>
<details class="code-toggle"><summary>markup</summary><pre data-src-for="11"><code></code></pre></details>
</section>
<section>
<h2>12. Full source</h2>
<p>
The whole of what this page loads. Nothing is generated and nothing is
minified: this is the file you copy.
</p>
<details class="code-toggle"><summary>llselect-angularjs.js - <llselect-single> / <llselect-multiple></summary><pre><code id="src-llselect-angularjs"></code></pre></details>
<details class="code-toggle"><summary>ui-llselect.js - the ui-select-shaped bridge</summary><pre><code id="src-ui-llselect"></code></pre></details>
<details class="code-toggle"><summary>app.js - this demo's own controller</summary><pre><code id="src-app"></code></pre></details>
</section>
</main>
</div>
<script src="https://cdn.jsdelivr.net/npm/angular@1.8.3/angular.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/angular-sanitize@1.8.3/angular-sanitize.min.js"></script>
<!-- ui-bootstrap: only for 8f's uib-tooltip. -->
<script src="https://cdn.jsdelivr.net/npm/angular-ui-bootstrap@2.5.6/dist/ui-bootstrap-tpls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/angular-translate@2.19.1/dist/angular-translate.min.js"></script>
<!-- useStaticFilesLoader is NOT in angular-translate core; it is its own
package, and it lives at the package root, not under dist/. Without it,
$translateProvider.useStaticFilesLoader() throws $injector:unpr. -->
<script src="https://cdn.jsdelivr.net/npm/angular-translate-loader-static-files@2.19.1/angular-translate-loader-static-files.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/angular-validation-ghiscoding@1.5.28/dist/angular-validation.min.js"></script>
<script src="../../dist/index.umd.js"></script>
<script src="../../angularjs/llselect-angularjs.js"></script>
<script src="../../angularjs/llselect-ui-select.js"></script>
<script src="app.js"></script>
<!-- Source display only. A module script so it can share the demo's
highlighter; it runs after the classic scripts above. -->
<script type="module" src="source-view.js"></script>
<script type="module" src="../toc.js"></script>
</body>
</html>