Как вручную запустить фильтр выбора даты Angular Материал? - PullRequest
0 голосов
/ 23 апреля 2020

У меня есть набор фильтров для выбора даты, который в основном отфильтровывает любые даты, которые недоступны.

Это все работает, как задумано, однако, потому что это наблюдаемый, получающий все недоступные даты, он не показывать отфильтрованные даты до тех пор, пока исходные данные не будут переданы в средство выбора даты.

Вот мой фильтр:

Получите последние недоступные даты из службы, а затем отфильтруйте эти результаты

    bookingsFilter = (d: Date | null): boolean => {
        this.contentService.bookingResults.subscribe(bookings => this.bookings = bookings);
        const day = (d || new Date()).setHours(14, 0, 0, 0);
        return !this.bookings.includes(day);
    }

И фрагмент шаблона:

   <input matInput [matDatepickerFilter]="bookingsFilter" ... required />

Объект bookingResults - это субъект поведения, содержащий массив дат, каждый раз, когда проверка выполняется для серверной части, он обновляет эту тему, и это Фильтр проверяет эту тему.

Все это работает правильно, когда пользователь выбирает дату, и во время проверки она проверяется, и единственное, что я не могу заставить работать, это заставить ее отображать обновленный фильтр. нагрузить.

Ответы [ 3 ]

1 голос
/ 24 апреля 2020

То, что вы просите, невозможно, учитывая текущий API. На самом деле, я предполагаю, что this.contentService.bookingResults извлекает данные из бэкэнда, поэтому это асинхронная наблюдаемая.

MatDatepicker имеет важное поведение: фильтр устанавливается на компонент каждый раз, когда он открывается. При асинхронном API, извлекающем данные, невозможно получить последние данные в фильтре без какой-либо сложной настройки.

Можно попробовать две вещи, но у них обоих есть свои недостатки.

  1. Показать устаревший список запрещенных дат: Это то, что вы делаете прямо сейчас: показ запрещенных дат, захваченных в последний раз, когда был открыт механизм выбора даты. Это первый подход: получение последних данных за некоторое время до того, как вы действительно откроете свой DatePicker. То, как он настроен в настоящий момент (вы жалуетесь, что фильтр не работает должным образом для первого открытия), вы получаете данные во время открытия даты. Поэтому, когда вы впервые открываете его, вы получаете список данных, но это не оказывает никакого влияния на уже открытую панель выбора даты. Даты будут там, без какой-либо фильтрации. Предложения в других ответах здесь говорят вам сделать первую поездку в бэкэнд и получить запрещенные даты в методе OnInit. Я думаю, что это было бы приемлемым решением , если ваши запрещенные даты не изменились в freneti c темпе (в приложении для бронирования я думаю, что эти частые изменения в датах происходят, и это важно, так что этот подход не приемлемо).

  2. Удерживайте открытие средства выбора даты, пока не получите данные с сервера: Этот другой подход не предлагается ни в одном ответе пока удерживает указатель даты, пока вы запрашиваете у сервера ваши данные. Ну ... по крайней мере, это опыт, который вы дадите своим пользователям. Фактически, вы должны закрыть средство выбора даты, как только откроете его, go получить данные на стороне сервера и снова открыть средство выбора даты, когда данные наконец будут на клиенте. IMO, это дает пользователю ужасный UX, но у вас будут последние данные в вашем фильтре.

    Поскольку другие ответы уже показывают, как сделать подход (1), я покажу это также не этот хороший подход (2), поскольку он гарантирует, что вы будете иметь самые последние данные на фильтре:

// grab a reference to your datepicker
@ViewChild(MatDatepicker) datepicker: MatDatepicker<Date>;

ngAfterViewInit() {
  this.subscribeToOpeningStream();
}

subscribeToOpeningStream() {
  this.datepicker.openedStream
    .pipe(
      tap(() => {
        // close the datepicker
        this.datepicker.close();
        // disable the datepicker so the user didn't try to open it again
        // while going to the server
        this.datepicker.disabled = true;
      }),
      // unsubscribe to the openedStream: it avoids an infinite loop
      // when you repoen the datepicker inside the subscriber function
      take(1),

      // this is when you go to the server to grab the most recent
      // list of forbidden dates. Notice that if you don't go to the
      // server, this would be a potentially synchronous observable
      // and the overall logic on this setup will probably not work
      // without adding a delay(300) to the observables pipe here
      switchMap(() => this.contentService.bookingResults),
    )
    .subscribe((bookings: any) => {
      this.bookings = bookings;

      // enable the datepicker again
      this.datepicker.disabled = false;

      // reopens the date picker
      this.datepicker.open();

      // resubscribe to openedStream
      this.subscribeToOpeningStream();

    });
}

Здесь у вас есть Stackblitz demo .

Что еще не сделано с вышеупомянутым решением: максимально улучшить UX. Возможно, при открытии средства выбора даты во вращающемся элементе.

Кроме того, рассмотрите возможность использования веб-сокета, чтобы вы могли подписаться на изменения в запрещенные даты. При правильном использовании он может сохранить UX вашего приложения.

0 голосов
/ 23 апреля 2020

у вас две проблемы, во-первых, это ответ Nabel, вам нужно подписаться и придать значение this.bookings в ngOnInit, помните, что ваш сервис делает асиновый вызов c, поэтому в вашей функции this. bookings "не имеет значения

ngOnInit()
{
    this.contentService.bookingResults
        .subscribe(bookings => this.bookings = bookings);
}

Вторая проблема заключается в том, что вы всегда получаете false, вы сравниваете объекты, а два объекта (две даты) имеют разные значения -yes, имеют одинаковое значение, но они различаются. Например,

const date1=new Date()
const date2=new Date()
const equal=date==date1 //equal is false

Таким образом, вы можете сохранить в бронировании getTime или строку в формате YYYYMMdd и сравнить с форматированными d.getTime () или d

ngOnInit()
{
    this.contentService.bookingResults
        .subscribe(bookings => this.bookings = bookings.map(x=>{
                 return x.getFullYear()
                        +('00'+(x.getMonth()+1)).slice(-2)
                        +('00'+x.getDate()).slice(-2)
                 })
        )    
}

This.bookings - это массив строк, поэтому вы можете сделать

  bookingsFilter = (d: Date): boolean => {
    const date=d.getFullYear()+
               ('00'+(d.getMonth()+1)).slice(-2)+
               ('00'+d.getDate()).slice(-2)
        return this.bookings.includes(date);
    }
0 голосов
/ 23 апреля 2020

Вы можете просто подписаться на onInit (), так как вы уже назначили его этому .bookings

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...