-
Notifications
You must be signed in to change notification settings - Fork 7
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
onSelectevent - notifies the option that is currently selected
- allow navigating with
^andvarrow 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