• RAHUL MISHRA 78
  • NEWBIE
  • 10 Points
  • Member since 2018

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 0
    Questions
  • 2
    Replies
Hi,

I developed a customizable ligtning calendar component.  It queries event data and then puts the event subjects on the relevant days.  Everything works great, except I can't get my calendar days to align properly.  The days with data in them don't align with the days that don't. I put all code here in case anyone else wants a working lightning calendar

Any ideas?  
 
<!-- Calendar.cmp  -->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" controller="CalendarEvent_CLASS">
    <aura:attribute name="daysOfWeek" type="String[]"/>
    <aura:attribute name="week1" type="String"/>
    <aura:attribute name="month" type="String"/>
    <aura:attribute name="currentMonth" type="Date"/>
    <aura:attribute name="pickList" type="String[]"/>
    <aura:attribute name="selectedDept" type="String" default="Any"/>
    <aura:attribute name="selectedUser" type="String" default="Any"/>
    <aura:attribute name="eventList" type="Event[]"/>
 
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
 
    <div class="slds-grid slds-page-header"   role="banner">  <!-- banner  -->
        
        
        <div class=" slds-size--1-of-12 slds-align--absolute-center"   > <lightning:buttonIcon name="back" alternativeText="Back" iconName="utility:chevronleft" onclick="{!c.lastMonth}"/> </div>
   	    <div class=" slds-size--9-of-12 slds-align--absolute-center"> <b>{!v.month} </b></div>
        <div class=" slds-size--1-of-12 slds-align--absolute-center"  >  <lightning:buttonIcon name="back" alternativeText="Back" iconName="utility:chevronright" onclick="{!c.nextMonth}"/> </div>
        <div class=" slds-size--1-of-12 slds-align--absolute-center"  > 
            
    <lightning:select name="pick" label="Department" onchange="{!c.updateDepartment}" aura:id="pickId">
        <aura:iteration items="{!v.pickList}" var="item">
        <option value="{!item}">{!item}</option>
        
        </aura:iteration>
    
    </lightning:select>
        
        </div>
            
    </div>

	<table class="slds-table slds-table--bordered slds-is-resizable" role="grid">
  		<thead>
   			 <tr class="slds-text-title--caps">
                 <aura:iteration items="{!v.daysOfWeek}" var="day">
                     <th class="slds-cell-shrink" scope="col" style="text-align: center;"><b>{!day}</b> </th>
                 </aura:iteration>
            </tr>
        </thead>
        <tbody>
   {!v.body}
        
        </tbody>
    </table>


    

	
</aura:component>

({
    // Calendar - controller
    
	doInit : function(component, event, helper) {
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth(); //January is 0!
        var yyyy = today.getFullYear();
      // get first day of month
        var today = new Date(yyyy, mm, 1); 
        component.set("v.currentMonth", today);
        var selected = component.get("v.selectedDept");
       helper.retrievePickList(component);
        helper.retrieveEventList(component, mm +1, yyyy, selected);
	},  // end function
    
    
    lastMonth : function(component, event, helper) {
        var currentMonth = component.get('v.currentMonth');
        currentMonth = new Date(currentMonth);
        
        currentMonth = currentMonth.setMonth(currentMonth.getMonth() -1);
        currentMonth = new Date(currentMonth);
        component.set('v.currentMonth', currentMonth);
        var month = currentMonth.getMonth() +1;
        var year = currentMonth.getFullYear() ;
        var selected = component.get("v.selectedDept");
        helper.retrieveEventList(component, month, year);
	},
    
 
    nextMonth : function(component, event, helper) {
        var currentMonth = component.get('v.currentMonth');
        currentMonth = new Date(currentMonth);
        
        currentMonth = currentMonth.setMonth(currentMonth.getMonth() +1);
        currentMonth = new Date(currentMonth);
        component.set('v.currentMonth', currentMonth);
        var month = currentMonth.getMonth() +1;
        var year = currentMonth.getFullYear() ;  
        var selected = component.get("v.selectedDept");
        helper.retrieveEventList(component, month, year);
        
	},


    updateDepartment : function(component, event, helper) {  
        var selected = component.find("pickId").get("v.value");
        component.set('v.selectedDept', selected);
        console.log('result' + selected);
    	var currentMonth = component.get('v.currentMonth');
        currentMonth = new Date(currentMonth);
        var month = currentMonth.getMonth() +1;
        var year = currentMonth.getFullYear() ;
        helper.createCalendar(component);        
    },
    
    
    
})
 
