function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
George Galaios 12George Galaios 12 

LWC - Listener for changes of a property with multiple attributes

I am new to Javascript and LWC so this question might be very easy! But i can't find a way to implement it... For the time being, i have a listener that when a value of a variable changes, it handles the change. Now, i want to take it one step further... I want to put 2 more properties to this variable and have it to the listener. Is this possible ?? A code snippet until now:
 
/*
@ggalaios 07/04/2020 
*/

import { LightningElement, wire, track, api } from "lwc";
import { loadScript, loadStyle } from "lightning/platformResourceLoader"; //In order for fullCalendar to be displayed
import FullCalendarJS from "@salesforce/resourceUrl/FullCalendarJS"; //import the static Resource!
import { NavigationMixin } from "lightning/navigation"; //Import this in order to be able to pop-up the New Event Screen
import { encodeDefaultFieldValues } from "lightning/pageReferenceUtils";
import getMyEvents from "@salesforce/apex/fullCalendarController.getEventsForCurrentUser"; //in order to call fullCalendarController Apex Class
import { RecordFieldDataType } from "lightning/uiRecordApi";

export default class FullCalendarJs extends NavigationMixin(LightningElement) {
  @wire(getMyEvents) myEvents; //@wire is used to call automatically the Apex method!
  @track eventsList = [];
  currentEvent;
  @track eventView = {
    value: "timeGridWeek"
  };

  connectedCallback() {
    var targetProxy = new Proxy(this.eventView, {
      set: (target, key, value) => {
        alert(`${key} set to ${value}`);
        target[key] = value;
        const viewChangeEvent = new CustomEvent("viewchange", {
          detail: { data: target[key] }
        });
        // Fire the custom event
        this.dispatchEvent(viewChangeEvent);
        return true;
      }
    });
    this.eventView = targetProxy;
  }
}


Now i want to make it somehow like this:
 
@track eventView = {
    value: "timeGridWeek",
    startDate: "08/04/2020",
    endDate: "15/04/2020"
  };

How could i implement my listener since it has just three inputs? (Target, key, value.) Is it possible to add more arguments? Also, how could i modify my listener method? Thanks!
David Zhu 🔥David Zhu 🔥
I will create a child component containing three fields in eventView property. In the child component, an event is fired when any of the fields changing value. In the parent componet, a method is to handle the value changes.
 
George Galaios 12George Galaios 12
I solved the issue by adding 3 more variables. I post my code so that maybe someone could be helped in the future:
 
/*
@ggalaios 07/04/2020 
Lightning Web Component to Implement fullCalendar.io solution
This LWC will be contained in an Aura Component that will have a map with the respective Locations
*/

import { LightningElement, wire, track } from "lwc";
import { loadScript, loadStyle } from "lightning/platformResourceLoader"; //In order for fullCalendar to be displayed
import FullCalendarJS from "@salesforce/resourceUrl/FullCalendarJS"; //import the static Resource!
import { NavigationMixin } from "lightning/navigation"; //Import this in order to be able to pop-up the New Event Screen
import getEventsForDateRange from "@salesforce/apex/fullCalendarController.getEventsForDateRange"; //in order to call fullCalendarController Apex Class
import getlocale from "@salesforce/apex/fullCalendarController.getUserLanguage";

export default class FullCalendarJs extends NavigationMixin(LightningElement) {
  //declare trackable variables eventView, startDate, endDate to send to Parent Component. Counter will be responsible for not firing event on page load!
  @track eventView = {
    value: "timeGridWeek"
  };
  @track startDate = {
    value: ""
  };
  @track endDate = {
    value: ""
  };
  @track counter = {
    value: 0
  };
  @track error;
  //declare wire in order to call the Apex method imperatively!
  @wire(getEventsForDateRange, {
    fromDate: `$startDate.value`,
    endDate: `$endDate.value`
  })
  getEventsForDateRange;
  @wire(getlocale) locale;
  // Listeners... When one of the values changes, it means user has clicked a button... handle the change and fire the event
  connectedCallback() {
    var targetCounter = new Proxy(this.counter, {
      //Counter Listener This variable will cause the event to fire except if it has value 1
      set: (target, key, value) => {
        //alert(`${key} set to ${value}`);
        target[key] = value;
        //if (value != 1) {
        //we don't want on page load to fire the event, that's why if exists
        const viewChangeEvent = new CustomEvent("viewchange", {
          detail: {
            calendarView: this.eventView.value,
            startDate: this.startDate.value,
            endDate: this.endDate.value
          }
        });
        // Fire the custom event
        this.dispatchEvent(viewChangeEvent);
        //}
        return true;
      }
    });
    this.counter = targetCounter;

    var targetProxy = new Proxy(this.eventView, {
      //Listener for event view
      set: function (target, key, value) {
        //alert(`${key} set to ${value}`);
        target[key] = value;
        return true;
      }
    });
    this.eventView = targetProxy;

    var targetStartDate = new Proxy(this.startDate, {
      //Listener for startDate
      set: function (target, key, value) {
        //alert(`${key} set to ${value}`);
        target[key] = value;
        return true;
      }
    });
    this.startDate = targetStartDate;

    var targetEndDate = new Proxy(this.endDate, {
      //Listener for endDate
      set: function (target, key, value) {
        //alert(`${key} set to ${value}`);
        target[key] = value;
        return true;
      }
    });
    this.endDate = targetEndDate;
  }

