valor-software / ngx-bootstrap

Fast and reliable Bootstrap widgets in Angular (supports Ivy engine)
https://valor-software.com/ngx-bootstrap
MIT License
5.52k stars 1.69k forks source link

feat(datepicker): add listening to the change of month property #1153

Open Misenooooo opened 7 years ago

Misenooooo commented 7 years ago

Is there a way, how to listen to the change of the month property of datepicker? I need to send a request to the server in order to load a new set of disabled dates. Than I need to disable the dates in datepicker before it loads.

valorkin commented 7 years ago

nice use case description! it will be done

sanjaypraja commented 5 years ago

have any one find solution for month change using next & previous arrow event?

jeffersonluissm commented 4 years ago

Any position on this?

pbaukov commented 4 years ago

Need it really hard :(

goku321 commented 4 years ago

Is it still open? If yes, would like to work on this if that's okay.

daniloff200 commented 4 years ago

@goku321 cool! You can start work on it! I'll assign it to you

pbaukov commented 4 years ago

Any progress here?

MathiasAt commented 4 years ago

Any updates on this topic? Maybe take a look at how it was implemented in this datepicker? https://ng-bootstrap.github.io/#/components/datepicker/api#NgbDatepickerNavigateEvent

mathias3d commented 4 years ago

Any progress on this?

pbaukov commented 4 years ago

Any progress on this?

As for me - I had to switch my datepicker to ng-bootstrap, unfortunately I had no time to wait until it is implemented here...

nitesh-daga commented 4 years ago

IN TEMPLATE

<input [(ngModel)]="modelDate" autocomplete="off" class="form-control" name="date" bsDatepicker [bsConfig]="{dateInputFormat: 'DD/MM/YYYY'}" (onShown)="onOpenCalendar($event)" >

IN COMPONENT

onOpenCalendar(container) {

    container.navigateTo  = (event: any): void => {
      container._store.dispatch(container._actions.navigateStep(event.step));
      console.log(event);
      // you will get step as month -1 or +1 and based on that you can do your stuff
    }; 
  }
banderberg commented 4 years ago

IN TEMPLATE

<input [(ngModel)]="modelDate" autocomplete="off" class="form-control" name="date" bsDatepicker [bsConfig]="{dateInputFormat: 'DD/MM/YYYY'}" (onShown)="onOpenCalendar($event)" >

No, this does not work when the user clicks the month navigation control to move forward (or backward)

banderberg commented 4 years ago

I would very much like to see this implemented as well.

Devoney commented 3 years ago

I solved it by subscribing to its internal store. When the view was changed to another month you will get the date of the view accordingly.

Add this utils class to your project

import { BsDatepickerInlineDirective } from 'ngx-bootstrap/datepicker';
import { BehaviorSubject } from 'rxjs';

interface BsDatePickerStoreView {
  date: Date,
  mode: keyof { 'day', 'month', 'year'}
}

interface BsDatePickerStoreData {
  view:BsDatePickerStoreView
}

export class BsDatePickerUtils
{
  public viewChanged = new BehaviorSubject<Date>(undefined);

  private lastKnownViewDate: Date = undefined;

  constructor(datePicker: BsDatepickerInlineDirective) {
    const store = (datePicker as any)._datepicker.instance._store.source as BehaviorSubject<BsDatePickerStoreData>;
    store.subscribe((data) => {
      const viewMode = data.view.mode;
      const date = data.view.date as Date;
      if (!this.lastKnownViewDate || this.lastKnownViewDate.toDateString() !== date.toDateString()) {
        if (data.view.mode === 'day') {
          this.lastKnownViewDate = date;
          this.viewChanged.next(data.view.date);
        }
      }
    });
  }
}
// Usage example
@Component({
  selector: 'my-component',
  template: `
<div>
  <bs-datepicker-inline #datePicker></<bs-datepicker-inline>
</div>
  `
})
export class MyComponent implements OnInit, AfterViewInit {

  @ViewChild(BsDatepickerInlineDirective) datePicker: BsDatepickerInlineDirective;
  bsDatePickerUtils: BsDatePickerUtils;

  ngAfterViewInit() {
    this.bsDatePickerUtils = new BsDatePickerUtils(this.datePicker);
    this.bsDatePickerUtils.viewChanged.subscribe(date => {
      console.log('Calendar changed: ' + date);
    });
  }
}
mstojevski commented 1 year ago

@Devoney solution is great but It will be triggered on any change event, not only month change event

To only trigger month change event

        const storeSubject = (datePicker as any)._datepicker.instance._store.source as BehaviorSubject<any>;
        storeSubject.subscribe(data => {
            const date = data.view.date as Date;
            if (
                !this.lastKnownViewDate ||
                (this.lastKnownViewDate.getMonth() !== date.getMonth())
            ) {
                if (data.view.mode === 'day') {
                    this.lastKnownViewDate = date;
                    this.viewChangedSubject.next(true);
                }
            }
        });

Edit: Code improvements used lastKnowViewDate

nguyenhmtriet commented 1 year ago

Thanks to @mstojevski & @Devoney solutions which are working for me. But there is an issue that when I want to set one of @Input() which are related to dates that the component will call setConfig() -> this._datepickerRef = this._datepicker .provide({ provide: BsDatepickerConfig, useValue: this._config }) .attach(BsDatepickerInlineContainerComponent) .to(this._elementRef) .show(); will re-create new instance for BsDatePickerInline & also lose all subscriptions which we are having workaround for listening on view state changed.

ngx-bootstrap: v10.2.0

image

image

sachinedward commented 1 year ago

Until the issue is resolved there is another way which worked better for me.

<input (onShown)="onOpenCalendar($event)" bsDaterangepicker [bsConfig]="bsConfig">
interface BsDatePickerStoreView {
  date: Date,
  mode: keyof { 'day', 'month', 'year'}
}
interface BsDatePickerStoreData {
  view:BsDatePickerStoreView
}
export class Component {
  lastKnownViewDate: Date = undefined;

 onOpenCalendar(container) {
    const store = container._store.source as BehaviorSubject<BsDatePickerStoreData>;
    store.subscribe((data) => {
      const date = data.view.date as Date;
      if (!this.lastKnownViewDate || this.lastKnownViewDate.toDateString() !== date.toDateString()) {
        if (data.view.mode === 'day') {
          this.lastKnownViewDate = date;
          console.log(data, date);
          // do the on change operations
        }
      }
    });
  }
}