I am using an Angular Material Date Picker application in my project which is a reservation form. What I want is for the user to select the date through the Date Picker. The Date Picker will have a filter that will show which dates are open and which aren't. In order for the Date Picker to know which dates are available it must make a call to one of my Services which returns an Observable. Here is my HTML code for the Date Picker:
<mat-form-field>
<label>
<input matInput [matDatepickerFilter]="dateFilter" required [matDatepicker]="picker" placeholder="Choose a date"
formControlName="date">
</label>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
and dateFilter():
dateFilter = (d: Date): boolean => {
if(monthIsSame(d) {
..// have a return statement that process a global variable: 'month: Day[]'
} else {
// the user hit the arrow at the top that switches months
//
// have a process that sets the 'month' variable to a new array of Days that was gotten
// through a RESTful api in one of my services.
// Somehow there must be a loading wheel here until the result from my server comes back and
// month is set to the new current month, and then a return statement that process a month
}
};
The problem is every time the user switches months, the calendar must load the month availability from the backside server, but the code from the server returns an Observable. Somehow the calendar must show a loading wheel until a value comes back from the subscribe method of the observable, and the calendar will get populated with the available dates.
Any help is greatly appreciated, and if I'm coming at this from the completely wrong way, please tell me. Thanks!
Edits:
Note: when I change the return type of my filter to Observable<boolean>
it sets all of the dates to be available.
I found the following post. Would it be somehow possible have a callback function that gets called when the user switches months and run my http request and load the results to a local variable. The only problem to this is that somehow the calendar would have to show a loading wheel until the callback function finishes.
mat-datepicker example Add a template reference variable mat-datepicker element. Connect mat-datepicker to input element via [matDatepicker] property. Finally add date picker toggle button to display or hide calender popup by using mat-datepicker-toggle element.
Before you can use Material date pickers, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page. Date pickers let users select a date or range of dates. They should be suitable for the context in which they appear.
To control the disabled state of the mat-datepicker-toggle, in a consistent, repeatable manner, by setting the same property on the input element.
How to make mat-calendar to refresh date filter asynchronously:
Solution is to set dateFilter
to a new value whenever data gets retrieved from server. Angular is checking this value in its change detection and refreshing the view.
// initial filter function always returns true
dateFilter = (date: Date): boolean => {return true;}
constructor( ... ) {
this.myDataObs.subscribe( () => {
// set filter function when new data is available
this.dateFilter = (date: Date): boolean => {
return filterBasedOnDataFromServer(date);
};
});
}
I'll have a shot at this with a high level plan, let's see if it helps.
You will need a service to pass data between your custom header (details in a minute) and your page component, where you have the dateFilter
method. Let's call this service OpenDatesService
. I think it should not be provided in a module, because you don't always need it, but it has to have at least as long lifecycle as your page, so ideally it is provided in your page. In that case, you should be able to inject in both the page component, and in you custom header, and those will be the same instance.
So create a custom header. You can completely grab the one from Angular Material, or the example from the docs. I'll explain using this example.
In the prev/next callbacks of the header, you don't immediately call the calendar (_dateFormats
in the example) but first start a network request, replace the arrows with a spinner (use a flag and some ngIf
s), and only re-enable the buttons once the network request has returned. Yes, this is async (observables/promise/async-await), but at this point, your are not forced to do anything synchronously. So after the network request has finished, but still before calling the calendar's prev/method, pass the open dates' data to the OpenDatesService
, ie. it should have a method sg. like updateOpenDates
. Then you can call the calendar's prev/next method.
After you have called the calendar's prev/next method, your page component's dateFilter
will be called soon. But by this time, the OpenDatesService
will have the data with the open dates, and the service is injected into the page, so in the dateFilter
you can just get it synchronously, and synchronously return the result based on it to the calendar.
So to sum up, there are 2 tricks:
dateFilter
method used by the calendar, to the click handler of the headerdateFilter
method and the header.Now that I think, you don't even need that service to pass data between the custom header and the page component. That is because the custom header is instantiated in the page component's template, where the header can just pass data up to the page with an @Output
, and the page can store it in some local fields, which are also accessible by the dateFilter
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With