Skip to content

Commit

Permalink
feat(Select): now supports user requests options refresh
Browse files Browse the repository at this point in the history
ISSUES CLOSED: #1572
  • Loading branch information
benjamincharity committed Aug 7, 2019
1 parent 381f73a commit 170fb1e
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 16 deletions.
4 changes: 3 additions & 1 deletion demo/app/components/select/select.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ <h3 tsCardTitle tsVerticalSpacing>

<ts-card tsVerticalSpacing>
<h3 tsCardTitle tsVerticalSpacing>
Single Select w/ Filtering
Single Select w/ Filtering & refresh request
</h3>

<ts-select
Expand All @@ -261,10 +261,12 @@ <h3 tsCardTitle tsVerticalSpacing>
[isFilterable]="true"
[formControl]="myForm.get('myChoices1')"
[compareWith]="comparator"
[showRefresh]="true"
(selectionChange)="isChanged($event)"
(queryChange)="onFilterOptions($event)"
(optionSelected)="isSelected($event)"
(optionDeselected)="isDeselected($event)"
(optionsRefreshRequested)="refreshRequested()"
tsVerticalSpacing
>
<ts-select-trigger>
Expand Down
10 changes: 6 additions & 4 deletions demo/app/components/select/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import {
Observable,
of,
} from 'rxjs';
import {
map,
} from 'rxjs/operators';
import {map} from 'rxjs/operators';



Expand Down Expand Up @@ -285,11 +283,15 @@ export class SelectComponent implements OnInit {
} else {
const regex = new RegExp(v, 'i');
this.firstOptions = this.singleWithCustomTrigger
.pipe(map((a) => a.filter((i) => i.slug.match(regex))));
.pipe(map(a => a.filter(i => i.slug.match(regex))));
}
}

duplicate(e) {
console.log('DEMO: Duplicate selection: ', e);
}

refreshRequested() {
console.log('DEMO: Options refresh requested!');
}
}
13 changes: 12 additions & 1 deletion terminus-ui/select/src/select.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,21 @@

<!-- Outlet for options passed in by consumer -->
<ng-template *ngTemplateOutlet="contentTemplate"></ng-template>

<div
class="ts-select-panel__refresh"
*ngIf="showRefresh"
(click)="optionsRefreshRequested.emit()"
>
<ts-icon>refresh</ts-icon>
<span>
Refresh &amp; reload to bring in new choices.
</span>
</div>
</div>
</ng-template>


