1,804 articles and 14,735 comments as of Saturday, April 2nd, 2011

EndUserSharePoint has combined resources with NothingButSharePoint.com. You can now find End User (Mark Miller), Developer (Jeremy Thake) and IT Pro SharePoint (Joel Oleson) content all in one place!

This site is a historical archive and is no longer being updated. Please update your favorites, bookmarks and RSS feeds.

NothingButSharePoint.com
Wednesday, March 4, 2009

JQuery for Everyone: $.grep and calcHTML Revisited

Every once in a while, good scripts need a second look. The calcHTML idea popularized by Christophe has such potential for frequent use, I decided to see if I can improve on my previous work (link).

First, I noticed that I created an unnecessary extension of jQuery with “$.calcHTML = function()…” I stopped that practice. Second, I noticed that the filter, “.filter(”:contains(<DIV)”)…” did not really find HTML in need of rendering, it found the beginnings of DIV tags.

In this updated version (tested with jQuery 1.3.1 in IE7 and FF3 with preview pane or grouping and in List View or Form), I wanted to cast a wide net to find HTML that needed rendering. To do that, I started by creating my array of elements just like before. Then I filtered the array using $.grep. The grep utility in jQuery, like the Unix function, finds things quickly in large data sets.

Of the original arrayList, I only returned items with text matching the regular expression “/<[^<]+?>/” back into arrayList. That one line of code does a lot but runs very quickly. Overall, this current script runs on my test page in 36ms (about 10ms slower than Christophe’s POJ version) — but because this script casts a wider net, we have more flexibility in our calculated columns.

For instance, instead of wrapping a link tag in a DIV, I can just use the formula:

="<a href='"&[url_field]&"'>"&[Title]&"</a>"
<script type="text/javascript">
if(typeof jQuery=="undefined"){
	var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/";
	document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>");
}
</script>
<script type="text/javascript">
function calcHTML() {
/*
Add or replace the following selectors to the arrayList variable
New groups are added by comma:
Example: var arrayList = $("td.ms-vb,td.ms-vb2");

td.ms-vb 			= Data View Web Part
td.ms-vb2 			= List View Web Part
td[id='SPFieldCalculated']	= Standard Form Calc Column
td.ms-stylebody			= Boxed View Styles
td.ms-formbody			= Standard Form
td.ms-cal-monthitem a		= Calendar Month
table.ms-cal-tweekitem a	= Calendar Week
*/
    var arrayList = $("td.ms-vb2");
 	arrayList = $.grep(arrayList, function(e,i){
		return ($(e).text().match(/&lt\;.+?&gt\;|<.+?>/));
	});
	$.each(arrayList, function(i,e){
		$(e).html($(e).text().replace(/&lt;(.+?)&gt;/g,'<$1>'));
    });
}
function ExpGroupRenderData(htmlToRender, groupName, isLoaded) {
    $("#tbod"+groupName+"_").attr("isloaded",isLoaded).html(htmlToRender).show("fast",calcHTML());
}
$(function() {
    calcHTML();
    if (typeof showpreview1=='undefined') {
		return;
	}else{
        $("td.ms-vb-title").bind("mouseover", function(){
            showpreview1(this);
            calcHTML();
        });
    }
});
</script>

Second version (tested cross-browser with many different views of data):

<script type="text/javascript">
if(typeof jQuery=="undefined"){
	var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/";
	document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>");
}
</script>
<script type="text/javascript">
function calcHTML() {
	var arrayList = $("table.ms-listviewtable").find("td")
		.add("td.ms-vb")
		.add("td[id='SPFieldCalculated']")
		.add("td.ms-stylebody")
		.add("td.ms-formbody")
		.add("td.ms-cal-monthitem a")
		.add("td.ms-cal-defaultbgcolor a")
		.add("table.ms-cal-tweekitem a")
		;//comment out unused lines above for better performance
	arrayList = $.grep(arrayList, function(e,i){
		return ($(e).text().match(/&lt\;.+?&gt\;|<.+?>/));
	});
	$.each(arrayList, function(i,e){
		$(e).html($(e).text().replace(/&lt;(.+?)&gt;/g,'<$1>'));
    });
}
function ExpGroupRenderData(htmlToRender, groupName, isLoaded) {
    $("#tbod"+groupName+"_").attr("isloaded",isLoaded).html(htmlToRender).show("fast",calcHTML());
}
$(function() {
    calcHTML();
    if (typeof showpreview1=='undefined') {
		return;
	}else{
        $("td.ms-vb-title").bind("mouseover", function(){
            showpreview1(this);
            calcHTML();
        });
    }
});
</script>

