Skip to content

Commit 4e8b1b2

Browse files
authored
Merge branch 'master' into set-width-hideallcolumns-master
2 parents a14d512 + 38b88ea commit 4e8b1b2

File tree

12 files changed

+212
-37
lines changed

12 files changed

+212
-37
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ All notable changes for each version of this project will be documented in this
6868
- `tickLabelsOrientation` input was added. Allows you to change the rotation of all tick labels from horizontal to vertical(toptobottom, bottomtotop).
6969
- `igxSliderTickLabel` directive has been introduced. Allows you to set a custom template for all tick labels.
7070
- `isContinuous` - input has been deleted. The option is not supported anymore.
71+
- `onValueChanged` - new output has been exposed. This event is emitted at the end of every slide interaction.
7172

7273
- `IgxCarousel`:
7374
- `keyboardSupport` input is added, which can be used to enable and disable keyboard navigation
@@ -82,6 +83,9 @@ All notable changes for each version of this project will be documented in this
8283
- `IgxSelect`:
8384
- adding `IgxSelectHeaderDirective` and `IgxSelectFooterDirective`. These can be used to provide a custom header, respectively footer templates for the `igxSelect` drop-down list. If there are no templates marked with these directives - no default templates will be used so the drop-down list will not have header nor footer.
8485

