Dynamically Filter Calendar View Webpart - JQuery/SPServices

May 24, 2011 at 7:11 PM
Edited May 24, 2011 at 7:13 PM

I'm usually able to resolve my issues just by reading through forums and finding examples or referencing books on my Sarfari account. Usually another developer has faced similar problems so finding solutions is never a problem. This has been one of my most difficult tasks thus far lol. I am currently the admin/developer/tester/everything for my SharePoint environment so I'm usually all over the place. I will be attending a UI/UX developer class in June taught by SharePoint Experts, Inc which would probably help me better work through solutions on my own.

I was recently tasked with taking a calendar created by a contractor in cold fusion and using the SharePoint OOTB calendar instead, I just have to bring over all of the functionality "woo hoo". I was able to get the print view and hover event display to work. Just not the filtering!

Im pretty sure I will have to use SPServices to get the actual list data so I can compare it to the events on the calendar. Just not sure how to begin.

I found an article "Using JQuery and SPServices to Display List Items" at http://thatstoday.com/article/1746298/using-jquery-and-spservices-to-display-list-items. Trying to incorporate this into my solution has been quite exhausting.

I've been testing my results in an alert box but keep getting unidentified object or just null values. Since the calendar only shows the time and the event title, it's hard to compare it to the actual list. The href for the event has an ID "dispform.aspx?id=xx".

If I can pull the href value from the <TD class="ms"-cal-monthitem> element, then maybe I can use the ID to filter my calendar.

 If I can do that then I can add an additional class to the element to uniquely identify it and then compare it to the list. From there I should be able to build a filter logic and hide the element based on check boxes. I would also be able to color code each event based on the location.

This is an example of the filtering option created in CEWP

 


Events By Category: <select> <option selected="selected" value="all">All Regions/CCs</option> <option value="bangor">Bangor</option> <option value="charleston">Charleston</option> <option value="columbia">Columbia</option> <option value="hanover">Hanover</option> <option value="huntsville">Huntsville</option> <option value="ne">NE</option> <option value="nym">NYM</option> <option value="philly">Philly Tri-State</option> <option value="rochester">Rochester</option> <option value="upny">UPNY</option> <option value="wallingford">Wallingford</option> <option value="wbv">WBV</option> <option value="wilmington">Wilmington</option></select>

Coordinator
May 24, 2011 at 7:17 PM
Edited May 24, 2011 at 7:28 PM

What's the goal of the filtering? Can you explain it in business requirements?

Also, is this SharePoint 2007 or 2010?

M.

May 24, 2011 at 7:29 PM

I am trying to help with this as well.  Basically the business need is this:

Have a selection of Checkbox Filters that when selected will refresh the calendar and just show the selected events based off the checkbox filters.

Hope that makes sense.

Coordinator
May 24, 2011 at 7:32 PM

What in the events do you want to filter against? Just the region?

This may be much easier by simply using different views. You only seem to have 13 regions, so it could be 13 views. Attach the the change event for the select and simply redirect to the proper view, or a single view with filtering on it.

M.

May 24, 2011 at 7:35 PM

This is SharePoint 2007.

Goal:

Above the calendar we have a set of check boxes for Location and a set for the Event Categories.  When the end user selects one or more options I would like to hide the <td> elements in the calendar that are not selected.  We have 13 Regions and 10 different categories and the end user will have to option to select multiple values.

May 24, 2011 at 7:41 PM

I considered using views but with 26 multiple options a ton of views would have to be created.  If I filtered by hiding the <TD> element the page would not have to refresh.  I was also hoping to use the same method to color code the events based on the location as well.

Coordinator
May 24, 2011 at 7:42 PM

Are you displaying the region in each event? If not, you can use GetListItems to retrieve the events for the region and then hide the events which aren't in that region.

I'd hide all events with one jQuery selector, and then light up the ones that should be visible in an each loop in the completefunc for GetListItems.

M.