Update: 2009-03-04

I updated the selector to include the title link on calendar views.

Update: 2009-03-05

I updated the selector to include the cells of a Data View Web Part and the current day of a calendar web part.

Update: 2009-03-05

On second thought. All of the additional selectors for every various possibility started to slow things down. I did adjust the regular expressions to replace HTML-encoded data but I’ll have to post another article about that and how we might use it.

If you have a case other than the List View Web Part, check the chart for your situation and make the appropriate change to the arrayList selector. If you have a custom theme or custom web part, you may have to do your own searching within the DOM.

Again, this version fits the original intent which was to test on List Views.

The second version will run slower (because it’s looking for more objects) but seems to fit more of the wild variations people create out of an htmlCalc column. To speed up the second version, you can comment out the lines starting with .add that you aren’t using. See version one’s list of known references. If you find new ones, please comment here. Thanks.

Paul Grenier

View all entries in this series: PaulGrenier-JQuery for Everyone»
Entries in this series:
  1. JQuery for Everyone: Accordion Left Nav
  2. JQuery for Everyone: Print (Any) Web Part
  3. JQuery for Everyone: HTML Calculated Column
  4. JQuery for Everyone: Dressing-up Links Pt1
  5. JQuery for Everyone: Dressing-up Links Pt2
  6. JQuery for Everyone: Dressing-up Links Pt3
  7. JQuery for Everyone: Cleaning Windows Pt1
  8. JQuery for Everyone: Cleaning Windows Pt2
  9. JQuery for Everyone: Fixing the Gantt View
  10. JQuery for Everyone: Dynamically Sizing Excel Web Parts
  11. JQuery for Everyone: Manually Resizing Web Parts
  12. JQuery for Everyone: Total Calculated Columns
  13. JQuery for Everyone: Total of Time Differences
  14. JQuery for Everyone: Fixing Configured Web Part Height
  15. JQuery for Everyone: Expand/Collapse All Groups
  16. JQuery for Everyone: Preview Pane for Multiple Lists
  17. JQuery for Everyone: Preview Pane for Calendar View
  18. JQuery for Everyone: Degrading Dynamic Script Loader
  19. JQuery for Everyone: Force Checkout
  20. JQuery for Everyone: Replacing [Today]
  21. JQuery for Everyone: Whether They Want It Or Not
  22. JQuery for Everyone: Linking the Attachment Icon
  23. JQuery for Everyone: Aspect-Oriented Programming with jQuery
  24. JQuery for Everyone: AOP in Action - loadTip Gone Wild
  25. JQuery for Everyone: Wiki Outbound Links
  26. JQuery for Everyone: Collapse Text in List View
  27. JQuery for Everyone: AOP in Action - Clone List Header
  28. JQuery for Everyone: $.grep and calcHTML Revisited
  29. JQuery for Everyone: Evolution of the Preview
  30. JQuery for Everyone: Create a Client-Side Object Model
  31. JQuery for Everyone: Print (Any) Web Part(s) Plugin
  32. JQuery for Everyone: Minimal AOP and Elegant Modularity
  33. JQuery for Everyone: Cookies and Plugins
  34. JQuery for Everyone: Live Events vs. AOP
  35. JQuery for Everyone: Live Preview Pane
  36. JQuery for Everyone: Pre-populate Form Fields
  37. JQuery for Everyone: Get XML List Data with OWSSVR.DLL (RPC)
  38. Use Firebug in IE
  39. JQuery for Everyone: Extending OWS API for Calculated Columns
  40. JQuery for Everyone: Accordion Left-nav with Cookies Speed Test
  41. JQuery for Everyone: Email a List of People with OWS
  42. JQuery for Everyone: Faster than Document.Ready
  43. jQuery for Everyone: Collapse or Prepopulate Form Fields
  44. jQuery for Everyone: Hourly Summary Web Part
  45. jQuery for Everyone: "Read More..." On a Blog Site
  46. jQuery for Everyone: Slick Speed Test
  47. jQuery for Everyone: The SharePoint Game Changer
  48. JQuery For Everyone: Live LoadTip
 

Please Join the Discussion