86+
- `IgxDropDown`:
87+
- `clearSelection` method is added, which can be used to deselect the selected dropdown item
88+
8589
- `IgxCircularProgressBar`:
8690
- added `IgxProgressBarGradientDirective` to allow providing custom circular progress SVG gradients. Providing a custom gradient via a template is as easy as writing:
8791
```html

projects/igniteui-angular/src/lib/drop-down/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ The following methods are available in the **igx-drop-down** component:
149149
| `setSelectedItem(index: number)` | Selects dropdown item by index. |
150150
| `open()` | Opens the dropdown. |
151151
| `close()` | Closes the dropdown. |
152+
| `clearSelection()` | Deselects the selected dropdown item. |
152153

153154
## Getters
154155
The following getters are available on the **igx-drop-down** component:

projects/igniteui-angular/src/lib/drop-down/drop-down.component.spec.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,39 @@ describe('IgxDropDown ', () => {
342342
expect(fixture.componentInstance.onSelection).toHaveBeenCalledTimes(1);
343343
}));
344344

345+
it('Should notify when selection is cleared', fakeAsync(() => {
346+
const fixture = TestBed.createComponent(IgxDropDownTestComponent);
347+
fixture.detectChanges();
348+
const button = fixture.debugElement.query(By.css('button')).nativeElement;
349+
const list = fixture.componentInstance.dropdown;
350+
const mockObj = jasmine.createSpyObj('mockEvt', ['stopPropagation', 'preventDefault']);
351+
spyOn(list.onSelection, 'emit').and.callThrough();
352+
spyOn(list.onClosed, 'emit').and.callThrough();
353+
spyOn(fixture.componentInstance, 'onSelection');
354+
355+
list.setSelectedItem(1);
356+
357+
button.click(mockObj);
358+
tick();
359+
fixture.detectChanges();
360+
expect(list.selectedItem).toEqual(list.items[1]);
361+
expect(list.onSelection.emit).toHaveBeenCalledTimes(1);
362+
expect(fixture.componentInstance.onSelection).toHaveBeenCalledTimes(1);
363+
364+
const selectionArgs: ISelectionEventArgs = {
365+
newSelection: null,
366+
oldSelection: list.items[1],
367+
cancel: false
368+
};
369+
list.clearSelection();
370+
tick();
371+
fixture.detectChanges();
372+
expect(list.selectedItem).toBeNull();
373+
expect(list.onSelection.emit).toHaveBeenCalledTimes(2);
374+
expect(fixture.componentInstance.onSelection).toHaveBeenCalledTimes(2);
375+
expect(list.onSelection.emit).toHaveBeenCalledWith(selectionArgs);
376+
}));
377+
345378
it('Should check if selection event return the proper eventArgs', fakeAsync(() => {
346379
const fixture = TestBed.createComponent(IgxDropDownTestComponent);
347380
fixture.detectChanges();
@@ -678,6 +711,45 @@ describe('IgxDropDown ', () => {
678711
expect(currentItem.componentInstance.itemIndex).toEqual(5);
679712
}));
680713

714+
it('Should deselect item when clearSelection is called', fakeAsync(() => {
715+
const fixture = TestBed.createComponent(IgxDropDownTestScrollComponent);
716+
fixture.detectChanges();
717+
const button = fixture.debugElement.query(By.css('button')).nativeElement;
718+
const list = fixture.componentInstance.dropdownScroll;
719+
const listItems = list.items;
720+
721+
list.setSelectedItem(0);
722+
button.click();
723+
tick();
724+
fixture.detectChanges();
725+
let selectedItem = fixture.debugElement.query(By.css('.' + CSS_CLASS_SELECTED));
726+
expect(selectedItem.componentInstance.itemIndex).toEqual(0);
727+
expect(listItems[0].selected).toBeTruthy();
728+
expect(selectedItem.classes[CSS_CLASS_SELECTED]).toBeTruthy();
729+
730+
list.clearSelection();
731+
tick();
732+
fixture.detectChanges();
733+
expect(listItems[0].selected).toBeFalsy();
734+
selectedItem = fixture.debugElement.query(By.css('.' + CSS_CLASS_SELECTED));
735+
expect(selectedItem).toBeNull();
736+
737+
list.setSelectedItem(5);
738+
tick();
739+
fixture.detectChanges();
740+
selectedItem = fixture.debugElement.query(By.css('.' + CSS_CLASS_SELECTED));
741+
expect(selectedItem.componentInstance.itemIndex).toEqual(5);
742+
expect(listItems[5].selected).toBeTruthy();
743+
expect(selectedItem.classes[CSS_CLASS_SELECTED]).toBeTruthy();
744+
745+
list.clearSelection();
746+
tick();
747+
fixture.detectChanges();
748+
expect(listItems[5].selected).toBeFalsy();
749+
selectedItem = fixture.debugElement.query(By.css('.' + CSS_CLASS_SELECTED));
750+
expect(selectedItem).toBeNull();
751+
}));
752+
681753
it('Home key should select the first enabled item', fakeAsync(() => {
682754
const fixture = TestBed.createComponent(IgxDropDownTestDisabledComponent);
683755
fixture.detectChanges();
@@ -1076,6 +1148,27 @@ describe('IgxDropDown ', () => {
10761148
expect(selectedItem).toBeNull();
10771149
}));
10781150

1151+
it('SelectedItem should return null when selection is cleared', fakeAsync(() => {
1152+
const fixture = TestBed.createComponent(IgxDropDownTestScrollComponent);
1153+
fixture.detectChanges();
1154+
const button = fixture.debugElement.query(By.css('button')).nativeElement;
1155+
const igxDropDown = fixture.componentInstance.dropdownScroll;
1156+
igxDropDown.setSelectedItem(3);
1157+
button.click();
1158+
tick();
1159+
1160+
fixture.detectChanges();
1161+
let selectedItem = igxDropDown.selectedItem;
1162+
expect(selectedItem).toBeTruthy();
1163+
expect(selectedItem.itemIndex).toEqual(3);
1164+
1165+
igxDropDown.clearSelection();
1166+
fixture.detectChanges();
1167+
selectedItem = igxDropDown.selectedItem;
1168+
expect(selectedItem).toBeNull();
1169+
}));
1170+
1171+
10791172
it('Should return empty array for items when there are no items', fakeAsync(() => {
10801173
const fixture = TestBed.createComponent(IgxDropDownTestEmptyListComponent);
10811174
fixture.detectChanges();

projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,23 @@ export class IgxDropDownComponent extends IgxDropDownBaseDirective implements ID
561561
}
562562
}
563563

564+
/**
565+
* Clears the selection of the dropdown
566+
* ```typescript
567+
* this.dropdown.clearSelection();
568+
* ```
569+
*/
570+
public clearSelection() {
571+
const oldSelection = this.selectedItem;
572+
const newSelection: IgxDropDownItemBaseDirective = null;
573+
const args: ISelectionEventArgs = { oldSelection, newSelection, cancel: false };
574+
this.onSelection.emit(args);
575+
if (this.selectedItem && !args.cancel) {
576+
this.selectedItem.selected = false;
577+
this.selection.clear(this.id);
578+
}
579+
}
580+
564581
/**
565582
* Checks whether the selection is valid
566583
* `null` - the selection should be emptied

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5988,6 +5988,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
59885988
const actualScrollLeft = left + rowForOf.getColumnScrollLeft(rowForOf.state.startIndex);
59895989
if (gridScrLeft !== actualScrollLeft) {
59905990
rowForOf.onHScroll(gridScrLeft);
5991+
rowForOf.cdr.detectChanges();
59915992
}
59925993
}
59935994

projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { first } from 'rxjs/operators';
2+
import { first, debounceTime } from 'rxjs/operators';
33
import { IgxColumnComponent } from './columns/column.component';
44
import { IgxGridGroupByRowComponent } from './grid/groupby-row.component';
55
import { ISelectionNode } from './selection/selection.service';
@@ -262,7 +262,7 @@ export class IgxGridNavigationService {
262262
this.getFocusableGrid().nativeElement.focus({ preventScroll: true });
263263
this.grid.verticalScrollContainer.scrollTo(targetIndex !== -1 ? targetIndex : 0);
264264
this.grid.verticalScrollContainer.onChunkLoad
265-
.pipe(first()).subscribe(() => {
265+
.pipe(debounceTime(10)).pipe(first()).subscribe(() => {
266266
const cells = this.grid.nativeElement.querySelectorAll(
267267
`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`);
268268
if (cells.length > 0) { (cells[0] as HTMLElement).focus(); }
@@ -299,7 +299,7 @@ export class IgxGridNavigationService {
299299
this.getFocusableGrid().nativeElement.focus({ preventScroll: true });
300300
this.grid.verticalScrollContainer.scrollTo(targetIndex !== -1 ? targetIndex : this.grid.dataView.length - 1);
301301
this.grid.verticalScrollContainer.onChunkLoad
302-
.pipe(first()).subscribe(() => {
302+
.pipe(debounceTime(10)).pipe(first()).subscribe(() => {
303303
const cells = this.grid.nativeElement.querySelectorAll(
304304
`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`);
305305
if (cells.length > 0) {

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-navigation.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
451451
// move focus to last summary row cell
452452
const summaryRow = summaryRows[0].nativeElement;
453453
this.focusPrevRow(summaryRow, lastIndex, childGrid, true, true);
454-
} else if (childGrid.rowList.toArray().length === 0 &&
454+
} else if (childGrid.rowList.length === 0 &&
455455
childGrid.allowFiltering && childGrid.filterMode === FilterMode.quickFilter) {
456456
// move to filter cell
457457
childGrid.navigation.moveFocusToFilterCell();
@@ -486,7 +486,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
486486
const childGridID = gridElem.getAttribute('id');
487487
const childGrid = this.getChildGrid(childGridID, grid);
488488

489-
if (childGrid.rowList.toArray().length === 0) {
489+
if (childGrid.rowList.length === 0) {
490490
this.focusNext(visibleColumnIndex, childGrid);
491491
return;
492492
}
@@ -516,7 +516,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
516516
const childGridID = gridElem.getAttribute('id');
517517
const childGrid = this.getChildGrid(childGridID, grid);
518518

519-
if (childGrid.rowList.toArray().length === 0) {
519+
if (childGrid.rowList.length === 0) {
520520
this.focusPrev(visibleColumnIndex, childGrid);
521521
return;
522522
}
@@ -669,7 +669,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
669669

670670
private focusNextRow(elem, visibleColumnIndex, grid, isSummary?) {
671671
const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary);
672-
if (grid.navigation.isColumnFullyVisible(visibleColumnIndex)) {
672+
if (grid.navigation.isColumnFullyVisible(visibleColumnIndex) || grid.rowList.length === 0) {
673673
const cell =
674674
elem.querySelector(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`);
675675
const closestScrollableGrid = this.getNextScrollableDown(grid).grid;