Coordinator
May 24, 2011 at 7:51 PM

Here's the "hide all" jQuery:

$("td.ms-cal-monthitem a").css("display", "none");

M.

May 24, 2011 at 7:54 PM

The calendar view web part is only displaying the Start Time and Event title.  All details are displayed to the right of the calendar when the user hovers over the event.  I would love to use GetListItems to retreive the events but that's where I'm stuck.  Since the calendar view web part only displays the title and time I have nothing to connect the event to the correct item in the actual calendar list.  I was hoping to extract the href from the <TD.ms-cal-monthitem> element and use the ID.

May 24, 2011 at 7:58 PM

Can you provide the correct script I would need to retrieve the events using GetListItems and also the each loop in the completefunc?  I'm farely new at using JQuery and I'm having a hard time figuring it out.

Coordinator
May 24, 2011 at 8:01 PM

Now what fun would it be if I gave you the full answer? :-)

Each event in a monthly calendar in SharePoint 2007 has this markup in the DOM:

<td class="ms-cal-monthitem">
<a tabindex="2" target="_self" onclick="GoToLink(this);return false;" href="/Intranet/JQueryLib/Lists/Calendar/DispForm.aspx?ID=3.0.2011-05-01T12:00:00Z" onfocus="OnLink(this)"> <nobr><b>8:00 AM</b></nobr><br>
test
</a> </td>

As you can see, the ID is available in the link to the DispForm page. When you call GetListItems, use a CAMLquery that filters for only items in that region, then look through all of the events in the calendar to see if they are in the results.

M.

May 24, 2011 at 8:16 PM

LOL.  The full answer would be a blast !  haha.

So I'm guessing the GetListItems will have to be triggered by a click event from the filters?  I will put something together test it and post back the result and the actual script.

Coordinator
May 24, 2011 at 8:52 PM

BTW, I can't give you the full solution, anyway, as I don't have your exact setup.

There a *lots* of examples of calling GetListItems with SPServices in these discussion threads, and of course there's one on the doc page: http://spservices.codeplex.com/wikipage?title=GetListItems&referringTitle=Lists

M.

May 24, 2011 at 9:59 PM

Okay, well I appreciate you taking your time to help me out.  It's nice to have this kind of support in the SharePoint community.  I am %110 sure that I will be using the discussion threads lol.

  • First I'm creating selectors to find the value of the checked filtered items.
  • Second I am using U2U CAML Query Builder to create a CAML query "as I have no experience with CAML :-)"  But U2U seems to be pretty simple.
  • Third I will call the GetListItems using the CAML query.
  • After this I will attempt to retrieve the list ID's and the ID's from the DispForm aspx page.

I'm currently attempting to test out the GetListItems example on the doc page but it doesn't work.

  $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "HR Kalendar",
    CAMLViewFields: "<ViewFields><FieldRef Name='Event Title' /></ViewFields>",
    completefunc: function (xData, Status) {
      $(xData.responseXML).find("[nodeName='z:row']").each(function() {
        var liHtml = "<li>" + $(this).attr("ows_Title") + "</li>";
        $("#tasksUL").append(liHtml);
      });
    }
  });

Could it be the ows_Title attribute?  I changed it to ows_Event Title and that did not work either.  Am I missing something?  I was hoping to see a list of the event titles.  I'm using jquery 1.5.2 and SPServices 0.6.1.

Coordinator
May 25, 2011 at 1:09 AM

I would skip the CAMLViewFields until you get it running. The StaticName of the Title column in a Calendar list is indeed Title.

The next issue is that you probably don't have a container with the id="tasksUL" (though you may: trying to kill two birds).

A good way to be sure that you are getting valid results is to alert the resulting XML (bird 3).

