Skip to content

Commit

Permalink
Merge pull request #30 from SQ-UI/update-how-we-pass-displayName-prop…
Browse files Browse the repository at this point in the history
…-to-sq-typeahead

Update how we pass display name prop to sq typeahead
  • Loading branch information
ardentia authored Sep 4, 2018
2 parents 9030f05 + 54e1671 commit 1511a94
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 140 deletions.
5 changes: 5 additions & 0 deletions docs/form-elements-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ In [app.component.html](https://github.com/SQ-UI/ng-sq-ui/blob/master/src/app/ap

```html
<sq-typeahead name="typeahead"
displayProp="displayName"
formControlName="typeahead"
[searchResults]="searchResults"
(onUserInputEnd)="searchMethod($event)"
Expand Down Expand Up @@ -303,6 +304,8 @@ export class AppComponent {
}
```
> If you wish to pass just an array of string, you must omit the property `displayProp` in the html.
### Component properties:
- **`@Input()` name:** `string` - Name of the typeahead. If not provided, a generic name is generated, using the following pattern: `'sq-form-control' + new Date().getTime().toString()`.
Expand All @@ -327,6 +330,8 @@ export class AppComponent {
- **`@Input()` multiple:** `boolean` - Allow the user to choose multiple items from the search results list. Defaults to `false`.
- **`@Input()` displayProp:** `string` - Specify which property of the object to use as display property. If you are just passing an array of strings you must not assign a value to this property.
### Class properties:
- **queryInputControl:** `FormControl` - The model for the input where the user types in a `query`.
Expand Down
7 changes: 0 additions & 7 deletions docs/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,3 @@ interface LabelValuePair {
value: any;
}
```

```typescript
interface SearchResult {
displayName: string;
value: any;
}
```
Original file line number Diff line number Diff line change
@@ -1,40 +1,28 @@
<div class="typeahead-wrapper"
sqOutsideClickListener
[listenForOutsideClick]="listenForOutsideClick"
(clickOutside)="onClickOutsideComponent()">
<div class="typeahead-wrapper" sqOutsideClickListener [listenForOutsideClick]="listenForOutsideClick" (clickOutside)="onClickOutsideComponent()">
<div class="loader" *ngIf="isLoading"></div>

<div class="input-field typeahead" [ngClass]="{'disabled': disabled}">
<i class="fa fa-search" aria-hidden="true"></i>

<label class="label"
for="{{controlId}}"
*ngIf="controlLabel">
<label class="label" for="{{controlId}}" *ngIf="controlLabel">
{{controlLabel}}
</label>
<input [formControl]="queryInputControl"
*ngIf="selectedItems.size === 0"
type="text"
id="{{controlId}}"
name="{{name}}"
(focus)="turnClickOutsideListenerOn()"
placeholder="{{controlPlaceholder}}">
<input [formControl]="queryInputControl" *ngIf="selectedItems.size === 0" type="text" id="{{controlId}}" name="{{name}}"
(focus)="turnClickOutsideListenerOn()" placeholder="{{controlPlaceholder}}">

<div class="entered-items" *ngIf="selectedItems.size > 0">
<div class="entered-item chosen-item"
*ngFor="let selectedItem of selectedItems, index as itemIndex;">
<div class="content">{{selectedItem.displayName}}</div>
<div class="content">{{ selectedItem.label }}</div>
<div class="remove" (click)="removeSearchResult(itemIndex)" *ngIf="!disabled">
<i class="fa fa-times" aria-hidden="true"></i>
</div>
</div>
</div>

<div class="options" [ngClass]="{'display-none': hideResults}">
<div class="option"
*ngFor="let result of searchResults"
(click)="selectSearchResult(result)">
{{result.displayName}}
<div class="option" *ngFor="let result of options" (click)="selectSearchResult(result)">
{{ result.label }}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,32 @@ describe('TypeaheadComponent', () => {
let component: TypeaheadComponent;
let fixture: ComponentFixture<TypeaheadComponent>;

const testSearchResults = [{
displayName: 'option1',
value: {key: 1}
const testSearchResults = [
{
label: 'option1',
value: { key: 1 },
},
{
displayName: 'option2',
value: {key: 2}
label: 'option2',
value: { key: 2 },
},
{
displayName: 'option3',
value: {id: '1234', key: 3}
}];
label: 'option3',
value: { id: '1234', key: 3 },
},
];

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TypeaheadComponent,
OutsideClickListenerDirective
],
imports: [
FormsModule,
ReactiveFormsModule
]
})
.compileComponents();
declarations: [TypeaheadComponent, OutsideClickListenerDirective],
imports: [FormsModule, ReactiveFormsModule],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TypeaheadComponent);
component = fixture.componentInstance;
component.displayProp = '';
fixture.detectChanges();
});

Expand All @@ -48,7 +44,10 @@ describe('TypeaheadComponent', () => {
it('#should populate with search results on end of user input', () => {
component.searchResults = testSearchResults;

expect(component.searchResults.length > 0).toBe(true, 'search results are properly populated');
expect(component.searchResults.length > 0).toBe(
true,
'search results are properly populated',
);
});

it('#should choose one item when [multiple] = false', () => {
Expand All @@ -61,11 +60,12 @@ describe('TypeaheadComponent', () => {
component.selectSearchResult(component.searchResults[0]);
component.selectSearchResult(component.searchResults[1]);

console.log(Object.is(component.selectedItems.get(0), component.value[0]));
// the typeahead should return a new array with the copied search items
expect(component.value.length === 1 &&
!Object.is(component.selectedItems.get(0).value, component.value[0].value) &&
component.value[0].value.id === component.selectedItems.get(0).value.id)
.toBe(true, 'single choice is correctly populated');
expect(
component.value.length === 1 &&
Object.is(component.selectedItems.get(0), component.value[0]),
).toBe(true, 'single choice is correctly populated');
});

it('#should be able to choose more than one result when [multiple] = true', () => {
Expand All @@ -76,9 +76,10 @@ describe('TypeaheadComponent', () => {
component.selectSearchResult(component.searchResults[i]);
}

expect(component.value.length === testSearchResults.length &&
!Object.is(component.selectedItems, component.value))
.toBe(true, 'multiple choice is correctly populated');
expect(
component.value.length === testSearchResults.length &&
!Object.is(component.selectedItems, component.value),
).toBe(true, 'multiple choice is correctly populated');
});

it('#should remove selected item by using the remove button', () => {
Expand All @@ -89,27 +90,54 @@ describe('TypeaheadComponent', () => {

component.removeSearchResult(component.selectedItems.size - 1);

expect(component.value.length === 0)
.toBe(true, 'selected item successfully removed');
expect(component.value.length === 0).toBe(
true,
'selected item successfully removed',
);
});

it('#should be able to populate correctly with a pre-defined SearchResult[] when [multiple] = true', () => {
it('#should be able to populate correctly with a pre-defined LabelValuePair[] when [multiple] = true', () => {
component.multiple = true;
component.value = testSearchResults;
expect(component.selectedItems.toArray())
.toEqual(component.value, 'component value and immutable list have the same items and length');
expect(component.selectedItems.toArray()).toEqual(
component.value,
'component value and immutable list have the same items and length',
);
});

it('#should be able to populate correctly with a pre-defined SearchResult[] when [multiple] = false', () => {
it('#should be able to populate correctly with a pre-defined LabelValuePair[] when [multiple] = false', () => {
component.multiple = false;
component.value = testSearchResults;
const itemsToArray = component.selectedItems.toArray();
expect(itemsToArray.length === 1)
.toBe(true, 'immutable list has only one item');

expect(Object.is(itemsToArray[0], component.value[0]))
.toBe(true, 'the only item is the first one from the value array');
expect(itemsToArray.length === 1).toBe(
true,
'immutable list has only one item',
);

expect(Object.is(itemsToArray[0], component.value[0])).toBe(
true,
'the only item is the first one from the value array',
);
});

it('#should be working with plain strings', () => {
const stringSearchResults = ['option1', 'option2', 'option3'];

component.displayProp = '';
component.multiple = false;
component.value = stringSearchResults;
component.selectSearchResult(testSearchResults[0]);
component.selectSearchResult(testSearchResults[1]);

const itemsToArray = component.selectedItems.toArray();
expect(itemsToArray.length === 1).toBe(
true,
'immutable list has only one item',
);

expect(itemsToArray[0] === component.value[0]).toBe(
true,
'the only item is the first one from the value array',
);
});
});
Loading

0 comments on commit 1511a94

Please sign in to comment.