<ng-template #contentTemplate>
<ng-content></ng-content>
</ng-template>
</ng-template>
37 changes: 28 additions & 9 deletions terminus-ui/select/src/select.component.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- [Custom Delimiter](#custom-delimiter)
- [Custom Sort Comparator](#custom-sort-comparator)
- [Filterable](#filterable)
- [Allow user to request update](#allow-user-to-request-update)
- [Events](#events)
- [Test Helpers](#test-helpers)

Expand Down Expand Up @@ -391,19 +392,37 @@ Any unique, debounced query will be emitted through the `queryChange` emitter. T
blank option can be used to show the user a message when no items are found by the query.


### Allow user to request update

There are times where the data may change after it is loaded. The `showRefresh` option allows the user to manually request updated data.

```html
<ts-select
[formControl]="myCtrl"
[showRefresh]="true"
(optionsRefreshRequested)="userRequestedRefresh()"
>
...
</ts-select>
```


## Events

Multiple events are fired during interaction with the select:

| Event | Description | Payload |
|:---------------------|:-----------------------------------------|:-----------------|
| `closed` | Fired when the panel is closed | `undefined` |
| `duplicateSelection` | Fired when a duplicate selection is made | `string` |
| `opened` | Fired when the panel is open | `undefined` |
| `optionDeselected` | Fired when an option is deselected | `TsSelectChange` |
| `optionSelected` | Fired when an option is selected | `TsSelectChange` |
| `queryChange` | Fired when query changes | `string` |
| `selectionChange` | Fired when the selection changes | `TsSelectChange` |
| Event | Description | Payload |
|:--------------------------|:------------------------------------------------|:---------------------|
| `closed` | Fired when the panel is closed | `undefined` |
| `duplicateSelection` | Fired when a duplicate selection is made | `string` |
| `opened` | Fired when the panel is open | `undefined` |
| `optionDeselected` | Fired when an option is deselected | `TsSelectChange` |
| `optionSelected` | Fired when an option is selected | `TsSelectChange` |
| `optionsRefreshRequested` | Fired when the user selects the refresh trigger | `undefined` |
| `queryChange` | Fired when query changes | `string` |
| `selectionChange` | Fired when the selection changes | `TsSelectChange` |
| `valueChange` | Fired when the selection value changes | `string \| string[]` |


```html
<ts-select (selectionChange)="myFunction($event)">
Expand Down
25 changes: 25 additions & 0 deletions terminus-ui/select/src/select.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,31 @@ $ts-select-placeholder-arrow-space: 2 * ($ts-select-arrow-size + $ts-select-arro
position: absolute;
right: spacing(small);
}

// <div> trigger to call for options refresh
.ts-select-panel__refresh {
// Match the height of the options (3em)
$height: 3 * 16;
@include typography(body, 2);
@include typography(caption);
background-color: color(utility, xlight);
color: color(utility, dark);
cursor: cursor(pointer);
height: #{$height}px;
line-height: #{$height}px;
padding: 0 spacing(default);
transition: color 200ms ease;

.ts-icon {
height: 24px;
vertical-align: text-bottom;
}

&:focus,
&:hover {
color: color(primary);
}
}
}


Expand Down
20 changes: 20 additions & 0 deletions terminus-ui/select/src/select.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1240,4 +1240,24 @@ describe(`TsSelectComponent`, function() {

});


describe(`allow refresh requests`, function() {

test(`should show the refresh trigger and emit the event on selection`, function() {
const fixture = createComponent<testComponents.TriggerRefresh>(testComponents.TriggerRefresh);
fixture.detectChanges();
openSelect(fixture);

const refreshTrigger = fixture.debugElement.query(By.css('.ts-select-panel__refresh'));
expect(refreshTrigger).toBeTruthy();
expect(fixture.componentInstance.hasRequested).toEqual(false);

refreshTrigger.nativeElement.click();
fixture.detectChanges();

expect(fixture.componentInstance.hasRequested).toEqual(true);
});

});

});
16 changes: 15 additions & 1 deletion terminus-ui/select/src/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ const DEFAULT_VIEWPORT_MARGIN = 100;
* label="My label!"
* placeholder="My placeholder!"
* [showProgress]="true"
* [showRefresh]="true"
* [sortComparator]="myComparator"
* tabIndex="-1"
* theme="primary"
Expand All @@ -206,6 +207,7 @@ const DEFAULT_VIEWPORT_MARGIN = 100;
* (opened)="panelWasOpened($event)"
* (optionDeselected)="optionWasDeselected($event)"
* (optionSelected)="optionWasSelected($event)"
* (optionsRefreshRequested)="refreshWasSelected()"
* (queryChange)="searchQueryChanged($event)"
* (selectionChange)="aSelectionWasChanged($event)"
* (valueChange)="theValueWasChanged($event)"
Expand Down Expand Up @@ -639,11 +641,17 @@ export class TsSelectComponent implements
private _placeholder: string | undefined;

/**
* Define if the input should currently be showing a progress spinner
* Define if the component should currently be showing a progress spinner
*/
@Input()
public showProgress = false;

/**
* Define if the select should show an option to trigger a refresh (by emitting an event)
*/
@Input()
public showRefresh = false;

/**
* Function used to sort the values in a select in multiple mode
*
Expand Down Expand Up @@ -722,6 +730,12 @@ export class TsSelectComponent implements
@Output()
public readonly optionSelected: EventEmitter<TsSelectChange> = new EventEmitter();

/**
* Event for when the user requests a refresh of the available options
*/
@Output()
public readonly optionsRefreshRequested: EventEmitter<void> = new EventEmitter();

/**
* Event for when the query has changed, used by filterable select
*/
Expand Down
29 changes: 29 additions & 0 deletions terminus-ui/select/testing/src/test-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,34 @@ export class Filterable {
}
}

@Component({
template: `
<ts-select
[formControl]="myCtrl"
[showRefresh]="true"
(optionsRefreshRequested)="refreshRequested()"
>
<ts-option
[value]="option.name"
[option]="option"
*ngFor="let option of options"
>
{{ option.name }}
</ts-option>
</ts-select>
`,
})
export class TriggerRefresh {
public myCtrl = new FormControl();
public options = STATES.slice();
public hasRequested = false;

public refreshRequested() {
this.hasRequested = true;
}
}



/**
* NOTE: Currently all exported Components must belong to a module. So this is our useless module to avoid the build error.
Expand Down Expand Up @@ -895,6 +923,7 @@ export class Filterable {
SelectionChangeEventEmitters,
SelectOptionChange,
Tabindex,
TriggerRefresh,
ValidateOnChange,
],
})
Expand Down

0 comments on commit 170fb1e

Please sign in to comment.