<script language="javascript" type="text/javascript">
  $(document).ready(function() {
    $().SPServices({
      operation: "GetListItems",
      async: false,
      listName: "HR Kalendar",
      //CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",
      completefunc: function (xData, Status) {
alert(xData.responseText); $(xData.responseXML).find("[nodeName='z:row']").each(function() { var liHtml = "<li>" + $(this).attr("ows_Title") + "</li>"; $("#tasksUL").append(liHtml); }); } }); }); </script> <div id="tasksUL"></div>

M.


Hopefully that will get you to the next level.

May 25, 2011 at 1:17 AM

Can you try this instead?  Open up your favorite browser dev tools and start the debug mode.  Then run this modified script:

 $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "HR Kalendar",
    CAMLViewFields: "<ViewFields><FieldRef Name='Event Title' /></ViewFields>",
    completefunc: function(xData, Status) {
console.log("Status: " + Status);
console.log("xData: " + xData.responseXML.xml);
    }
  });
You will get output in the console and possibly your error.  Most of the time Status is success even though it has failed.  It's always best to look at the xData since that's really what's happening between you and SP.

May 27, 2011 at 6:16 PM

Happy Friday Gentlemen!!

Marc-  Before I had my code directly under the Main ContentPlaceHolder with the DIV id="taskUL" placed in a Content Web Editor.  I was getting no results.

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">

<script type="text/javascript" language="javascript" src="../../Style Library/jquery_library/jquery-1.5.2.min.js"></script>
<script type="text/javascript" language="javascript" src="../../Style Library/jquery_library/jquery.SPServices-0.6.1.min.js"></script>
<script language="javascript" type="text/javascript">

  $(document).ready(function() {
    $().SPServices({
      operation: "GetListItems",
      async: false,
      listName: "HR Kalendar",
      //CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",
      completefunc: function (xData, Status) {
        alert(xData.responseText);
        $(xData.responseXML).find("[nodeName='z:row']").each(function() {
          var liHtml = "<li>" + $(this).attr("ows_Title") + "</li>";
          $("#tasksUL").append(liHtml);
        });
      }
    });  });
</script>


I tried placing the code into same Content Web Editor with the DIV and I got an alert with the XML results (see below).  But the results did not append to the DIV.

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/"><GetListItemsResult><listitems xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'

     xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'

     xmlns:rs='urn:schemas-microsoft-com:rowset'

     xmlns:z='#RowsetSchema'>

<rs:data ItemCount="3">

   <z:row ows_Start_x0020_Date='2011-05-20 13:00:00' ows_End_x0020_Date_x002f_Time='2011-05-20 13:00:00' ows_Title='2 Year Test' ows_Locations2='Bangor' ows_Event_x0020_Category=';#2 Year College;#' ows_Region_x002f_CC='Bangor' ows_VZW_x0020_POC_x0020_Name='90;#Stepp, Joshua H' ows_MetaInfo='12;#' ows__ModerationStatus='0' ows__Level='1' ows_ID='12' ows_owshiddenversion='4' ows_UniqueId='12;#{87F2BD63-776B-4C25-943B-253259711BA0}' ows_FSObjType='12;#0' ows_Created='2011-05-21 12:25:53' ows_FileRef='12;#custcare/hrevents/Lists/HR Kalendar/12_.000' />

   <z:row ows_Start_x0020_Date='2011-05-21 13:00:00' ows_End_x0020_Date_x002f_Time='2011-05-21 13:00:00' ows_Title='4 Year College Test' ows_Locations2='Bangor' ows_VZW_x0020_POC_x0020_Name='90;#Stepp, Joshua H' ows_MetaInfo='13;#' ows__ModerationStatus='0' ows__Level='1' ows_ID='13' ows_owshiddenversion='2' ows_UniqueId='13;#{5E0E1DC5-83E8-4192-AA72-92B8CEE85B6C}' ows_FSObjType='13;#0' ows_Created='2011-05-21 12:26:45' ows_FileRef='13;#custcare/hrevents/Lists/HR Kalendar/13_.000' />

   <z:row ows_Start_x0020_Date='2011-05-20 15:00:00' ows_End_x0020_Date_x002f_Time='2011-05-20 16:00:00' ows_Title='test 15' ows_Locations2='Bangor' ows_VZW_x0020_POC_x0020_Name='90;#Stepp, Joshua H' ows_MetaInfo='14;#' ows__ModerationStatus='0' ows__Level='1' ows_ID='14' ows_owshiddenversion='2' ows_UniqueId='14;#{34DB4BD5-C36E-4CFC-AA85-FA5679247D3C}' ows_FSObjType='14;#0' ows_Created='2011-05-24 11:57:19' ows_FileRef='14;#custcare/hrevents/Lists/HR Kalendar/14_.000' />

