Skip to content

Select and picker

Lucien Bertin edited this page Jul 17, 2019 · 5 revisions

tl;dr

here are the underlying principles used for the select, how it goes from the most basic-est select to the user-select

Input with a picker

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

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

  • input
  • picker as you can see a picker panel extends a popover panel - see guide on popovers for more info on how the popovers work

Select, picker and displayer

So, the component lu-select is an input with picker. it must handle the 2-way data binding and recognize and pilot its picker.

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>

Displayer

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>

Option picker

Basic

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 ^ and v arrow keys and selecting with enter

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>

Advanced

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

Tree option picker

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

All in one select components

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

Api-select

example

its a select that pings an api to fetch a list of options. it automatically handles search-ability and pagination server side

User-select

example

same but for users. in the future it'll also certainly handle

  • #400 former and future employees
  • #413 homonyms

Department-select

example

allows selection of a department or departments in the form of a tree

N.B. Select multiple