0

I am finding the following problem with Angular\TypeScript.

I have this class that handle the behavior of my component:

import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { EventService } from '../event.service';
import interactionPlugin, { Draggable } from '@fullcalendar/interaction';

interface WorkShiftTypes {
  name: string;
  value: string;
}

@Component({
  selector: 'app-people-list',
  templateUrl: './people-list.component.html',
  styleUrls: ['./people-list.component.css']
})
export class PeopleListComponent implements OnInit {

  people: any[];

  //cities: City[];

  workShiftTypes: WorkShiftTypes[];
  selectedShift: WorkShiftTypes;

  @ViewChild('draggable_people') draggablePeopleExternalElement: ElementRef;

  constructor(private eventService: EventService) { }

  ngOnInit(): void {
    this.eventService.getPeople().then(people => {this.people = people;});

    this.selectedShift = {name: 'Mattina', value: 'Mattina'};

    this.workShiftTypes = [
      {name: 'Mattina', value: 'Mattina'},
      {name: 'Pomeriggio', value: 'Pomeriggio'},
      {name: 'Notte', value: 'Notte'},
      {name: 'Custom', value: 'Custom'}
    ];
  }

  ngAfterViewInit() {
    console.log("PEOPLE LIST ngAfterViewInit() START !!!")

    new Draggable(this.draggablePeopleExternalElement.nativeElement, {
      itemSelector: '.fc-event',
      eventData: function(eventEl) {
        console.log("DRAG !!!");
        console.log("SELECTED SHIFT: " + this.selectedShift.value);
        return {
          title: eventEl.innerText,
          selectedShift: this.selectedShift.value
        };
      }
    });

  }
}

As you can see in the previous code I have this property:

selectedShift: WorkShiftTypes;

that always contains a value (because I am setting it a default value into the ngOnInit() hook method and because it is bound to a PrimeNG component into my view.

Then I have this ngAfterViewInit() method hook:

ngAfterViewInit() { console.log("PEOPLE LIST ngAfterViewInit() START !!!")

new Draggable(this.draggablePeopleExternalElement.nativeElement, {
  itemSelector: '.fc-event',
  eventData: function(eventEl) {
    console.log("DRAG !!!");
    console.log("SELECTED SHIFT: " + this.selectedShift.value);
    return {
      title: eventEl.innerText,
      selectedShift: this.selectedShift.value
    };
  }
});

Here I am creating a Draggable object in which is defined a callback function for the drag event (I am drag an item from a list and dropped this item into a calendar).

This function first try to print into the console log the value of the previous this.selectedShift class property and them I am trying to use this value to add a field to the returned object, by:

selectedShift: this.selectedShift.value

And on these two operation I have a problem. The code compile without error but trying to perform my application, when I try to drag an item from my list and drop it into my Calendar I obtain the following error message:

core.js:6272 ERROR TypeError: Cannot read property 'value' of undefined
    at ExternalElementDragging.eventData [as suppliedDragMeta] (people-list.component.ts:48)
    at ExternalElementDragging.push../node_modules/@fullcalendar/interaction/main.esm.js.ExternalElementDragging.buildDragMeta (main.esm.js:1916)
    at EmitterMixin.ExternalElementDragging.handleDragStart (main.esm.js:1830)
    at applyAll (main.esm.js:982)
    at EmitterMixin.push../node_modules/@fullcalendar/core/main.esm.js.EmitterMixin.triggerWith (main.esm.js:3576)
    at EmitterMixin.push../node_modules/@fullcalendar/core/main.esm.js.EmitterMixin.trigger (main.esm.js:3571)
    at EmitterMixin.HitDragging.handleDragStart (main.esm.js:991)
    at applyAll (main.esm.js:982)
    at EmitterMixin.push../node_modules/@fullcalendar/core/main.esm.js.EmitterMixin.triggerWith (main.esm.js:3576)
    at EmitterMixin.push../node_modules/@fullcalendar/core/main.esm.js.EmitterMixin.trigger (main.esm.js:3571)

It seems to me that form the inside of the **eventData: function(eventEl) { ...} event handler function it can't access to my this.selectedShift class property (is it because in this specific case the this refers to the Draggable object?). I am pretty sure of this because mooving this line:

console.log("SELECTED SHIFT: " + this.selectedShift.value);

outside of this function (for example as first line of the **ngAfterViewInit() hook function) I retrieve the correct default value set by the ngOnInit() function. So this value is correctly initialized.

Why I can't access to this property from the inside of this function? How can I access to it and fix my error?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
AndreaNobili
  • 40,955
  • 107
  • 324
  • 596
  • Does this answer your question? [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – R. Richards May 20 '20 at 11:33

1 Answers1

1

Its because of the scope of the eventData handler. You are not using an arrow function, so the context of this is binded to the caller.

You might want to use an arrow-function instead (context of arrow-functions are binded to its declartion):

eventData: (eventEl) => {
    console.log("DRAG !!!");
    console.log("SELECTED SHIFT: " + this.selectedShift.value);
    return {
      title: eventEl.innerText,
      selectedShift: this.selectedShift.value
    };
  }

Another way would be to use the bind function:

const handler = function(eventEl) {
        console.log("DRAG !!!");
        console.log("SELECTED SHIFT: " + this.selectedShift.value);
        return {
          title: eventEl.innerText,
          selectedShift: this.selectedShift.value
        };
      }

new Draggable(this.draggablePeopleExternalElement.nativeElement, {
  itemSelector: '.fc-event',
  eventData: handler.bind(this)
});
enno.void
  • 6,242
  • 4
  • 25
  • 42