</rs:data>

</listitems></GetListItemsResult></GetListItemsResponse></soap:Body></soap:Envelope>
I'm definately getting the correct data but why are the results not appending to the DIV?
May 27, 2011 at 6:28 PM
iOnline247 wrote:

Can you try this instead?  Open up your favorite browser dev tools and start the debug mode.  Then run this modified script:

 

 $().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "HR Kalendar",
    CAMLViewFields: "<ViewFields><FieldRef Name='Event Title' /></ViewFields>",
    completefunc: function(xData, Status) {
console.log("Status: " + Status);
console.log("xData: " + xData.responseXML.xml);
    }
  });
You will get output in the console and possibly your error.  Most of the time Status is success even though it has failed.  It's always best to look at the xData since that's really what's happening between you and SP.

 


iOnline247-- So I tried this as well but had to worst time trying to get the script debugger to work in IE so I went with FireFox which worked well.  The status was Success and the responseText reads the data from the list.  Still worried about the data not appending to the DIV, but I will move on since I'm atleast pulling the data.

I plan on pulling the event category, region, and ID from the XML, and adding them as a class to the matching event on the calendar view web part.  From here I should be able to get the filters working as planned.

Coordinator
May 27, 2011 at 7:13 PM

It might just be a typo, but above I see

DIV id="taskUL"

but

$("#tasksUL").append(liHtml);

They aren't spelled the same!

M.

Jun 28, 2011 at 4:16 PM

Hello Everyone-  Just wanted to post the working script for the filtering.   

  <--------- THIS SECTION FINDS THE DISPFORM.ASPX?ID=XX AND PULLS ONLY THE ID  ---------------->

	$(function () {//-----------FIND THE ALL HREF VALUES CONTAINING "DISPFORM.ASPX"
		var arrayListHrefID = $("a[href*='DispForm.aspx']");
		$.each(arrayListHrefID, function(i,e){
			var h = $(e).attr("href").split("=");//------------GET ONLY THE ID FROM EACH HREF VALUE
			var idRow = h[1];
			parentRow = $(this).parent('td');//----------FIND PARENT <TD> OF THE HREF <A> TAG
			parentRow.attr('id', idRow);//---------ADD HREF ID TO AS ID TAG OF THE <TD>
		});
	
	});

<--------- THIS SECTION PULLS ALL DATA FROM THE SPECIFIED LIST NAME THEN ADDS THE FIELDS USED AS FILTERS ---------------->

   $(function () {//-----------SPSERVICES GET ALL LIST ITEMS FROM HR KALENDAR
   	 $().SPServices({
    	  operation: "GetListItems",
    	  async: false,
    	  listName: "HR Kalendar",
    	  completefunc: function (xData, Status) {       //alert(xData.responseText);
          	   $(xData.responseXML).find("[nodeName='z:row']").each(function() { //--------FIND EACH RECORD FROM HR KALENDAR
     		   	listCategory = $(this).attr("ows_Event_x0020_Category").split(";#").join(" "); //---------REMOVE "semi-colon, pound sign, AND comma" FROM THE MULTIPLE CATGORIES ARRAY
				$("#" + $(this).attr("ows_ID")).addClass($(this).attr("ows_Region_x002f_CC")); //------COMPARE ID FROM LIST DATA TO THE ID WE ADDED TO THE CALENDAR AND ADD REGION AS CLASS TO <TD> OF CALENDAR
				$("#" + $(this).attr("ows_ID")).addClass(listCategory); //------COMPARE ID FROM LIST DATA TO THE ID WE ADDED TO THE CALENDAR AND ADD CATEGORIES AS CLASS TO <TD> OF CALENDAR

      	  });
     	 }
    });  
   });
 
