Skip to content

Commit

Permalink
Allow setting tooltips (#371)
Browse files Browse the repository at this point in the history
The new `tooltip` field of the ListItem class makes it possible to add
extended information as a tooltip. Also refactor the component a bit so
that the new field needs to be handled only at one place.

Fixes #317
  • Loading branch information
jtotht authored Nov 10, 2022
1 parent 5d9d48b commit 965cec7
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 33 deletions.
6 changes: 4 additions & 2 deletions src/app/components/select/multiple-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class MultipleDemoComponent implements OnInit {
ngOnInit() {
this.cities = [
{ item_id: 1, item_text: 'New Delhi' },
{ item_id: 1, item_text: 'New Delhi', item_tooltip: 'The capital of India!' },
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 3, item_text: 'Bangalore' },
{ item_id: 4, item_text: 'Pune' },
Expand All @@ -64,6 +64,7 @@ export class MultipleDemoComponent implements OnInit {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
tooltipField: 'item_tooltip',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
itemsShowLimit: 99999,
Expand Down Expand Up @@ -112,7 +113,7 @@ export class MultipleDemoComponent implements OnInit {

ngOnInit() {
this.cities = [
{ item_id: 1, item_text: 'New Delhi' },
{ item_id: 1, item_text: 'New Delhi', item_tooltip: 'The capital of India!' },
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 3, item_text: 'Bangalore', isDisabled: this.disableBangalore },
{ item_id: 4, item_text: 'Pune' },
Expand All @@ -128,6 +129,7 @@ export class MultipleDemoComponent implements OnInit {
defaultOpen: false,
idField: 'item_id',
textField: 'item_text',
tooltipField: 'item_tooltip',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
enableCheckAll: this.showAll,
Expand Down
6 changes: 3 additions & 3 deletions src/ng-multiselect-dropdown/src/multi-select.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<span tabindex="-1" class="dropdown-btn" (click)="toggleDropdown($event)">
<span *ngIf="selectedItems.length == 0">{{_placeholder}}</span>
<span *ngFor="let item of selectedItems; trackBy: trackByFn;let k = index" class="selected-item-container" >
<span class="selected-item" [hidden]="k > (this._settings.itemsShowLimit-1)">
<span class="selected-item" [hidden]="k > (this._settings.itemsShowLimit-1)" [attr.title]="item.tooltip">
<span >{{item.text}}&nbsp;</span>
<a style="padding-left:2px;color:white" (click)="onItemClick($event,item)">x</a>
</span>

</span>
<span [ngClass]="{ 'dropdown-multiselect--active': _settings.defaultOpen }" style="float:right !important;padding-right:4px">
<span style="padding-right: 15px;" *ngIf="itemShowRemaining()>0">+{{itemShowRemaining()}}</span>
Expand All @@ -26,7 +26,7 @@
</li>
</ul>
<ul class="item2" [style.maxHeight]="_settings.maxHeight+'px'">
<li *ngFor="let item of _data | multiSelectFilter:filter; let i = index;" (click)="onItemClick($event,item)" class="multiselect-item-checkbox">
<li *ngFor="let item of _data | multiSelectFilter:filter; let i = index;" (click)="onItemClick($event,item)" class="multiselect-item-checkbox" [attr.title]="item.tooltip">
<input type="checkbox" [attr.aria-label]="item.text" [checked]="isSelected(item)" [disabled]="disabled || (isLimitSelectionReached() && !isSelected(item)) || item.isDisabled" />
<div>{{item.text}}</div>
</li>
Expand Down
48 changes: 20 additions & 28 deletions src/ng-multiselect-dropdown/src/multiselect.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class MultiSelectComponent implements ControlValueAccessor {
singleSelection: false,
idField: "id",
textField: "text",
tooltipField: "tooltip",
disabledField: "isDisabled",
enableCheckAll: true,
selectAllText: "Select All",
Expand Down Expand Up @@ -76,15 +77,7 @@ export class MultiSelectComponent implements ControlValueAccessor {
const firstItem = value[0];
this._sourceDataType = typeof firstItem;
this._sourceDataFields = this.getFields(firstItem);
this._data = value.map((item: any) =>
typeof item === "string" || typeof item === "number"
? new ListItem(item)
: new ListItem({
id: item[this._settings.idField],
text: item[this._settings.textField],
isDisabled: item[this._settings.disabledField]
})
);
this._data = value.map(item => this.deobjectify(item));
}
}

Expand Down Expand Up @@ -141,30 +134,13 @@ export class MultiSelectComponent implements ControlValueAccessor {
if (this._settings.singleSelection) {
try {
if (value.length >= 1) {
const firstItem = value[0];
this.selectedItems = [
typeof firstItem === "string" || typeof firstItem === "number"
? new ListItem(firstItem)
: new ListItem({
id: firstItem[this._settings.idField],
text: firstItem[this._settings.textField],
isDisabled: firstItem[this._settings.disabledField]
})
];
this.selectedItems = [ this.deobjectify(value[0]) ];
}
} catch (e) {
// console.error(e.body.msg);
}
} else {
const _data = value.map((item: any) =>
typeof item === "string" || typeof item === "number"
? new ListItem(item)
: new ListItem({
id: item[this._settings.idField],
text: item[this._settings.textField],
isDisabled: item[this._settings.disabledField]
})
);
const _data = value.map((item: any) => this.deobjectify(item));
if (this._settings.limitSelection > 0) {
this.selectedItems = _data.splice(0, this._settings.limitSelection);
} else {
Expand Down Expand Up @@ -285,6 +261,9 @@ export class MultiSelectComponent implements ControlValueAccessor {
if (this._sourceDataFields.includes(this._settings.disabledField)) {
obj[this._settings.disabledField] = val.isDisabled;
}
if (this._sourceDataFields.includes(this._settings.tooltipField)) {
obj[this._settings.tooltipField] = val.tooltip;
}
return obj;
}
if (this._sourceDataType === 'number') {
Expand All @@ -294,6 +273,19 @@ export class MultiSelectComponent implements ControlValueAccessor {
}
}

private deobjectify(item: any) {
if (typeof item === "string" || typeof item === "number") {
return new ListItem(item);
} else {
return new ListItem({
id: item[this._settings.idField],
text: item[this._settings.textField],
tooltip: item[this._settings.tooltipField],
isDisabled: item[this._settings.disabledField]
})
}
}

toggleDropdown(evt) {
evt.preventDefault();
if (this.disabled && this._settings.singleSelection) {
Expand Down
3 changes: 3 additions & 0 deletions src/ng-multiselect-dropdown/src/multiselect.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface IDropdownSettings {
singleSelection?: boolean;
idField?: string;
textField?: string;
tooltipField?: string;
disabledField?: string;
enableCheckAll?: boolean;
selectAllText?: string;
Expand All @@ -23,6 +24,7 @@ export interface IDropdownSettings {
export class ListItem {
id: String | number;
text: String | number;
tooltip?: String | undefined;
isDisabled?: boolean;

public constructor(source: any) {
Expand All @@ -33,6 +35,7 @@ export class ListItem {
if (typeof source === 'object') {
this.id = source.id;
this.text = source.text;
this.tooltip = source.tooltip;
this.isDisabled = source.isDisabled;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Component, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { MultiSelectComponent } from './../src/multiselect.component';
import { createTestingModule } from './helper';

@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent {
@ViewChild(MultiSelectComponent, { static: false })
select: MultiSelectComponent;
cities = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangalore', tooltip_text: undefined },
{ item_id: 3, item_text: 'Pune', tooltip_text: '' },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi', tooltip_text: 'The capital of India!' }
];
selectedItem = [{ item_id: 1, item_text: 'Mumbai' }, { item_id: 4, item_text: 'Navsari' }];
dropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
tooltipField: 'item_tooltip',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('Multiple Selection:tooltip', () => {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
}));
it('should show the tooltips', fakeAsync(() => {
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
// Mumbai
expect(selCheckBoxes[1].querySelector('div').textContent).toContain('Mumbai');
expect(selCheckBoxes[1].title).toBe('');
// Bangalore
expect(selCheckBoxes[2].querySelector('div').textContent).toContain('Bangalore');
expect(selCheckBoxes[2].title).toBe('');
// Pune
expect(selCheckBoxes[3].querySelector('div').textContent).toContain('Pune');
expect(selCheckBoxes[3].title).toBe('');
// Navsari
expect(selCheckBoxes[4].querySelector('div').textContent).toContain('Navsari');
expect(selCheckBoxes[4].title).toBe('The capital of India!');
// New Delhi
expect(selCheckBoxes[5].querySelector('div').textContent).toContain('New Delhi');
expect(selCheckBoxes[5].title).toBe('');

expect(fixture.componentInstance.selectedItem.length).toEqual(2);
}));
});

0 comments on commit 965cec7

Please sign in to comment.