projects/igniteui-angular/src/lib/slider/slider.common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export interface IRangeSliderValue {
4848
upper: number;
4949
}
5050

51-
export interface ISliderValueChangeEventArgs extends IBaseEventArgs {
51+
export interface ISliderValueChangeEventArgs {
5252
oldValue: number | IRangeSliderValue;
5353
value: number | IRangeSliderValue;
5454
}

projects/igniteui-angular/src/lib/slider/slider.component.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,34 @@ describe('IgxSlider', () => {
13261326
expect(slider.lowerBound).toEqual(expectedMinVal);
13271327
expect(slider.upperBound).toEqual(expectedMaxVal);
13281328
});
1329+
1330+
it('Should emit onValueChanged only when stop interacting with the slider', () => {
1331+
const fix = TestBed.createComponent(SliderTestComponent);
1332+
fix.detectChanges();
1333+
1334+
const instance = fix.componentInstance;
1335+
const spyOnValueChanged = spyOn<any>(instance.slider.onValueChanged, 'emit').and.callThrough();
1336+
const sliderEl = fix.debugElement.query(By.css(SLIDER_CLASS));
1337+
sliderEl.triggerEventHandler('focus', null);
1338+
fix.detectChanges();
1339+
1340+
sliderEl.triggerEventHandler('pointerdown', {pointerId: 1, clientX: 200, preventDefault: <any>( ( e: any ) => { })});
1341+
fix.detectChanges();
1342+
let currentValue = instance.slider.value;
1343+
expect(spyOnValueChanged).toHaveBeenCalledTimes(0);
1344+
expect(currentValue).toBeGreaterThan(0);
1345+
1346+
sliderEl.triggerEventHandler('pointerdown', {pointerId: 1, clientX: 300, preventDefault: <any>( ( e: any ) => { })});
1347+
fix.detectChanges();
1348+
expect(spyOnValueChanged).toHaveBeenCalledTimes(0);
1349+
expect(instance.slider.value).toBeGreaterThan(currentValue as number);
1350+
1351+
currentValue = instance.slider.value;
1352+
sliderEl.triggerEventHandler('pointerup', {pointerId: 1, preventDefault: <any>( ( e: any ) => { })});
1353+
fix.detectChanges();
1354+
expect(spyOnValueChanged).toHaveBeenCalledTimes(1);
1355+
expect(instance.slider.value).toEqual(currentValue);
1356+
});
13291357
});
13301358