<--------- THIS SECTION LOOPS THROUGH EACH CHECK BOX AND REMOVED UNCHECKED OPTIONS FROM THE CALENDAR ---------------->
$(function() { //---------------- TRIGGERS THE EVENT FILTERS WHEN A CHECKBOX STATE IS CHANGED
	$(":checkbox").change(function() {
	var checkFilters=[];
	var checkFiltersWeekend=[];
	var checkFiltersOther=[];
	
			$(":checkbox:checked").each(function() { //-----------LOOKS THROUGH EACH CHECKBOX
				// save field value and checkstate in variable  
				checkFilters.push(".ms-cal-workitem table tbody tr td."+ $(this).val()); //------------ADDS THE ELEMENT PARENT CHILD RELATIONSHIP + THE CHECKBOX VALUE TO AN ARRAY
				checkFiltersWeekend.push(".ms-cal-noworkitem table tbody tr td."+ $(this).val());
				checkFiltersOther.push(".ms-cal-nodataMid table tbody tr td."+ $(this).val());				
			});
			if(checkFilters==0) { //----------IF STATEMENT TO DETERMINE WHAT SHOULD BE FILTERED
				$(".ms-cal-workitem table tbody tr td").fadeIn()//--------------SHOWS ALL EVENTS WHEN CHECKBOXES ARE NOT CHECKED
				$(".ms-cal-noworkitem table tbody tr td").fadeIn()//--------------SHOWS ALL EVENTS WHEN CHECKBOXES ARE NOT CHECKED
				$(".ms-cal-nodataMid table tbody tr td").fadeIn()//--------------SHOWS ALL EVENTS WHEN CHECKBOXES ARE NOT CHECKED
			} else {
				$(".ms-cal-workitem table tbody tr td").not(checkFilters.join(",")).fadeOut(); //-----------REMOVE EVENTS NOT CHECKED ON WEEKDAY
				$(".ms-cal-noworkitem table tbody tr td").not(checkFiltersWeekend.join(",")).fadeOut(); //-----------REMOVE EVENTS NOT CHECKED ON WEEKENDS
				$(".ms-cal-nodataMid table tbody tr td").not(checkFiltersOther.join(",")).fadeOut(); //-----------REMOVE EVENTS NOT CHECKED ON PREVIOUS AND FOLLOWING MONTHS				
				$(".ms-cal-workitem table tbody tr td").filter(checkFilters.join(",")).fadeIn(); //----------SHOW EVENTS THAT ARE CHECKED ON WEEKDAY
				$(".ms-cal-noworkitem table tbody tr td").filter(checkFiltersWeekend.join(",")).fadeIn(); //----------SHOW EVENTS THAT ARE CHECKED ON WEEKENDS
				$(".ms-cal-nodataMid table tbody tr td").filter(checkFiltersOther.join(",")).fadeIn(); //----------SHOW EVENTS THAT ARE CHECKED ON PREVIOUS AND FOLLOWING MONTHS
			};			
	});
}); 

 <--------- THIS SECTION WILL COLOR CODE YOUR CALENDAR - BY PRE-DEFINED REGION ---------------->
	$(function() { //---------CALENDAR COLOR CODING "REGIONS RED AND CALL CENTERS BLACK"
	//--------- CREATE ARRAYS FOR REGIONS AND CALL CENTERS WITH EACH VALUE
		var colorRegionsRed= [ "philly-tri-state" , "wbv" , "ne" , "nym" , "upny" ]; 
		var colorCentersGrey= [ "bangor" , "charleston" , "columbia" , "hanover" , "huntsville" , "rochester" , "wallingford" , "wilmington" ]
				
		$.each(colorRegionsRed, function(i,e)	{ //--------- FIND EACH REGION AND COLOR THE EVENT ON THE CALENDAR
			var b = $("." + e);
			$(".ms-cal-workitem table tbody tr td."+ e).css({background: "red", width: "130px", opacity: 0.9, borderLeft:"1px white solid", borderRight:"1px white solid"});
			$(".ms-cal-noworkitem table tbody tr td."+ e).css({background: "red", width: "130px", opacity: 0.9, borderLeft:"1px white solid", borderRight:"1px white solid"});
			$(".ms-cal-nodataMid table tbody tr td."+ e).css({background: "red", width: "130px", opacity: 0.9, borderLeft:"1px white solid", borderRight:"1px white solid"});
		});
		
		$.each(colorCentersGrey, function(i,e)	{ //--------- FIND EACH CALL CENTER AND COLOR THE EVENT ON THE CALENDAR
			var b = $("." + e);
			$(".ms-cal-workitem table tbody tr td."+ e).css({background: "black", width: "130px", opacity: 0.7, borderLeft:"1px white solid", borderRight:"1px white solid"});
			$(".ms-cal-noworkitem table tbody tr td."+ e).css({background: "black", width: "130px", opacity: 0.7, borderLeft:"1px white solid", borderRight:"1px white solid"});
			$(".ms-cal-nodataMid table tbody tr td."+ e).css({background: "black", width: "130px", opacity: 0.7, borderLeft:"1px white solid", borderRight:"1px white solid"});
		});

			$("NOBR B").css({color: "white"}); //---------- THIS COLORS THE EVENT TIME WHITE
			$("td.ms-cal-monthitem a").css({color: "white", textDecoration: 'none'}); //----------- THIS COLORS TEH EVENT TITLE WHITE AND REMOVES THE UNDERLINE

	});