({
    // calendar - helper
    
    retrievePickList : function(component) {
		var action = component.get("c.getDepartments");
       
       // action.setParams({"month": month, "year": year});
        action.setCallback(this, function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                var returned =response.getReturnValue();
                console.log("SUCCESS returned: " + JSON.stringify(returned));
                component.set('v.pickList', returned);
            }
        });
        $A.enqueueAction(action);          
    },
    
    
    retrieveEventList : function(component, month, year) {
		var action = component.get("c.getEventList");
        action.setParams({"month": month, "year": year});
        action.setCallback(this, function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                var returned =response.getReturnValue();
                component.set('v.eventList', returned);
                // console.log("SUCCESS returned: " + JSON.stringify(returned));
                var that = this;
                that.createCalendar(component);

            }
        });
        $A.enqueueAction(action);          
    },
    
    
    
	createCalendar : function(component) {
        var eventList = component.get('v.eventList');
        var today = component.get('v.currentMonth');
        var selectedDept = component.get('v.selectedDept');
		
        //these are labels for the days of the week
        var cal_days_labels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];    
        component.set('v.daysOfWeek', cal_days_labels)
        // these are human-readable month name labels, in order
        var cal_months_labels = ['January', 'February', 'March', 'April',
                         'May', 'June', 'July', 'August', 'September',
                         'October', 'November', 'December'];        
		            
        //today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth(); //January is 0!
        var yyyy = today.getFullYear();
        // get first day of month
        var firstDay = new Date(yyyy, mm, 1);
        console.log(' firstday = ' + firstDay);
				
		        
        var startingDay = firstDay.getDay();
        var nextDay = new Date(firstDay);
        component.set('v.month', cal_months_labels[mm] + ' ' + yyyy);       
        console.log(' starting day ' + startingDay);
	    
        // find number of days in month
        var monthLength = new Date(yyyy, mm, 0).getDate() +1;
        console.log (' monthLength ' + monthLength);  
				       
        // compensate for leap year
        if (mm == 2) { // February only!
        	if((yyyy % 4 == 0 && yyyy % 100 != 0) || yyyy % 400 == 0){
          		monthLength = 29;
        }
      }
        
        

 // **********************************************************************88   
    // Array of components to create
    	var newComponents = [];
        
        // put the weeks/table rows in the components array
        for (var i = 0; i < 7; i++) 
        {
			newComponents.push(["aura:html", {
            	"tag": "tr"
      		}]);              
        }
        
        for (var i = 1; i <= startingDay; i++) {
            // put the days rows in the components array
       		 newComponents.push(["c:CalendarDay", {
				"visible": false
        	 }]); 
        }           
  
 // **********************************************************************88 
 // in this section, we loop through the days of the month and create components for each day       
        for (var i = 1; i <= monthLength; i++) {  //
            var stringBody = [];
            var nextDay = nextDay.toISOString().slice(0,10);
            // console.log('nextDay ' +nextDay);
            for(var e = 0;  e < eventList.length; e ++) {
                var eventDate = new Date(eventList[e].StartDateTime);
                var eventDept = eventList[e].Department__c;
                eventDate = eventDate.toISOString().slice(0,10);
                // if the calendar day of the month matches the calendar day of the event, then add the subject of the event to the calendar day compeonet
            	if (eventDate == nextDay) {
                    if (selectedDept == 'Any') {
                    	stringBody.push(eventList[e].Subject);    
                    }
                    else if (eventDept == selectedDept) {
                        stringBody.push(eventList[e].Subject); 
                    }
            	}                
            } // end for 

            // increament day for the date variable
            var nextDay = new Date(nextDay);
            var dateValue = nextDay.getDate() + 1;
            nextDay.setDate(dateValue);
     		
            newComponents.push(["c:CalendarDay", {
				"day": i,
                 "toDoItems": stringBody
        	 }]); 
        }  
        
        for (var i = 1; i <= 5; i++) {
            // put the days rows in the components array
       		 newComponents.push(["c:CalendarDay", {
                 "visible": false
        	 }]); 
        }             
            
 // **********************************************************************88           
 
   $A.createComponents(newComponents,
        function (components, status, errorMessage) {
           if (status === "SUCCESS") {
               var pageBody = component.get("v.body");
               pageBody = [];
               for (var outer = 0; outer < 5; outer ++) {	
                    var tr = components[outer];
                    var trBody = tr.get("v.body");
                    for (var inner = 1; inner < 8; inner ++) {
                        var outerAdj = outer +0;
                    	var adj =  6 + + inner + (7 * outerAdj); 
                        var toDay = components[adj];
                        trBody.push(toDay);
                    }
                    tr.set("v.body", trBody)
                    pageBody.push(tr);
               }

				component.set("v.body", pageBody);
            }  // end success
            else // Report any error
            {
                this.displayToast("Error", "Failed to create list components.");
            }
        } // end callback function
    );     // end create component   
        		
	}
})

<!-- CalendarDay.cmp  -->
<aura:component >
    <aura:attribute name="day" type="String"/>
    <aura:attribute name="visible" type="Boolean" default="true"/>
    <aura:attribute name="toDoItems" type="String[]"/>
    
    <td class = "outline" scope="col" >
       <aura:if isTrue="{!v.visible}">  
        <fieldset class="slds-box slds-theme--default ">
           
            
            
    <table class="subtable" style="vertical-align:top">
  		<thead>
   			 <tr >

                    <th   class="thClass"> {!v.day} </th>

            </tr>
        </thead>
        <tbody>
        	<aura:iteration items="{!v.toDoItems}" var="item">
           		<tr><td >{!item} </td></tr>
               </aura:iteration>
            

        
        </tbody>
    </table>
 

            
        </fieldset>
           </aura:if>
        </td>
	
</aura:component>

/* calendarDay.css  */

.THIS.outline {
    border: solid black 1px;
    float: top;
}

.THIS .thClass {
    vertical-align:top;
    text-align: center;

}

.THIS .subtable {
        vertical-align:top;
    position: relative;
     






}


 
Hi Guys,

We have been trying to achieve similar popover like you can see on Lightning Calendar (See attached). Lightning Design System provides styles for popover but unfortunately there is no functionality to simply plug it in.

We have analysed the Lightning Calendar and we noticed that Salesforce guys used Open Source Aura components (ui:panelManager2, ui:panel) that are not available in the Lightning Experience.

As we would like to stay native and avoid third party libraries such as Boostrap, what would you recommend to tackle this issue and achieve similar popover? Write the Javascript bit from scratch?

Thanks,

Chris

Lightning Calendar - Popover