21 Responses to “JQuery for Everyone: $.grep and calcHTML Revisited”
  1. niax says:

    Great job Paul!
    Now the only thing I miss is this jquery to work with calendar views.
    Well that is not all true I do wish I had some jquery understanding as well, but for now I have to stick with what you guys deliver and I am truly impressed!
    Are you planning on getting this to work for calendar views as well, Paul?

    Thanks a lot!

    /niax

  2. AutoSponge says:

    Thanks for the idea. I updated the script to support calendar views. Let me know how your testing goes.

    ~Paul

  3. Christophe says:

    Coincidence…I was just checking out the grep() function this week. I was not convinced that it would bring any improvement in this case. What is the benefit of grep() here, compared to a standard selector?

  4. Christophe says:

    Paul, I also tested your script in a calendar with an “advanced” use case and it didn’t work. I’ll send you the formula I used.

  5. AutoSponge says:

    @Christophe

    Grep seems to be a very efficient way to reduce an array facing an expensive process.

    By using grep, I was able to remove any logic from my function that applies the DOM manipulation.

    Since DOM manipulation is usually a more expensive operation, I wanted to only process the required records.

    Definitely send me the test case, I had never thought of using calcHTML in a calendar view before last night.

  6. Christophe says:

    In the first link of your post you’ll find all the tutorials related to the HTML calculated column.
    The most frequent request for calendars is color coding, but there are other applications.
    The latest addition is the use of the method to write scripts. The next step in the series will be – as you could expect: “using calculated columns to write jQuery”!

  7. niax says:

    Hi Paul,
    I tried the updated version as well in a calender view, but did not succeed.

    /niax

  8. AutoSponge says:

    @niax

    Are you using the default theme/template/css?
    What formula did you use?
    What exactly failed?

  9. AutoSponge says:

    I updated the selector to include cells from a DVWP and current month calendar day.

  10. AutoSponge says:

    Today’s updates come with a lot of testing help from Peter Allen. This should show better results in IE than the previous version.

    For some reason, IE only found 77 of the 112 elements on the test page so I had to alter the selector method to use .add. I didn’t notice any speed difference so I left both versions in this post.

    If you’re not sure which one to use, start with version 2.

    Thanks,
    Paul

  11. Christophe says:

    Version 2 worked for my test.

  12. Christophe says:

    btw the first version has a dummy jQPath, I was wondering if you did this on purpose.

  13. AutoSponge says:

    @Christophe

    Thanks for catching that, I fixed it.

  14. niax says:

    Sorry for my late response, Paul!
    I tested the second version as well, and it worked quite well, thank you!
    On that page I also had PlanetWilsons Coulor Calendar, and it stoped working, if any one is intrested to know. I didn’t dig any further in the matter to try to work things out.

  15. Detlef says:

    I am trying to combine both your calcHTML() and collapseText() so that my Lists can contain blocks and have the ability to collapse and expand large multiline text fields. Since each has their own version of ExpGroupRenderData() I was not able to figure out how to support both in the same script.

  16. AutoSponge says:

    @Detlef,

    I have a few articles coming out this week which might help. One about an abbreviated AOP script which works very nicely and another about jQuery plugins that return /this/ (which allows the chaining of methods).

  17. Vijay says:

    Is there any way to replace the Links in a SharePoint Monthly/Weekly/Daily Calendar View to point to a Custom page?

    For example –

    If there is a Calendar on a SharePoint page the detail page usually is –

    /Lists/MyCalendar/DispForm.aspx?ID=2

    I want to replace this link with something like –

    /pages/EventDetails.aspx?itemid=2

    How to do this with JQuery, your help will be greatly appreciated. Thanks!

  18. Charlie Epes says:

    Hi Paul:
    I have a squirrely formula that wraps up minutes (numbers) into a time format:

    =TEXT(TIME(0,Minutes,0),”HH:MM”)

    Thus far, I cannot seem to get any HTML calculated column code to work. And yes, I am grouping by a field called [Month].

    Any ideas?

    Thanks-Charlie Epes
    Buffalo, NY

  19. AutoSponge says:

    @Vijay,

    To do this with jQuery (not sure if that’s the best long term solution), find the links: $(”a[href*='/Lists/MyCalendar/DispForm.aspx?ID=']“), then iterate over the group using $.each(). While you do that, perform a RegEx replace on the href attribute.

    @Charlie,

    That formula does not have any HTML in it, what is it that you need to appear as HTML?

Trackbacks

Check out what others are saying about this post...
  1. [...] SharePoint bloggers. On EndUserSharePoint.com for example, you’ll find Paul Grenier’s jQuery version of the script, and a detailed example by Jim Bob Howard: the payroll [...]

  2. [...] example, Paul Grenier proposed a jQuery version of my script, which allows you to grab only certain cells. If HTML Calculated Columns are only in List View [...]




Notify me of comments to this article:


Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!