-
Notifications
You must be signed in to change notification settings - Fork 4
Select and picker
here are the underlying principles used for the select, how it goes from the most basic-est select to the user-select
the first basic notion used here is the notion of an input with a picker.
the input handles
- the 2 way data binding - via implementing the logic behind the ng control value accessor
- when to open/close the picker - via implementing popover trigger and target
- listens to its picker to update the value when the picker wnats to change it
while the picker
- diplays a way too pick a value
- highlights the current value
- notifies its input when a new value is selected
this definitions allow us to tackle all kind of inputs
- a select with a list of options
- a date input with a date picker, a la MatDatePicker
- a color picker like this one
- a text input with an auto complete
they can all be summerized by
- an input handling 2-way data binding
- a picker allowing selection of a value in a user friendly way
so then any type of input can be coupled with any kind of picker, a date input with a option-picker instead of a calendar for example.
for now only 2 kinds of picker exist in LF
- option picker allowing you to select one or more options in a list of options
- tree option picker, same but the options are displayed as a tree, and the logic behind selecting multiple options changes a bit, see department select
you can find the interfaces definitions here
So, the component lu-select
is an input with picker. it must handle the 2-way data binding and recognize and pilot its picker.
if you look at the code you'll see that it gets its picker as a ContentChild
. it will detect any ALuPickerPanel
in its content child, so this code works
<lu-select>
<lu-option-picker>...</lu-option-picker>
</lu-select>
or if you create any component and provide it as a ALuPickerPanel
, then the select will recognize it
@Component({
selector: 'my-picker',
providers: [{provide: ALuPickerPanel, useExisting: forwardRef(() => MyPickerComponent), },],
/* ... */
}) export class MyPickerComponent implements ILuPickerPanel { /* ... */ }
<lu-select>
<my-picker>...</my-picker>
</lu-select>
the other responsability is the 2-way data binding, and in particular the model -> view way. The way the select was developped, it is too generic to make assumptions on the form of its value, it can be a number
, bool
, string
, or more complex objects like user
or department
.
as a result it doesn't know how to display its value, that's where the displayer comes in
a displayer is this interface, you give it a value, it returns a ViewRef
if you look at the code agian you'll se that the select recognize its displayer the same way it does its picker.
so this code, works and displays the number
<lu-select [ngModel]="myNumber">
<span *luDisplayer="let value">{{value}}</span>
</lu-select>
this code displays it times 2
<lu-select [ngModel]="myNumber">
<span *luDisplayer="let value">{{value * 2}}</span>
</lu-select>
and this code displays a user's last name
<lu-select [ngModel]="myUser">
<span *luDisplayer="let value">{{value.lastName}}</span>
</lu-select>
at its core an the directive lu-option-picker
is a component that
- has a list of options
- listens to its options emitting a
onSelect
event - notifies the option that is currently selected
- allow navigating with
^
andv
arrow keys and selecting withenter
as for the select, it has little opinion on the form its options take, it'll just recognize them through a ContentChildren
query - code
so any component provided a ALuOptionItem
implementing ILuOptionItem
interface works, so
<!-- this works -->
<lu-option-picker>
<lu-option value="1">1</lu-option>
<lu-option value="2">2</lu-option>
<lu-option value="3">3</lu-option>
</lu-option-picker>
<!-- this works too -->
<lu-option-picker>
<lu-option *ngFor="let value of values" [value]="value">{{value}}</lu-option>
</lu-option-picker>
<!-- this works also-->
<lu-option-picker>
<my-option></my-option>
</lu-option-picker>
the lu-option-picler-advanced
directives goes a bit further, it recognizes what we call option-operators that will generate the list of options. it's made to tackle issues like
- the list of options is built dynamically via an api call
- paging a options list too large
- filtering a list of options
the way it works is the picker recognizes a list of ALuoptionOperators
through, you guessed it, ContentChildren
query. then it chains these operators, and then the operators do their thing. for example the picker sees these operators
- a feeder that provides a list of options
- a searcher that allows filtering on said list
- a pager to avoid breaking the DOM
- a template to display each option
and it chains them so the list will be filtered, then paged, then displayed.
the lucca-front library provides a number of option-operators
that you can use or you can make yours
- option feeder, searcher and pager
- api feeder, pager and searcher that handles pagination and filtering server side via parameters in the api call
- user searcher that is specific for handling users
a lu-tree-option-picker
is basically the same as an option picker but it has a list of ALuTreeOptionItem
instead of ALuOptionItem
.
all its basic functionnality are the same but when selecting a parent in the tree, it also selects all its children and its children's children and so on
like the option picker, there's a lu-tree-option-picker
and a lu-tree-option-picker-advanced
if you dont want to fumble with the differents picker and operators and displayers and what not, there are some all in one components that do all of this for you. they are fairly generic so sometimes, it wont do exactly what you want, in that case you'll have to fumble with the pickers and the displayers and the operators
its a select that pings an api to fetch a list of options. it automatically handles search-ability and pagination server side
same but for users. in the future it'll also certainly handle
- #400 former and future employees
- #413 homonyms
allows selection of a department or departments in the form of a tree