Jul 26, 2011 at 4:38 PM
Edited Jul 26, 2011 at 9:04 PM

Hey Marc,

Quick question for you.  Is there a limit to how much data GetListItems will pull back?  My list has 16 test items in it but SPServices is only returning the last 4.  I am not using CAML query at all.  Do you have any suggestions for the below code?  I had to make the Category, Region, and Title fields required so that SPServices returns the data.

 

   $(function () {//-----------SPSERVICES GET ALL LIST ITEMS FROM HR KALENDAR
   	 $().SPServices({
    	  operation: "GetListItems",
    	  async: false,
    	  listName: "HR Kalendar",
    	  completefunc: function (xData, Status) {       //alert(xData.responseText);
          	   $(xData.responseXML).find("[nodeName='z:row']").each(function() { //--------FIND EACH RECORD FROM HR KALENDAR
     		   	listCategory = $(this).attr("ows_Event_x0020_Category").split(";#").join(" "); //---------REMOVE "semi-colon, pound sign, AND comma" FROM THE MULTIPLE CATGORIES ARRAY
				$("#" + $(this).attr("ows_ID")).addClass($(this).attr("ows_Region_x002f_CC")); //------COMPARE ID FROM LIST DATA TO THE ID WE ADDED TO THE CALENDAR AND ADD REGION AS CLASS TO <TD> OF CALENDAR
				$("#" + $(this).attr("ows_ID")).addClass(listCategory); //------COMPARE ID FROM LIST DATA TO THE ID WE ADDED TO THE CALENDAR AND ADD CATEGORIES AS CLASS TO <TD> OF CALENDAR

      	  });
     	 }
    });  
   });
Jul 26, 2011 at 8:54 PM


 

sympmarc wrote:

Generally speaking iOnline's suggestion won't be necessary. However, if you don't specify any CAML options at all, GetListItems uses the default view for the list. That view may or may not return what you think you've asked for. By specifying *something*, you're asking SharePoint to "stop out of" the default view.

M.