PoDuck
PoDuck

Reputation: 1454

How do get the external events for Fullcalendar to work in Angular?

I have been trying to get external events working with Fullcalendar and Angular. I confess that I am new to Angular, and there are some things I obviously don't understand.

Fullcalendar has a page on setting it up with Angular, which is here. I got the main calendar setup in this way, and things were all working excellent until I got to the point that I wanted to drop external events onto the calendar. Apparently there is a Draggable object that needs to be employed, and there is some documentation about how to use it using Typescript, but trying to translate that into working with how they say to set up the calendar has been frustrating me.

Searching for anything showing how to setup draggables for fullcalendar in Angular has only brought up a single code example, which is here. I am having trouble getting their code for the Draggable item working though, given my desire to add it in a new component. This is the bit that seems to be troublesome for me.

new Draggable(this.external.nativeElement, {
  itemSelector: '.fc-event',
  eventData: function(eventEl) {
    return {
      title: eventEl.innerText
    };
  }
});

I have created an external-events component to handle these, but I have tried it in the component I create the calendar in and get exactly the same error. Here is the external-events.component.html:

<div class="external-event-list">
  <div class="fc-event" *ngFor="let job of jobs" data-event="{{job}}" #external>{{job.customer.first_name}} {{job.customer.last_name}}</div>
</div>

Here is the external-events.component.ts:

import {AfterContentInit, Component, ElementRef, OnInit, ViewChildren} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Draggable} from '@fullcalendar/interaction';


@Component({
  selector: 'app-external-events',
  templateUrl: './external-events.component.html',
  styleUrls: ['./external-events.component.css'],
})

export class ExternalEventsComponent implements OnInit, AfterContentInit {
  @ViewChildren('external', {static: true}) external: any;
  jobs: string [];

  constructor(private httpService: HttpClient) {
  }

  ngOnInit(): void {
    this.httpService.get('http://127.0.0.1:7000/api/schedule/unscheduled/?format=json').subscribe(
      (data) => {
        this.jobs = data as string [];
      },
      (err: HttpErrorResponse) => {
        console.log(err.message);
      },
    );
  }

  ngAfterViewInit(): void {
    this.external = new ElementRef('external');
    new Draggable(this.external.nativeElement, {
      itemSelector: '.fc-event',
      eventData: (eventEl) => {
        console.log(eventEl);
        return {
          title: eventEl.innerText,
        };
      },
    });
  }
}

I keep getting the error containerEl.addEventListener is not a function where the Draggable is called. I have no idea where containerEl resides, as it isn't in my code anywhere. I am assuming it is part of the fullcalendar code. My guess is that it is trying to attach a listener to the calendar, but can't find it.

What do I need to do to get the draggable working?

EDIT Here is the stack trace for the error (Line 34 of external-events.component.ts is where I call Draggable):

ERROR TypeError: containerEl.addEventListener is not a function
    at new PointerDragging (main.js:125)
    at new FeaturefulElementDragging (main.js:780)
    at new ExternalDraggable (main.js:2031)
    at ExternalEventsComponent.ngAfterViewInit (external-events.component.ts:34)
    at callHook (core.js:2481)
    at callHooks (core.js:2451)
    at executeInitAndCheckHooks (core.js:2403)
    at refreshView (core.js:9242)
    at refreshComponent (core.js:10324)
    at refreshChildComponents (core.js:8968)
defaultErrorLogger  @   core.js:6006
handleError @   core.js:6054
(anonymous) @   core.js:29191
invoke  @   zone-evergreen.js:364
run @   zone-evergreen.js:123
runOutsideAngular   @   core.js:28195
tick    @   core.js:29191
(anonymous) @   core.js:29070
invoke  @   zone-evergreen.js:364
onInvoke    @   core.js:28267
invoke  @   zone-evergreen.js:363
run @   zone-evergreen.js:123
run @   core.js:28150
next    @   core.js:29069
schedulerFn @   core.js:25632
__tryOrUnsub    @   Subscriber.js:183
next    @   Subscriber.js:122
_next   @   Subscriber.js:72
next    @   Subscriber.js:49
next    @   Subject.js:39
emit    @   core.js:25622
checkStable @   core.js:28203
onHasTask   @   core.js:28281
hasTask @   zone-evergreen.js:419
_updateTaskCount    @   zone-evergreen.js:440
_updateTaskCount    @   zone-evergreen.js:263
runTask @   zone-evergreen.js:184
drainMicroTaskQueue @   zone-evergreen.js:569
Promise.then (async)        
scheduleMicroTask   @   zone-evergreen.js:552
scheduleTask    @   zone-evergreen.js:388
scheduleTask    @   zone-evergreen.js:210
scheduleMicroTask   @   zone-evergreen.js:230
scheduleResolveOrReject @   zone-evergreen.js:847
then    @   zone-evergreen.js:979
bootstrapModule @   core.js:28855
zUnb    @   main.ts:11
__webpack_require__ @   bootstrap:79
0   @   scheduler.component.ts:18
__webpack_require__ @   bootstrap:79
checkDeferredModules    @   bootstrap:45
webpackJsonpCallback    @   bootstrap:32
(anonymous) @   main.js:1

Upvotes: 1

Views: 899

Answers (1)

PoDuck
PoDuck

Reputation: 1454

Okay, I figured it out. I was doing a few things wrong.

First, I put the property decorator on the wrong element in the HTML template. #element should have been on the parent div. Like this:

<div class="external-event-list" #external>
  <div class="fc-event" *ngFor="let job of jobs" data-event="{{job}}">{{job.customer.first_name}} {{job.customer.last_name}}</div>
</div>

I was thinking that Draggable was wanting access to each draggable item, but it really wanted the parent item, and it finds the draggables inside that container with the .fc-event selector.

Here is the external events component for anyone having trouble with this in the future:

import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Draggable} from '@fullcalendar/interaction';


@Component({
  selector: 'app-external-events',
  templateUrl: './external-events.component.html',
  styleUrls: ['./external-events.component.css'],
})

export class ExternalEventsComponent implements OnInit, AfterViewInit {
  @ViewChild('external') external: ElementRef;
  jobs: string [];

  constructor(private httpService: HttpClient) {
  }

  ngOnInit(): void {
    this.httpService.get('http://127.0.0.1:7000/api/schedule/unscheduled/?format=json').subscribe(
      (data) => {
        this.jobs = data as string [];
      },
      (err: HttpErrorResponse) => {
        console.log(err.message);
      },
    );
  }

  ngAfterViewInit(): void {
    new Draggable(this.external.nativeElement, {
      itemSelector: '.fc-event',
      eventData: (eventEl) => {
        return {
          title: eventEl.innerText,
        };
      },
    });
  }
}

Upvotes: 2

Related Questions