Skip to content

Commit 736b686

Browse files
authored
Merge pull request #6037 from IgniteUI/calendar-selection-6015-master
fix(calendar): Fix selection with ngModel - master
2 parents 41c9fa1 + 9b5e776 commit 736b686

File tree

4 files changed

+83
-27
lines changed

4 files changed

+83
-27
lines changed

projects/igniteui-angular/src/lib/calendar/calendar-base.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ export class IgxCalendarBase implements ControlValueAccessor {
421421
this.selectedDates = this.selectedDates.concat(newSelection);
422422
}
423423
}
424+
this.selectedDates = this.selectedDates.filter(d => !this.isDateDisabled(d));
424425
this.selectedDates.sort((a: Date, b: Date) => a.valueOf() - b.valueOf());
425426
this._onChangeCallback(this.selectedDates);
426427
}
@@ -500,6 +501,18 @@ export class IgxCalendarBase implements ControlValueAccessor {
500501
}
501502
}
502503

504+
/**
505+
* Performs deselection of a single value, when selection is multi
506+
* Usually performed by the selectMultiple method, but leads to bug when multiple months are in view
507+
* @hidden
508+
*/
509+
public deselectMultipleInMonth(value: Date) {
510+
const valueDateOnly = this.getDateOnly(value);
511+
this.selectedDates = this.selectedDates.filter(
512+
(date: Date) => date.getTime() !== valueDateOnly.getTime()
513+
);
514+
}
515+
503516
/**
504517
* Performs a range deselection.
505518
* @hidden
@@ -561,7 +574,7 @@ export class IgxCalendarBase implements ControlValueAccessor {
561574
* @hidden
562575
*/
563576
public writeValue(value: Date | Date[]) {
564-
this.selectedDates = value;
577+
this.selectDate(value as Date);
565578
}
566579

