nekken / ng2-fullcalendar

95 stars 47 forks source link

eventClick/ dayClick that trigger EventEmitter object #2

Closed Clemouuche closed 7 years ago

Clemouuche commented 8 years ago

Hello guys,

As you've written into the doc, I created a new component that has '<angular2-fullcalendar [options]="calendarOptions">' in the template.

Then I put my calendarOptions during the ngAfterViewInit(). My events display well. Now, I added '@Output('change') valueChange: EventEmitter = new EventEmitter();' into my component because when eventClick or dayClick are triggered, I want to do a this.valueChange.emit({value: this.eventOut}). (because after that, I want to do a this.nav.push or something from my current page)

But unfortunately, it says "cannot read emit of undefined". Maybe I'm wrong but what I understand is that this method is not called from my component but into $('angular2-fullcalendar') so that it can't find my valueChange variable.

Now, my question is "What is the best practice to do it correctly ?".

nekken commented 8 years ago

hi Clemouuche, can you put the code of your component so I can better suggest the best practice?

Clemouuche commented 8 years ago

Just to know, I'm using ionic2

`import { Component, Input, Output, NgZone, EventEmitter } from '@angular/core'; import { NavController } from 'ionic-angular' import {Observable} from 'rxjs/Rx'; import * as moment from 'moment';

import { DataService } from '../../providers/data-service'; import { Local } from '../../providers/local' import { DispoAddPage } from '../../pages/dispo-add/dispo-add';

/* Generated class for the FullCalendar component.

See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html for more info on Angular 2 Components. */ @Component({ selector: 'full-calendar', templateUrl: 'full-calendar.html' }) export class FullCalendarComponent { @Input('idCoach') idCoach: any; @Output('change') valueChange: EventEmitter = new EventEmitter(); eventOut: any;

events: any = []
calendarOptions:any = {};
  constructor(
      private cache: DataService,
      private local: Local,
      private zone: NgZone,
      private nav: NavController
  ) {}
  ngAfterViewInit() {
      this.calendarOptions = {
          height: 'parent',
        contentHeight: 'auto',
        local: 'fr',
          fixedWeekCount : false,
          defaultDate: moment().format('YYYY-MM-DD'),
          editable: true,
          eventLimit: false, // allow "more" link when too many events
        defaultView: 'agendaWeek',
        allDaySlot: false,
        slotLabelFormat: 'HH:mm',
        minTime: '06:00:00',
        maxTime: '23:00:00',
        header: {
        left: '',
        center: 'prev, title, next',
        right: ''
            },
          events: [],
        eventClick: function(event, jsEvent, view ) {
            //console.log('coucou ;) '+moment(event.start).format('YYYY-MM DD HH:mm:ss'))
            //this.eventOut = event
            //this.eventOut.type = 'update'
        },
        dayClick: this.clickday,
        };

      this.getCoachDispo()
  }

  ngOnInit(): void {

  }

  getCoachDispo(): void {
      this.local.get('userInfos').then((res) => {

          this.idCoach = JSON.parse(res).id
          var observable = this.cache.load('events', {
            'filter[id_customer]': this.idCoach,
            'filter[nb_days]': '30',
            'filter[deleted]': '0',
            'display': 'full'
        })

        observable.subscribe(
            res => {
                this.fetchDispo2(res.events)
                //console.log(JSON.stringify(res))
            },
            err => {
                //this.log.error('ca189ead3e783f3cc87ae611a7d001a1', 'GET /events coach page', err)
            })

      })

}

fetchDispo2(events): any {

    var dispo = events
    events.forEach(
        (elem, i) => {
            if (elem.deleted == 0) {
                dispo[i].start = elem.start_date
                dispo[i].end = elem.end_date
                delete dispo[i].start_date
                delete dispo[i].end_date
                dispo[i].title = ""
            }
            if (elem.status == "available") {
                dispo[i].color = '#00B888'
            }
            if (elem.status == "ok") {
                dispo[i].color = '#e74c3c'
            }
            if (elem.status == "pending") {
                dispo[i].color = '#f39c12'
            }
        }
    )
    this.zone.run(
        () => {
            this.calendarOptions.events = dispo
            //console.log(JSON.stringify(this.calendarOptions.events, null, 2))
        }
    )
}

clickday(date, jsEvent, view): void {

        console.log('hé '+JSON.stringify(date))
        this.eventOut = {}
        this.eventOut.type = 'new'
        this.eventOut.date = date
        //this.valueChange = new EventEmitter()
        if (this.valueChange) {
            console.log('defined')
            this.valueChange.emit({
              value: this.eventOut
          })
        }
        else {
            console.log('undefined')
            this.valueChange = new EventEmitter()
            this.valueChange.emit({
              value: this.eventOut
          })
        }
        console.log('eventOut : '+JSON.stringify(this.eventOut))
    }

} `

nekken commented 8 years ago

Hi Clemouuche,

the problem is not related to the component itself, but the scoping inside your clickday function.

in your fullCalendar class, try the following:

dayClick: this.clickday.bind(this),

OR

dayClick: (date, jsEvent, view) => this.clickDay(date, jsEvent, view),

then you should be able to output the event to your parent component

More info at: http://stackoverflow.com/questions/20627138/typescript-this-scoping-issue-when-called-in-jquery-callback

Note that you don't need to check if valueChange is defined or not anymore, since you already initiated it on variable declaration

@Output() valueChange: EventEmitter<any> = new EventEmitter();

hope this helps

alyssa19 commented 7 years ago

Hi @nekken ,

good day!

I'm having a problem to show those event from database. When I hard coded those event it works but when I'm calling it from API it doesn't work.

here's my code

showEvent(){
     this._event_service.getEventList()
     .subscribe(
        data => {
        this.events = Array.from(data);
        this.calendarOptions['events'] = this.events;
        console.log(this.calendarOptions['events']);
          let event = this.events.length;
           for (var i = 0; i < event; i++) {
             this.events[i].title;
               console.log(this.events[i].title);
            }           
        },
        err => this.catchError(err)

    );
  }

 ngOnInit() {
    this.showEvent();
 }

I hope you can help me with this one, I am very new in Angular 2

jayendranshan commented 7 years ago

@alyssa19 the response object from the server should have property id, title and start, then only it will bind properly and then you can have other properties inthe object but those 3 are must.

woodm1 commented 7 years ago

@alyssa19 did you manage to get this to work? I'm having the same issue. Can't get it to display API data from an observable at all.

hnitzsche commented 7 years ago

@alyssa19 @woodm1 any news on this? Is it possible to display API data from an observable with fullcalendar at all or am I wasting time?

woodm1 commented 7 years ago

If you're having problems getting it to display the data from an observable, have a look at https://github.com/akveo/ng2-admin/issues/331

I got it to work & there's an example in there