mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[ACS-4986] Advanced Search - New component for Tags and Location filters (#8655)
* [ACS-4986] SearchChipsAutocompleteComponent - minimal state * [ACS-4986] refactored components * [ACS-4986] documentation * [ACS-4986] i18n * [ACS-4986] versionIndex.md * [ACS-4986] unit tests * [ACS-4986] replaced function calls on pipe * [ACS-4986] linting * [ACS-4986] slight correction * [ACS-4986] missing types * [ACS-4986] space * [ACS-4986] moved pipe + docs & tests * [ACS-4986] changed pipe type * [ACS-4986] versionIndex.md * [ACS-4986] removed 'important' in styles * [ACS-4986] fixed code smell * [ACS-4986] linting
This commit is contained in:
parent
5fafb0ea6f
commit
61d5aa965b
@ -287,10 +287,12 @@ for more information about installing and using the source code.
|
||||
| [Rating component](content-services/components/rating.component.md) | Allows a user to add and remove rating to an item. | [Source](../lib/content-services/src/lib/social/rating.component.ts) |
|
||||
| [Search check list component](content-services/components/search-check-list.component.md) | Implements a checklist widget for the Search Filter component. | [Source](../lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.ts) |
|
||||
| [Search Chip Input Component](content-services/components/search-chip-input.component.md) | Displays input for providing phrases display as "chips". | [Source](../lib/content-services/src/lib/search/components/search-chip-input/search-chip-input.component.ts) |
|
||||
| [Search Chip Autocomplete Input component](content-services/components/search-chip-autocomplete-input.component.md) | Displays an input with autocomplete options. | [Source](../lib/content-services/src/lib/search/components/search-chip-autocomplete-input/search-chip-autocomplete-input.component.ts) |
|
||||
| [Search Chip List Component](content-services/components/search-chip-list.component.md) | Displays search criteria as a set of "chips". | [Source](../lib/content-services/src/lib/search/components/search-chip-list/search-chip-list.component.ts) |
|
||||
| [Search control component](content-services/components/search-control.component.md) | Displays a input text that shows find-as-you-type suggestions. | [Source](../lib/content-services/src/lib/search/components/search-control.component.ts) |
|
||||
| [Search date range component](content-services/components/search-date-range.component.md) | Implements a search widget for the Search Filter component. | [Source](../lib/content-services/src/lib/search/components/search-date-range/search-date-range.component.ts) |
|
||||
| [Search datetime range component](content-services/components/search-datetime-range.component.md) | Implements a search widget for the Search Filter component. | [Source](../lib/content-services/src/lib/search/components/search-datetime-range/search-datetime-range.component.ts) |
|
||||
| [Search Filter Autocomplete Chips component](content-services/components/search-filter-autocomplete-chips.component.md) | Implements a search widget for the Search Filter component. | [Source](../lib/content-services/src/lib/search/components/search-filter-autocomplete-chips/search-filter-autocomplete-chips.component.ts) |
|
||||
| [Search Filter Chips component](content-services/components/search-filter-chips.component.md) | Represents a chip based container component for custom search and faceted search settings. | [Source](../lib/content-services/src/lib/search/components/search-filter-chips/search-filter-chips.component.ts) |
|
||||
| [Search Filter component](content-services/components/search-filter.component.md) | Represents a main container component for custom search and faceted search settings. | [Source](../lib/content-services/src/lib/search/components/search-filter/search-filter.component.ts) |
|
||||
| [Search Form component](content-services/components/search-form.component.md) | Search Form screenshot | [Source](../lib/content-services/src/lib/search/components/search-form/search-form.component.ts) |
|
||||
|
@ -0,0 +1,52 @@
|
||||
---
|
||||
Title: Search Chip Autocomplete Input component
|
||||
Added: v6.1.0
|
||||
Status: Active
|
||||
Last reviewed: 2023-06-13
|
||||
---
|
||||
|
||||
# [Search Chip Autocomplete Input component](../../../lib/content-services/src/lib/search/components/search-chip-autocomplete-input/search-chip-autocomplete-input.component.ts "Defined in search-chip-autocomplete-input.component.ts")
|
||||
|
||||
Represents an input with autocomplete options.
|
||||
|
||||

|
||||
|
||||
## Basic usage
|
||||
|
||||
```html
|
||||
<adf-search-chip-autocomplete-input
|
||||
[autocompleteOptions]="allOptions"
|
||||
[onReset$]="onResetObservable$"
|
||||
[allowOnlyPredefinedValues]="allowOnlyPredefinedValues"
|
||||
(optionsChanged)="onOptionsChange($event)">
|
||||
</adf-search-chip-autocomplete-input>
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
|---------------------------|--------------------------|----|-----------------------------------------------------------------------------------------------|
|
||||
| autocompleteOptions | `string[]` | [] | Options for autocomplete |
|
||||
| onReset$ | [`Observable`](https://rxjs.dev/guide/observable)`<void>` | | Observable that will listen to any reset event causing component to clear the chips and input |
|
||||
| allowOnlyPredefinedValues | boolean | true | A flag that indicates whether it is possible to add a value not from the predefined ones |
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- |-----------------------------------------------|
|
||||
| optionsChanged | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<string[]>` | Emitted when the selected options are changed |
|
||||
|
||||
## See also
|
||||
|
||||
- [Search Configuration Guide](../../user-guide/search-configuration-guide.md)
|
||||
- [Search Query Builder service](../services/search-query-builder.service.md)
|
||||
- [Search Widget Interface](../interfaces/search-widget.interface.md)
|
||||
- [Search Filter Autocomplete Chips component](search-filter-autocomplete-chips.component.md)
|
||||
- [Search Logical Filter component](search-logical-filter.component.md)
|
||||
- [Search check list component](search-check-list.component.md)
|
||||
- [Search date range component](search-date-range.component.md)
|
||||
- [Search number range component](search-number-range.component.md)
|
||||
- [Search radio component](search-radio.component.md)
|
||||
- [Search slider component](search-slider.component.md)
|
||||
- [Search text component](search-text.component.md)
|
||||
- [Search Chip Input component](search-chip-input.component.md)
|
@ -0,0 +1,67 @@
|
||||
---
|
||||
Title: Search Filter Autocomplete Chips component
|
||||
Added: v6.1.0
|
||||
Status: Active
|
||||
Last reviewed: 2023-06-13
|
||||
---
|
||||
|
||||
# [Search Filter Autocomplete Chips component](../../../lib/content-services/src/lib/search/components/search-filter-autocomplete-chips/search-filter-autocomplete-chips.component.ts "Defined in search-filter-autocomplete-chips.component.ts")
|
||||
|
||||
Implements a [search widget](../../../lib/content-services/src/lib/search/models/search-widget.interface.ts) consists of 1 input with autocomplete options representing conditions to form search query.
|
||||
|
||||

|
||||
|
||||
## Basic usage
|
||||
|
||||
```json
|
||||
{
|
||||
"search": {
|
||||
"categories": [
|
||||
{
|
||||
"id": "location",
|
||||
"name": "Location",
|
||||
"enabled": true,
|
||||
"component": {
|
||||
"selector": "autocomplete-chips",
|
||||
"settings": {
|
||||
"allowUpdateOnChange": false,
|
||||
"hideDefaultAction": true,
|
||||
"allowOnlyPredefinedValues": false,
|
||||
"field": "SITE",
|
||||
"options": [ "Option 1", "Option 2" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Settings
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- |----------|--------------------------------------------------------------------------------------------------------------------|
|
||||
| field | `string` | Field to apply the query to. Required value |
|
||||
| options | `string[]` | Predefined options for autocomplete |
|
||||
| allowOnlyPredefinedValues | `boolean` | Specifies whether the input values should only be from predefined |
|
||||
| allowUpdateOnChange | `boolean` | Enable/Disable the update fire event when text has been changed. By default is true |
|
||||
| hideDefaultAction | `boolean` | Show/hide the widget actions. By default is false |
|
||||
## Details
|
||||
|
||||
This component allows the user to choose filter options for the search query.
|
||||
See the [Search Chip Autocomplete Input component](search-chip-autocomplete-input.component.md) for more details.
|
||||
|
||||
## See also
|
||||
|
||||
- [Search Configuration Guide](../../user-guide/search-configuration-guide.md)
|
||||
- [Search Query Builder service](../services/search-query-builder.service.md)
|
||||
- [Search Widget Interface](../interfaces/search-widget.interface.md)
|
||||
- [Search Chip Autocomplete Input component](search-chip-autocomplete-input.component.md)
|
||||
- [Search Chip Input component](search-chip-input.component.md)
|
||||
- [Search check list component](search-check-list.component.md)
|
||||
- [Search date range component](search-date-range.component.md)
|
||||
- [Search number range component](search-number-range.component.md)
|
||||
- [Search radio component](search-radio.component.md)
|
||||
- [Search slider component](search-slider.component.md)
|
||||
- [Search text component](search-text.component.md)
|
||||
- [Search Logical Filter component](search-logical-filter.component.md)
|
28
docs/content-services/pipes/is-included.pipe.md
Normal file
28
docs/content-services/pipes/is-included.pipe.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
Title: Is Included pipe
|
||||
Added: v6.1.0
|
||||
Status: Active
|
||||
Last reviewed: 2023-06-13
|
||||
---
|
||||
|
||||
# [Is Included pipe](../../../lib/content-services/src/lib/pipes/is-included.pipe.ts "Defined in is-included.pipe.ts")
|
||||
|
||||
Checks if the provided value is contained in the provided array.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
<!-- {% raw %} -->
|
||||
|
||||
```HTML
|
||||
<mat-option [disabled]="value | adfIsIncluded: arrayOfValues"</mat-option>
|
||||
```
|
||||
|
||||
<!-- {% endraw %} -->
|
||||
|
||||
## Details
|
||||
|
||||
The pipe takes the provided value and checks if that value is included in the provided array and returns the appropriate boolean value.
|
||||
|
||||
## See also
|
||||
|
||||
- [File upload error pipe](./file-upload-error.pipe.md)
|
BIN
docs/docassets/images/search-chip-autocomplete-input.png
Normal file
BIN
docs/docassets/images/search-chip-autocomplete-input.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
docs/docassets/images/search-filter-autocomplete-chips.png
Normal file
BIN
docs/docassets/images/search-filter-autocomplete-chips.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -49,6 +49,9 @@ backend services have been tested with each released version of ADF.
|
||||
- [Use none component view encapsulation](eslint-angular/rules/use-none-component-view-encapsulation.md)
|
||||
- [Search Chip Input component](content-services/components/search-chip-input.component.md)
|
||||
- [Search Logical Filter component](content-services/components/search-logical-filter.component.md)
|
||||
- [Search Chip Autocomplete Input component](content-services/components/search-chip-autocomplete-input.component.md)
|
||||
- [Search Filter Autocomplete Chips component](content-services/components/search-filter-autocomplete-chips.component.md)
|
||||
- [Is Included pipe](content-services/pipes/is-included.pipe.md)
|
||||
|
||||
<!--v610 end-->
|
||||
|
||||
|
@ -297,7 +297,8 @@
|
||||
"APPLY": "Apply",
|
||||
"CLEAR-ALL": "Clear all",
|
||||
"SHOW-MORE": "Show more",
|
||||
"SHOW-LESS": "Show less"
|
||||
"SHOW-LESS": "Show less",
|
||||
"ADD_OPTION": "Add Option..."
|
||||
},
|
||||
"BUTTONS": {
|
||||
"CLOSE": "Close",
|
||||
@ -331,7 +332,8 @@
|
||||
"BEYOND-MAX-DATETIME": "The datetime is beyond the maximum datetime."
|
||||
},
|
||||
"ARIA-LABEL": {
|
||||
"SEARCH_FILTER": "Search Filter List"
|
||||
"SEARCH_FILTER": "Search Filter List",
|
||||
"OPTIONS-SELECTION": "Options Selection"
|
||||
},
|
||||
"ANY": "Any"
|
||||
},
|
||||
|
@ -19,6 +19,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NodeNameTooltipPipe } from './node-name-tooltip.pipe';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { IsIncludedPipe } from './is-included.pipe';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -26,13 +27,16 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
NodeNameTooltipPipe
|
||||
NodeNameTooltipPipe,
|
||||
IsIncludedPipe
|
||||
],
|
||||
providers: [
|
||||
NodeNameTooltipPipe
|
||||
NodeNameTooltipPipe,
|
||||
IsIncludedPipe
|
||||
],
|
||||
exports: [
|
||||
NodeNameTooltipPipe
|
||||
NodeNameTooltipPipe,
|
||||
IsIncludedPipe
|
||||
]
|
||||
})
|
||||
export class ContentPipeModule {
|
||||
|
44
lib/content-services/src/lib/pipes/is-included.pipe.spec.ts
Normal file
44
lib/content-services/src/lib/pipes/is-included.pipe.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { IsIncludedPipe } from './is-included.pipe';
|
||||
|
||||
describe('IsIncludedPipe', () => {
|
||||
|
||||
let pipe: IsIncludedPipe<any>;
|
||||
const array = [1, 2, 'test', [null], {}];
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new IsIncludedPipe();
|
||||
});
|
||||
|
||||
it('should return true if the string is contained in an array', () => {
|
||||
expect(pipe.transform('test', array)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if the string is not contained in an array', () => {
|
||||
expect(pipe.transform('test 1', array)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return true if the number is in the array', () => {
|
||||
expect(pipe.transform(2, array)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if the number is not contained in an array', () => {
|
||||
expect(pipe.transform(50, array)).toBeFalsy();
|
||||
});
|
||||
});
|
27
lib/content-services/src/lib/pipes/is-included.pipe.ts
Normal file
27
lib/content-services/src/lib/pipes/is-included.pipe.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'adfIsIncluded'
|
||||
})
|
||||
export class IsIncludedPipe<T> implements PipeTransform {
|
||||
transform(value: T, array: T[]): boolean {
|
||||
return array.includes(value);
|
||||
}
|
||||
}
|
@ -16,4 +16,5 @@
|
||||
*/
|
||||
|
||||
export * from './node-name-tooltip.pipe';
|
||||
export * from './is-included.pipe';
|
||||
export * from './content-pipe.module';
|
||||
|
@ -0,0 +1,28 @@
|
||||
<mat-form-field class="adf-chip-list" appearance="outline">
|
||||
<mat-chip-list #chipList [attr.aria-label]="'SEARCH.FILTER.ARIA-LABEL.OPTIONS-SELECTION' | translate">
|
||||
<mat-chip
|
||||
class="adf-option-chips"
|
||||
*ngFor="let option of selectedOptions"
|
||||
(removed)="remove(option)">
|
||||
<span>{{option}}</span>
|
||||
<button matChipRemove class="adf-option-chips-delete-button" [attr.aria-label]="('SEARCH.FILTER.BUTTONS.REMOVE' | translate) + ' ' + option">
|
||||
<mat-icon class="adf-option-chips-delete-icon">close</mat-icon>
|
||||
</button>
|
||||
</mat-chip>
|
||||
<input
|
||||
placeholder="{{ 'SEARCH.FILTER.ACTIONS.ADD_OPTION' | translate }}"
|
||||
#optionInput
|
||||
[formControl]="formCtrl"
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputFor]="chipList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[attr.aria-label]="'SEARCH.FILTER.ACTIONS.ADD_OPTION' | translate"
|
||||
(matChipInputTokenEnd)="add($event)">
|
||||
</mat-chip-list>
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
|
||||
<mat-option [disabled]="option | adfIsIncluded: selectedOptions" *ngFor="let option of filteredOptions$ | async"
|
||||
[ngClass]="(option | adfIsIncluded: selectedOptions) && 'adf-autocomplete-added-option'">
|
||||
{{option}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
@ -0,0 +1,46 @@
|
||||
adf-search-chip-autocomplete-input {
|
||||
.adf-chip-list {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-form-field-appearance-outline .mat-form-field-outline {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-infix {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mat-chip.adf-option-chips {
|
||||
border: 1px solid var(--theme-text-color);
|
||||
border-radius: 10px;
|
||||
background-color: var(--theme-primary-color-default-contrast);
|
||||
height: auto;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.mat-chip-remove.adf-option-chips-delete-button {
|
||||
font-size: 13px;
|
||||
height: 13px;
|
||||
width: 13px;
|
||||
|
||||
.adf-option-chips-delete-icon.mat-icon {
|
||||
font-size: 13px;
|
||||
height: 13px;
|
||||
width: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-chip-list-wrapper {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.mat-form-field-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-option.adf-autocomplete-added-option {
|
||||
background: var(--adf-theme-mat-grey-color-a200);
|
||||
color: var(--adf-theme-primary-300);
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatChip, MatChipRemove } from '@angular/material/chips';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ContentTestingModule } from '../../../testing/content.testing.module';
|
||||
import { SearchChipAutocompleteInputComponent } from './search-chip-autocomplete-input.component';
|
||||
|
||||
describe('SearchChipAutocompleteInputComponent', () => {
|
||||
let component: SearchChipAutocompleteInputComponent;
|
||||
let fixture: ComponentFixture<SearchChipAutocompleteInputComponent>;
|
||||
const onResetSubject = new Subject<void>();
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchChipAutocompleteInputComponent],
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(SearchChipAutocompleteInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.onReset$ = onResetSubject.asObservable();
|
||||
fixture.detectChanges();
|
||||
component.autocompleteOptions = ['option1', 'option2'];
|
||||
});
|
||||
|
||||
function enterNewInputValue(value: string) {
|
||||
const inputElement = fixture.debugElement.query(By.css('input'));
|
||||
inputElement.nativeElement.dispatchEvent(new Event('focusin'));
|
||||
inputElement.nativeElement.value = value;
|
||||
inputElement.nativeElement.dispatchEvent(new Event('input'));
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
function addNewOption(value: string) {
|
||||
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
inputElement.value = value;
|
||||
fixture.detectChanges();
|
||||
inputElement.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 13}));
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
function getChipList(): MatChip[] {
|
||||
return fixture.debugElement.queryAll(By.css('mat-chip')).map((chip) => chip.nativeElement);
|
||||
}
|
||||
|
||||
function getChipValue(index: number): string {
|
||||
return fixture.debugElement.queryAll(By.css('mat-chip span')).map((chip) => chip.nativeElement)[index].innerText;
|
||||
}
|
||||
|
||||
it('should add new option only if value is predefined when allowOnlyPredefinedValues = true', () => {
|
||||
addNewOption('test');
|
||||
addNewOption('option1');
|
||||
expect(getChipList().length).toBe(1);
|
||||
expect(getChipValue(0)).toBe('option1');
|
||||
});
|
||||
|
||||
it('should add new option even if value is not predefined when allowOnlyPredefinedValues = false', () => {
|
||||
component.allowOnlyPredefinedValues = false;
|
||||
addNewOption('test');
|
||||
addNewOption('option1');
|
||||
expect(getChipList().length).toBe(2);
|
||||
expect(getChipValue(0)).toBe('test');
|
||||
});
|
||||
|
||||
it('should add new option upon clicking on option from autocomplete', async () => {
|
||||
const optionsChangedSpy = spyOn(component.optionsChanged, 'emit');
|
||||
enterNewInputValue('op');
|
||||
await fixture.whenStable();
|
||||
|
||||
const matOptions = document.querySelectorAll('mat-option');
|
||||
expect(matOptions.length).toBe(2);
|
||||
|
||||
const optionToClick = matOptions[0] as HTMLElement;
|
||||
optionToClick.click();
|
||||
|
||||
expect(optionsChangedSpy).toHaveBeenCalledOnceWith(['option1']);
|
||||
expect(component.selectedOptions).toEqual(['option1']);
|
||||
expect(getChipList().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should apply class to already selected options', async () => {
|
||||
addNewOption('option1');
|
||||
enterNewInputValue('op');
|
||||
|
||||
const addedOptions = fixture.debugElement.queryAll(By.css('.adf-autocomplete-added-option'));
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(addedOptions[0]).toBeTruthy();
|
||||
expect(addedOptions.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should limit autocomplete list to 15 values max', () => {
|
||||
component.autocompleteOptions = ['a1','a2','a3','a4','a5','a6','a7','a8','a9','a10','a11','a12','a13','a14','a15','a16'];
|
||||
enterNewInputValue('a');
|
||||
|
||||
const matOptions = document.querySelectorAll('mat-option');
|
||||
expect(matOptions.length).toBe(15);
|
||||
});
|
||||
|
||||
it('should not add a value if same value has already been added', () => {
|
||||
addNewOption('option1');
|
||||
addNewOption('option1');
|
||||
expect(getChipList().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should show autocomplete list if similar predefined values exists', () => {
|
||||
enterNewInputValue('op');
|
||||
const matOptions = document.querySelectorAll('mat-option');
|
||||
expect(matOptions.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should not show autocomplete list if there are no similar predefined values', () => {
|
||||
enterNewInputValue('test');
|
||||
const matOptions = document.querySelectorAll('mat-option');
|
||||
expect(matOptions.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should emit new value when selected options changed', () => {
|
||||
const optionsChangedSpy = spyOn(component.optionsChanged, 'emit');
|
||||
addNewOption('option1');
|
||||
expect(optionsChangedSpy).toHaveBeenCalledOnceWith(['option1']);
|
||||
expect(getChipList().length).toBe(1);
|
||||
expect(getChipValue(0)).toBe('option1');
|
||||
});
|
||||
|
||||
it('should clear the input after a new value is added', () => {
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
addNewOption('option1');
|
||||
expect(input.value).toBe('');
|
||||
});
|
||||
|
||||
it('should reset all options when onReset$ event is emitted', () => {
|
||||
addNewOption('option1');
|
||||
addNewOption('option2');
|
||||
const optionsChangedSpy = spyOn(component.optionsChanged, 'emit');
|
||||
onResetSubject.next();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(optionsChangedSpy).toHaveBeenCalledOnceWith([]);
|
||||
expect(getChipList()).toEqual([]);
|
||||
expect(component.selectedOptions).toEqual([]);
|
||||
});
|
||||
|
||||
it('should remove option upon clicking remove button', () => {
|
||||
addNewOption('option1');
|
||||
addNewOption('option2');
|
||||
const optionsChangedSpy = spyOn(component.optionsChanged, 'emit');
|
||||
|
||||
fixture.debugElement.query(By.directive(MatChipRemove)).nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(optionsChangedSpy).toHaveBeenCalledOnceWith(['option2']);
|
||||
expect(getChipList().length).toEqual(1);
|
||||
});
|
||||
});
|
@ -0,0 +1,120 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, ElementRef, ViewChild, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { ENTER } from '@angular/cdk/keycodes';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatChipInputEvent } from '@angular/material/chips';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, startWith, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-search-chip-autocomplete-input',
|
||||
templateUrl: './search-chip-autocomplete-input.component.html',
|
||||
styleUrls: ['./search-chip-autocomplete-input.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchChipAutocompleteInputComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('optionInput')
|
||||
optionInput: ElementRef<HTMLInputElement>;
|
||||
|
||||
@Input()
|
||||
autocompleteOptions: string[] = [];
|
||||
|
||||
@Input()
|
||||
onReset$: Observable<void>;
|
||||
|
||||
@Input()
|
||||
allowOnlyPredefinedValues = true;
|
||||
|
||||
@Output()
|
||||
optionsChanged: EventEmitter<string[]> = new EventEmitter();
|
||||
|
||||
readonly separatorKeysCodes = [ENTER] as const;
|
||||
formCtrl = new FormControl('');
|
||||
filteredOptions$: Observable<string[]>;
|
||||
selectedOptions: string[] = [];
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor() {
|
||||
this.filteredOptions$ = this.formCtrl.valueChanges.pipe(
|
||||
startWith(null),
|
||||
map((value: string | null) => (value ? this.filter(value) : []))
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.onReset$?.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.reset());
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
add(event: MatChipInputEvent) {
|
||||
const value = (event.value || '').trim();
|
||||
|
||||
if (value && this.isExists(value) && !this.isAdded(value)) {
|
||||
this.selectedOptions.push(value);
|
||||
this.optionsChanged.emit(this.selectedOptions);
|
||||
event.chipInput.clear();
|
||||
this.formCtrl.setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
remove(value: string) {
|
||||
const index = this.selectedOptions.indexOf(value);
|
||||
|
||||
if (index >= 0) {
|
||||
this.selectedOptions.splice(index, 1);
|
||||
this.optionsChanged.emit(this.selectedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
selected(event: MatAutocompleteSelectedEvent) {
|
||||
if (!this.isAdded(event.option.viewValue)) {
|
||||
this.selectedOptions.push(event.option.viewValue);
|
||||
this.optionInput.nativeElement.value = '';
|
||||
this.formCtrl.setValue(null);
|
||||
this.optionsChanged.emit(this.selectedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
private filter(value: string): string[] {
|
||||
const filterValue = value.toLowerCase();
|
||||
return this.autocompleteOptions.filter(option => option.toLowerCase().includes(filterValue)).slice(0, 15);
|
||||
}
|
||||
|
||||
private isAdded(value: string): boolean {
|
||||
return this.selectedOptions.includes(value);
|
||||
}
|
||||
|
||||
private isExists(value: string): boolean {
|
||||
return this.allowOnlyPredefinedValues
|
||||
? this.autocompleteOptions.map(option => option.toLowerCase()).includes(value.toLowerCase())
|
||||
: true;
|
||||
}
|
||||
|
||||
private reset() {
|
||||
this.selectedOptions = [];
|
||||
this.optionsChanged.emit(this.selectedOptions);
|
||||
this.formCtrl.setValue(null);
|
||||
this.optionInput.nativeElement.value = '';
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<adf-search-chip-autocomplete-input
|
||||
[autocompleteOptions]="autocompleteOptions"
|
||||
[onReset$]="reset$"
|
||||
[allowOnlyPredefinedValues]="settings.allowOnlyPredefinedValues"
|
||||
(optionsChanged)="onOptionsChange($event)">
|
||||
</adf-search-chip-autocomplete-input>
|
||||
|
||||
<div class="adf-facet-buttons" *ngIf="!settings?.hideDefaultAction">
|
||||
<button mat-button color="primary" data-automation-id="adf-search-chip-autocomplete-btn-clear" (click)="reset()">
|
||||
{{ 'SEARCH.FILTER.ACTIONS.CLEAR' | translate }}
|
||||
</button>
|
||||
<button mat-button color="primary" data-automation-id="adf-search-chip-autocomplete-btn-apply" (click)="submitValues()">
|
||||
{{ 'SEARCH.FILTER.ACTIONS.APPLY' | translate }}
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,122 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ContentTestingModule } from '../../../testing/content.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SearchFilterAutocompleteChipsComponent } from './search-filter-autocomplete-chips.component';
|
||||
import { TagService } from '@alfresco/adf-content-services';
|
||||
import { EMPTY, of } from 'rxjs';
|
||||
|
||||
describe('SearchFilterAutocompleteChipsComponent', () => {
|
||||
let component: SearchFilterAutocompleteChipsComponent;
|
||||
let fixture: ComponentFixture<SearchFilterAutocompleteChipsComponent>;
|
||||
let tagService: TagService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchFilterAutocompleteChipsComponent],
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
],
|
||||
providers: [{
|
||||
provide: TagService,
|
||||
useValue: { getAllTheTags: () => EMPTY }
|
||||
}]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(SearchFilterAutocompleteChipsComponent);
|
||||
component = fixture.componentInstance;
|
||||
tagService = TestBed.inject(TagService);
|
||||
component.id = 'test-id';
|
||||
component.context = {
|
||||
queryFragments: {},
|
||||
update: () => EMPTY
|
||||
} as any;
|
||||
component.settings = {
|
||||
field: 'test', allowUpdateOnChange: true, hideDefaultAction: false, allowOnlyPredefinedValues: false,
|
||||
options: ['option1', 'option2']
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
function addNewOption(value: string) {
|
||||
const inputElement = fixture.debugElement.query(By.css('adf-search-chip-autocomplete-input input')).nativeElement;
|
||||
inputElement.value = value;
|
||||
inputElement.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 13}));
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
it('should set autocomplete options on init', () => {
|
||||
component.settings.options = ['test 1', 'test 2'];
|
||||
component.ngOnInit();
|
||||
expect(component.autocompleteOptions).toEqual(['test 1', 'test 2']);
|
||||
});
|
||||
|
||||
it('should load tags if field = TAG', () => {
|
||||
const tagPagingMock = {
|
||||
list: {
|
||||
pagination: {},
|
||||
entries: [{entry: {tag: 'tag1', id: 'id1'}}, {entry: {tag: 'tag2', id: 'id2'}}]
|
||||
}
|
||||
};
|
||||
|
||||
component.settings.field = 'TAG';
|
||||
spyOn(tagService, 'getAllTheTags').and.returnValue(of(tagPagingMock));
|
||||
component.ngOnInit();
|
||||
expect(component.autocompleteOptions).toEqual(['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
it('should update display value when options changes', () => {
|
||||
const newOption = 'option1';
|
||||
spyOn(component, 'onOptionsChange').and.callThrough();
|
||||
spyOn(component.displayValue$, 'next');
|
||||
addNewOption(newOption);
|
||||
|
||||
expect(component.onOptionsChange).toHaveBeenCalled();
|
||||
expect(component.displayValue$.next).toHaveBeenCalledOnceWith(newOption);
|
||||
});
|
||||
|
||||
it('should reset value and display value when reset button is clicked', () => {
|
||||
component.setValue(['option1', 'option2']);
|
||||
fixture.detectChanges();
|
||||
expect(component.selectedOptions).toEqual(['option1', 'option2']);
|
||||
spyOn(component.context, 'update');
|
||||
spyOn(component.displayValue$, 'next');
|
||||
const clearBtn: HTMLButtonElement = fixture.debugElement.query(By.css('[data-automation-id="adf-search-chip-autocomplete-btn-clear"]')).nativeElement;
|
||||
clearBtn.click();
|
||||
|
||||
expect(component.context.queryFragments[component.id]).toBe('');
|
||||
expect(component.context.update).toHaveBeenCalled();
|
||||
expect(component.selectedOptions).toEqual( [] );
|
||||
expect(component.displayValue$.next).toHaveBeenCalledWith('');
|
||||
});
|
||||
|
||||
it('should correctly compose the search query', () => {
|
||||
spyOn(component.context, 'update');
|
||||
addNewOption('option2');
|
||||
addNewOption('option1');
|
||||
const applyBtn: HTMLButtonElement = fixture.debugElement.query(By.css('[data-automation-id="adf-search-chip-autocomplete-btn-apply"]')).nativeElement;
|
||||
applyBtn.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.context.update).toHaveBeenCalled();
|
||||
expect(component.context.queryFragments[component.id]).toBe('test: "option2" OR test: "option1"');
|
||||
});
|
||||
});
|
@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { SearchWidget } from '../../models/search-widget.interface';
|
||||
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
|
||||
import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
|
||||
import { SearchFilterList } from '../../models/search-filter-list.model';
|
||||
import { TagService } from '../../../tag/services/tag.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-search-filter-autocomplete-chips',
|
||||
templateUrl: './search-filter-autocomplete-chips.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnInit {
|
||||
id: string;
|
||||
settings?: SearchWidgetSettings;
|
||||
context?: SearchQueryBuilderService;
|
||||
options: SearchFilterList<string[]>;
|
||||
startValue: string[] = null;
|
||||
displayValue$ = new Subject<string>();
|
||||
|
||||
private resetSubject$ = new Subject<void>();
|
||||
reset$: Observable<void> = this.resetSubject$.asObservable();
|
||||
autocompleteOptions: string[] = [];
|
||||
selectedOptions: string[] = [];
|
||||
enableChangeUpdate: boolean;
|
||||
|
||||
constructor( private tagService: TagService ) {
|
||||
this.options = new SearchFilterList<string[]>();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.settings) {
|
||||
this.setOptions();
|
||||
if (this.startValue) {
|
||||
this.setValue(this.startValue);
|
||||
}
|
||||
this.enableChangeUpdate = this.settings.allowUpdateOnChange ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.selectedOptions = [];
|
||||
this.resetSubject$.next();
|
||||
this.updateQuery();
|
||||
}
|
||||
|
||||
submitValues() {
|
||||
this.updateQuery();
|
||||
}
|
||||
|
||||
hasValidValue(): boolean {
|
||||
return !!this.selectedOptions;
|
||||
}
|
||||
|
||||
getCurrentValue(): string[]{
|
||||
return this.selectedOptions;
|
||||
}
|
||||
|
||||
onOptionsChange(selectedOptions: string[]) {
|
||||
this.selectedOptions = selectedOptions;
|
||||
if (this.enableChangeUpdate) {
|
||||
this.updateQuery();
|
||||
this.context.update();
|
||||
}
|
||||
}
|
||||
|
||||
setValue(value: string[]) {
|
||||
this.selectedOptions = value;
|
||||
this.displayValue$.next(this.selectedOptions.join(', '));
|
||||
this.submitValues();
|
||||
}
|
||||
|
||||
private updateQuery() {
|
||||
this.displayValue$.next(this.selectedOptions.join(', '));
|
||||
if (this.context && this.settings && this.settings.field) {
|
||||
this.context.queryFragments[this.id] = this.selectedOptions.map(val => `${this.settings.field}: "${val}"`).join(' OR ');
|
||||
this.context.update();
|
||||
}
|
||||
}
|
||||
|
||||
private setOptions() {
|
||||
if (this.settings.field === 'TAG') {
|
||||
this.tagService.getAllTheTags().subscribe(res => {
|
||||
this.autocompleteOptions = res.list.entries.map(tag => tag.entry.tag);
|
||||
});
|
||||
} else {
|
||||
this.autocompleteOptions = this.settings.options;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ export interface SearchWidgetSettings {
|
||||
unit?: string;
|
||||
/* describes query format */
|
||||
format?: string;
|
||||
/* allow the user to search only within predefined options */
|
||||
allowOnlyPredefinedValues?: boolean;
|
||||
|
||||
[indexer: string]: any;
|
||||
}
|
||||
|
@ -63,5 +63,7 @@ export * from './components/search-facet-field/search-facet-field.component';
|
||||
export * from './components/search-chip-input/search-chip-input.component';
|
||||
export * from './components/search-logical-filter/search-logical-filter.component';
|
||||
export * from './components/reset-search.directive';
|
||||
export * from './components/search-chip-autocomplete-input/search-chip-autocomplete-input.component';
|
||||
export * from './components/search-filter-autocomplete-chips/search-filter-autocomplete-chips.component';
|
||||
|
||||
export * from './search.module';
|
||||
|
@ -19,6 +19,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { ContentPipeModule } from '../pipes/content-pipe.module';
|
||||
|
||||
import { CoreModule, SearchTextModule } from '@alfresco/adf-core';
|
||||
|
||||
@ -29,6 +30,8 @@ import { SearchWidgetContainerComponent } from './components/search-widget-conta
|
||||
import { SearchFilterComponent } from './components/search-filter/search-filter.component';
|
||||
import { SearchChipListComponent } from './components/search-chip-list/search-chip-list.component';
|
||||
import { SearchTextComponent } from './components/search-text/search-text.component';
|
||||
import { SearchChipAutocompleteInputComponent } from './components/search-chip-autocomplete-input/search-chip-autocomplete-input.component';
|
||||
import { SearchFilterAutocompleteChipsComponent } from './components/search-filter-autocomplete-chips/search-filter-autocomplete-chips.component';
|
||||
import { SearchRadioComponent } from './components/search-radio/search-radio.component';
|
||||
import { SearchSliderComponent } from './components/search-slider/search-slider.component';
|
||||
import { SearchNumberRangeComponent } from './components/search-number-range/search-number-range.component';
|
||||
@ -53,6 +56,7 @@ import { ResetSearchDirective } from './components/reset-search.directive';
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ContentPipeModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MaterialModule,
|
||||
@ -67,6 +71,8 @@ import { ResetSearchDirective } from './components/reset-search.directive';
|
||||
SearchChipListComponent,
|
||||
SearchWidgetContainerComponent,
|
||||
SearchTextComponent,
|
||||
SearchChipAutocompleteInputComponent,
|
||||
SearchFilterAutocompleteChipsComponent,
|
||||
SearchRadioComponent,
|
||||
SearchSliderComponent,
|
||||
SearchNumberRangeComponent,
|
||||
@ -94,6 +100,8 @@ import { ResetSearchDirective } from './components/reset-search.directive';
|
||||
SearchChipListComponent,
|
||||
SearchWidgetContainerComponent,
|
||||
SearchTextComponent,
|
||||
SearchChipAutocompleteInputComponent,
|
||||
SearchFilterAutocompleteChipsComponent,
|
||||
SearchRadioComponent,
|
||||
SearchSliderComponent,
|
||||
SearchNumberRangeComponent,
|
||||
|
@ -24,6 +24,7 @@ import { SearchCheckListComponent } from '../components/search-check-list/search
|
||||
import { SearchDateRangeComponent } from '../components/search-date-range/search-date-range.component';
|
||||
import { SearchDatetimeRangeComponent } from '../components/search-datetime-range/search-datetime-range.component';
|
||||
import { SearchLogicalFilterComponent } from '../components/search-logical-filter/search-logical-filter.component';
|
||||
import { SearchFilterAutocompleteChipsComponent } from '../components/search-filter-autocomplete-chips/search-filter-autocomplete-chips.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -41,7 +42,8 @@ export class SearchFilterService {
|
||||
'check-list': SearchCheckListComponent,
|
||||
'date-range': SearchDateRangeComponent,
|
||||
'datetime-range': SearchDatetimeRangeComponent,
|
||||
'logical-filter': SearchLogicalFilterComponent
|
||||
'logical-filter': SearchLogicalFilterComponent,
|
||||
'autocomplete-chips': SearchFilterAutocompleteChipsComponent
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user