567580
/**
@@ -586,7 +599,7 @@ export class IgxCalendarBase implements ControlValueAccessor {
586599

587600
switch (this.selection) {
588601
case CalendarSelection.SINGLE:
589-
if (isDate(value)) {
602+
if (isDate(value) && !this.isDateDisabled(value as Date)) {
590603
this.selectSingle(value as Date);
591604
}
592605
break;
@@ -634,10 +647,7 @@ export class IgxCalendarBase implements ControlValueAccessor {
634647
switch (this.selection) {
635648
case CalendarSelection.SINGLE:
636649
case CalendarSelection.MULTI:
637-
if (!this.isDateDisabled(value)) {
638-
this.selectDate(value);
639-
}
640-
650+
this.selectDate(value);
641651
break;
642652
case CalendarSelection.RANGE:
643653
this.selectRange(value, true);

projects/igniteui-angular/src/lib/calendar/calendar-multi-view.component.spec.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('Multi-View Calendar - ', () => {
1616

1717
beforeEach(async(() => {
1818
TestBed.configureTestingModule({
19-
declarations: [MultiViewCalendarSampleComponent, MultiViewDatePickerSampleComponent],
19+
declarations: [MultiViewCalendarSampleComponent, MultiViewDatePickerSampleComponent, MultiViewNgModelSampleComponent],
2020
imports: [IgxCalendarModule, IgxDatePickerModule, FormsModule, NoopAnimationsModule]
2121
}).compileComponents();
2222
}));
@@ -978,7 +978,7 @@ describe('Multi-View Calendar - ', () => {
978978
expect(HelperTestFunctions.getMonthViewSelectedDates(fixture, 2).length).toBe(0);
979979
});
980980

981-
it('Multi Selecion - Select/Deselect date from one view should also select/deselect the date in the another', () => {
981+
it('Multi Selection - Select/Deselect date from one view should also select/deselect the date in the another', () => {
982982
spyOn(calendar.onSelection, 'emit');
983983
expect(calendar.hideOutsideDays).toBe(false);
984984
calendar.selection = 'multi';
@@ -1189,6 +1189,37 @@ describe('Multi-View Calendar - ', () => {
11891189
});
11901190
});
11911191

1192+
describe('Selection tests with ngModel - ', () => {
1193+
beforeEach(fakeAsync(() => {
1194+
fixture = TestBed.createComponent(MultiViewNgModelSampleComponent);
1195+
fixture.detectChanges();
1196+
calendar = fixture.componentInstance.calendar;
1197+
calendar.viewDate = new Date(2019, 8, 1); // 1st September 2019
1198+
tick();
1199+
fixture.detectChanges();
1200+
}));
1201+
1202+
it('Should be able to select/deselect dates in multi mode', () => {
1203+
const secondMonthDates = HelperTestFunctions.getMonthViewDates(fixture, 1);
1204+
UIInteractions.simulateClickEvent(secondMonthDates[16]);
1205+
1206+
fixture.detectChanges();
1207+
expect(calendar.value[0].getTime()).toEqual(new Date(2019, 9, 10).getTime());
1208+
expect(calendar.daysView.value[0].getTime()).toEqual(new Date(2019, 9, 10).getTime());
1209+
1210+
UIInteractions.simulateClickEvent(secondMonthDates[17]);
1211+
1212+
fixture.detectChanges();
1213+
expect(calendar.value[0].getTime()).toEqual(new Date(2019, 9, 10).getTime());
1214+
expect(calendar.value[1].getTime()).toEqual(new Date(2019, 9, 17).getTime());
1215+
expect(calendar.value[2].getTime()).toEqual(new Date(2019, 9, 18).getTime());
1216+
1217+
expect(calendar.daysView.value[0].getTime()).toEqual(new Date(2019, 9, 10).getTime());
1218+
expect(calendar.daysView.value[1].getTime()).toEqual(new Date(2019, 9, 17).getTime());
1219+
expect(calendar.daysView.value[2].getTime()).toEqual(new Date(2019, 9, 18).getTime());
1220+
});
1221+
});
1222+
11921223
describe('DatePicker/Calendar Integration Tests - ', () => {
11931224
let datePicker;
11941225
beforeEach(fakeAsync(() => {
@@ -1416,3 +1447,14 @@ export class MultiViewDatePickerSampleComponent {
14161447
public date = new Date('2019-09-15');
14171448
public monthViews = 3;
14181449
}
1450+
1451+
@Component({
1452+
template: `
1453+
<igx-calendar [monthsViewNumber]="monthViews" selection="multi" [(ngModel)]="model"></igx-calendar>
1454+
`
1455+
})
1456+
export class MultiViewNgModelSampleComponent {
1457+
@ViewChild(IgxCalendarComponent, { static: true }) public calendar: IgxCalendarComponent;
1458+
public monthViews = 3;
1459+
public model = new Date(2019, 9, 10);
1460+
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,26 @@ describe('IgxCalendar', () => {
12731273
);
12741274
});
12751275

1276+
it('Should not select date from model, if it is part of disabled dates', async () => {
1277+
const fixture = TestBed.createComponent(IgxCalendarDisabledSpecialDatesComponent);
1278+
const calendar = fixture.componentInstance.calendar;
1279+
fixture.detectChanges();
1280+
await (500);
1281+
1282+
expect(calendar.value).toBeFalsy();
1283+
});
1284+
1285+
it('Should not select date from model in range selection, if model passes null', async () => {
1286+
const fixture = TestBed.createComponent(IgxCalendarDisabledSpecialDatesComponent);
1287+
const calendar = fixture.componentInstance.calendar;
1288+
calendar.selection = 'range';
1289+
fixture.componentInstance.model = null;
1290+
fixture.detectChanges();
1291+
await (500);
1292+
1293+
expect((calendar.value as Date[]).length).toEqual(0);
1294+
});
1295+
12761296
describe('Select and deselect dates', () => {
12771297
configureTestSuite();
12781298
let fixture;
@@ -2046,7 +2066,7 @@ export class IgxCalendaRangeComponent {
20462066
`
20472067
})
20482068
export class IgxCalendarDisabledSpecialDatesComponent {
2049-
public model: Date | Date[] = new Date(2017, 5, 13);
2069+
public model: Date | Date[] = new Date(2017, 5, 23);
20502070
public viewDate = new Date(2017, 5, 13);
20512071
public specialDates = [{type: DateRangeType.Between, dateRange: [new Date(2017, 5, 1), new Date(2017, 5, 6)]}];
20522072
public disabledDates = [{type: DateRangeType.Between, dateRange: [new Date(2017, 5, 23), new Date(2017, 5, 29)]}];

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

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
458458

459459
// generally the scrolling is built on the calendar component
460460
// and all start/stop scrolling methods are called on the calendar
461-
// if we change below lines to call stopMonthScroll$ on the calendar instead of on the veiws,
461+
// if we change below lines to call stopMonthScroll$ on the calendar instead of on the views,
462462
// strange bug is introduced --> after changing number of months, continuous scrolling on mouse click does not happen
463463
this.daysView.stopMonthScroll$.next(true);
464464
this.daysView.stopMonthScroll$.complete();
@@ -610,26 +610,10 @@ export class IgxCalendarComponent extends IgxMonthPickerBase implements AfterVie
610610
*/
611611
private deselectDateInMonthViews(value: Date) {
612612
this.monthViews.forEach(m => {
613-
this.deselectMultipleInMonth(m, value);
613+
m.deselectMultipleInMonth(value);
614614
});
615615
}
616616

617-
/**
618-
* @hidden
619-
*/
620-
private deselectMultipleInMonth(monthView: IgxDaysViewComponent, value: Date) {
621-
const mDates = monthView.selectedDates.map(v => this.getDateOnly(v).getTime());
622-
const selDates = this.selectedDates.map(v => this.getDateOnly(v).getTime());
623-
624-
if (JSON.stringify(mDates) === JSON.stringify(selDates)) {
625-
return;
626-
}
627-
const valueDateOnly = this.getDateOnly(value);
628-
monthView.selectedDates = monthView.selectedDates.filter(
629-
(date: Date) => date.getTime() !== valueDateOnly.getTime()
630-
);
631-
}
632-
633617
/**
634618
* @hidden
635619
*/

0 commit comments

Comments
 (0)