  //Function to pop-up New Event Standard screen
  createNewEvent() {
    this[NavigationMixin.Navigate]({
      type: "standard__objectPage",
      attributes: {
        objectApiName: "Event",
        actionName: "new"
      },
      state: {
        nooverride: "1"
      }
    });
  }

  renderedCallback() {
    Promise.all([
      // First step: load FullCalendar core
      loadStyle(this, FullCalendarJS + "/packages/core/main.css"),
      loadScript(this, FullCalendarJS + "/packages/core/main.js")
    ])
      .then(() => {
        // Second step: Load the plugins in a new promise
        Promise.all([
          loadStyle(this, FullCalendarJS + "/packages/daygrid/main.css"),
          loadScript(this, FullCalendarJS + "/packages/daygrid/main.js"),
          loadStyle(this, FullCalendarJS + "/packages/timegrid/main.css"),
          loadScript(this, FullCalendarJS + "/packages/timegrid/main.js"),
          loadScript(this, FullCalendarJS + "/packages/interaction/main.js")
        ]).then(() => {
          // Third step: calls your calendar builder once the plugins have been also loaded
          this.initialiseFullCalendar(
            this.eventView,
            this.startDate,
            this.endDate,
            this.counter
          );
        });
      })
      .catch((error) => {
        console.error("error while loading the scripts here: " + error);
      });
  }

  initialiseFullCalendar(eventView, startDate, endDate, counter) {
    console.log(this.locale.data);
    //const eventsData = this.myEvents.data;
    let dataObj = {};
    let events = [];
    const ele = this.template.querySelector("div.fullcalendar");
    //console.log("ele >>> " + ele);
    var calendar = new FullCalendar.Calendar(ele, {
      locales: "locales-all",
      locale: this.locale.data,
      header: {
        left: "prev,next,today",
        center: "title",
        right: "dayGridMonth,timeGridWeek,timeGridDay"
      },
      plugins: [
        "interaction",
        "resourceDayGrid",
        "resourceTimeGrid",
        "dayGrid",
        "timeGrid",
        "timeline",
        "interactionPlugin"
      ],
      events: {},
      defaultView: "timeGridWeek",
      datesRender: function (info) {
        //Triggered when a new set of dates has been rendered.
        eventView.value = info.view.type; //set the new event view to the eventView variable
        startDate.value = info.view.activeStart.toISOString().slice(0, 10); //set the new start date formatted in (YYYY-MM-DD)
        endDate.value = info.view.activeEnd.toISOString().slice(0, 10); //set the new end date formatted in (YYYY-MM-DD)
        counter.value += 1; //Increment the counter by 1, in order to fire the event
        getEventsForDateRange({
          //Call Apex method getEventsForDateRange giving the new set of dates
          fromDate: startDate.value,
          endDate: endDate.value
        })
          .then((result) => {
            //get the results of the events list that should be rendered
            console.log(result);
            var eventSources = calendar.getEventSources();
            var len = eventSources.length;
            //Erase all the existing events in the calendar
            for (var i = 0; i < len; i++) {
              eventSources[i].remove();
            }
            len = result.length;
            dataObj = {};
            events = [];
            //Build again the list of the events that should be displayed
            for (var i = 0; i < len; i++) {
              dataObj.id = result[i].id;
              dataObj.start = result[i].StartDateTime;
              dataObj.end = result[i].EndDateTime;
              dataObj.title = result[i].Subject;
              events.push(dataObj);
              dataObj = {};
            }
            calendar.addEventSource(events); //Render the new events to the Calendar!
          })
          .catch((error) => {
            this.error = error;
            console.log(error);
          });
      }
    });
    calendar.render();
  }
}