13311359
describe('igxSlider ticks', () => {

projects/igniteui-angular/src/lib/slider/slider.component.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ export class IgxSliderComponent implements
740740
}
741741

742742
/**
743-
* This event is emitted when user has stopped interacting the thumb and value is changed.
743+
* This event is emitted every time the value is changed.
744744
* ```typescript
745745
* public change(event){
746746
* alert("The value has been changed!");
@@ -753,6 +753,20 @@ export class IgxSliderComponent implements
753753
@Output()
754754
public onValueChange = new EventEmitter<ISliderValueChangeEventArgs>();
755755

756+
/**
757+
* This event is emitted at the end of every slide interaction.
758+
* ```typescript
759+
* public change(event){
760+
* alert("The value has been changed!");
761+
*}
762+
* ```
763+
* ```html
764+
* <igx-slider (onValueChanged)="change($event)" #slider [(ngModel)]="task.percentCompleted" [step]="5">
765+
* ```
766+
*/
767+
@Output()
768+
public onValueChanged = new EventEmitter<number | IRangeSliderValue>();
769+
756770

757771
constructor(
758772
private renderer: Renderer2,
@@ -782,7 +796,7 @@ export class IgxSliderComponent implements
782796
* @hidden
783797
*/
784798
@HostListener('pointerup', ['$event'])
785-
public onPointerUp($event) {
799+
public onPointerUp($event: PointerEvent) {
786800
if (!this.thumbTo.isActive && this.thumbFrom === undefined) {
787801
return;
788802
}
@@ -791,6 +805,7 @@ export class IgxSliderComponent implements
791805
activeThumb.nativeElement.releasePointerCapture($event.pointerId);
792806

793807
this.hideSliderIndicators();
808+
this.onValueChanged.emit(this.value);
794809
}
795810

796811
/**
@@ -809,22 +824,6 @@ export class IgxSliderComponent implements
809824
this.update($event.srcEvent.clientX);
810825
}
811826

812-
/**
813-
* @hidden
814-
*/
815-
@HostListener('panstart')
816-
public onPanStart() {
817-
this.showSliderIndicators();
818-
}
819-
820-
/**
821-
* @hidden
822-
*/
823-
@HostListener('panend')
824-
public onPanEnd() {
825-
this.hideSliderIndicators();
826-
}
827-
828827
/**
829828
*Returns whether the `IgxSliderComponent` type is RANGE.
830829
*```typescript

0 commit comments

Comments
 (0)