Showing posts with label how to. Show all posts
Showing posts with label how to. Show all posts

Friday, June 20, 2014

Why I say Data View Plus web part is the best we ever made #1

** UPDATE: try this updated version ** 

KWizCom Data View Plus web part is a simple web part that was built with the designer in mind.

It connects to various data sources, lists, list views, enterprise aggregation feature (more source coming), and does something rather simple.

Unlike the SharePoint data view web part that forces you to work with XSL to transform you data into HTML, the Data View Plus takes a different approach, one that I personally think is much more natural for developers and designers alike.

It works with a list of templates, each template has a simple header, footer and body HTML.

You can simply write the HTML you wish to have at the header and footer of the web part, and the body part will be rendered once for each item in the source.

So, how do you get the values from your data into the HTML? Using simple tokens.

{Item:Title:Value} will render the title field value of the item, you can use this token for any field on the current item.

The list of tokens is long, yet very simple to understand. You can find it in the admin guide of the web part on page 23: Download KWizCom Data View Plus administration guide

So, why do I say it is the best we ever made? Since using it, it took me an hour to make an upcoming birthday’s web part.

I build a new data view plus template called: “Upcoming birthdays”, connected it to my birthdays list and here is the result:

image

Have you ever asked yourself “how do I show upcoming birthdays in SharePoint?” – now you got the answer! Here is a step by step guide on how I did it:

Step 1: Create birthdays list

Create a custom list, use the title to type the person’s name.

Add a choice field called “Month” with options 01, 02…12

Add a choice field called “Day” with options 01, 02… 31

Fill in some birthdays in the list.

Step 2: Install Data View Plus web part

If you haven’t done so already, download and install KWizCom data view plus web part:

http://www.kwizcom.com/sharepoint-add-ons/data-view-plus/download/

Enable the site collection feature and it will create the default template list for you

Step 3: Build the birthdays list template

Visit the “KWizCom Data View Plus Display Layouts” list at your site collection (Not there? Go back to step 2.)

Create a new item in the list with the following data:

(for easy copy, I’ve put this here: http://pastebin.com/ErgixJWv)

1. Title:

Upcoming Birthdays

2. Description:

This shows a simple grouped list with the next 10 weeks of birthdays coming up.
It splits them into groups: Today, tomorrow, this week, or upcoming.

3. EmptyView: (this is the html that will be rendered if no items were found in the source)

<div>There are no upcoming birthdays.</div>

4. Header: (We will use script to transform our data into a birthday list, so the script will go in the header)

   1: <script>
   1:  
   2: KWizCom.DVPWP.Instances['_WPQ_'].Load = function() 
   3: { 
   4:             var numOfWeeksToShow = 10; 
   5:             var monthNames = { 
   6:                 "01": "Jan", 
   7:                 "02": "Feb", 
   8:                 "03": "Mar", 
   9:                 "04": "Apr", 
  10:                 "05": "May", 
  11:                 "06": "Jun", 
  12:                 "07": "Jul", 
  13:                 "08": "Aug", 
  14:                 "09": "Sep", 
  15:                 "010": "Oct", 
  16:                 "011": "Nov", 
  17:                 "012": "Dec", 
  18:             } 
  19:             var groupNames = { 
  20:                 "today": "Today", 
  21:                 "tomorrow": "Tomorrow", 
  22:                 "thisweek": "This week", 
  23:                 "upcoming": "Upcoming" 
  24:             } 
  25:  
  26:             var make2DigitString = function (n) { 
  27:                 return n < 10 ? "0" + n : "" + n; 
  28:             } 
  29:              
  30:             var now = new Date(); 
  31:             var tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000); 
  32:             var nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); 
  33:             var endDate = new Date(now.getTime() + numOfWeeksToShow * 7 * 24 * 60 * 60 * 1000); 
  34:             var $list = $kw("#_WPQ_Birthdays"); 
  35:             var $placeholder = $kw("#_WPQ_BirthdaysPlaceHolder"); 
  36:             var currentYear = now.getFullYear(); 
  37:             var nextYear = currentYear + 1; 
  38:             var currentMonth = now.getMonth() + 1;//it is zero based 
  39:             var currentDay = now.getDate(); 
  40:             var tomorrowMonth = tomorrow.getMonth() + 1; 
  41:             var tomorrowDay = tomorrow.getDate(); 
  42:             var tomorrowYear = tomorrow.getFullYear(); 
  43:             var nextWeekMonth = nextWeek.getMonth() + 1; 
  44:             var nextWeekDay = nextWeek.getDate(); 
  45:             var nextWeekYear = nextWeek.getFullYear(); 
  46:             var endMonth = endDate.getMonth() + 1; 
  47:             var endDay = endDate.getDate(); 
  48:             var endYear = endDate.getFullYear(); 
  49:  
  50:             var todayString = currentYear + "-" + make2DigitString(currentMonth) + "-" + make2DigitString(currentDay); 
  51:             var tomorrowString = tomorrowYear + "-" + make2DigitString(tomorrowMonth) + "-" + make2DigitString(tomorrowDay); 
  52:             var nextWeekString = nextWeekYear + "-" + make2DigitString(nextWeekMonth) + "-" + make2DigitString(nextWeekDay); 
  53:             var endDateString = endYear + "-" + make2DigitString(endMonth) + "-" + make2DigitString(endDay); 
  54:             var birthdaysList = new Array(); 
  55:  
  56:             $list.find("li").each(function () { 
  57:                 try{ 
  58:                     var title = $kw(this).attr("data-title"); 
  59:                     var month = parseInt($kw(this).attr("data-month"),10); 
  60:                     var day = parseInt($kw(this).attr("data-day"),10); 
  61:                     var sortableString = currentYear + "-" + make2DigitString(month) + "-" + make2DigitString(day); 
  62:                     if (sortableString < todayString)//this one passed. move it to next year 
  63:                         sortableString = nextYear + "-" + make2DigitString(month) + "-" + make2DigitString(day); 
  64:                     if( sortableString <= endDateString ) 
  65:                         birthdaysList[birthdaysList.length] = sortableString + ":" + title; 
  66:                 } catch (e) { 
  67:                 } 
  68:             }); 
  69:  
  70:             birthdaysList.sort();//now we got sorted birthdays 
  71:             var titleMode = null; 
  72:             var html = ""; 
  73:             for (var i = 0; i < birthdaysList.length; i++) { 
  74:                 var datePart = birthdaysList[i].split(":")[0]; 
  75:                 var titlePart = birthdaysList[i].split(":")[1]; 
  76:                 var dateArr = datePart.split("-"); 
  77:                 var dateString = monthNames[dateArr[1]] + " " + dateArr[2]; 
  78:  
  79:                 var newGroup = false; 
  80:                 if (todayString == datePart) { 
  81:                     if (titleMode != "today")//add title 
  82:                     { 
  83:                         newGroup = true; 
  84:                         titleMode = "today"; 
  85:                     } 
  86:                 } 
  87:                 else if (tomorrowString == datePart) { 
  88:                     if (titleMode != "tomorrow")//add title 
  89:                     { 
  90:                         newGroup = true; 
  91:                         titleMode = "tomorrow"; 
  92:                     } 
  93:                 } 
  94:                 else if (nextWeekString >= datePart) { 
  95:                     if (titleMode != "thisweek")//add title 
  96:                     { 
  97:                         newGroup = true; 
  98:                         titleMode = "thisweek"; 
  99:                     } 
 100:                 } 
 101:                 else { 
 102:                     if (titleMode != "upcoming")//add title 
 103:                     { 
 104:                         newGroup = true; 
 105:                         titleMode = "upcoming"; 
 106:                     } 
 107:                 } 
 108:  
 109:                 if (newGroup) 
 110:                 { 
 111:                     if (html != "") html += "</div>"; 
 112:                     html += "<h3>"+groupNames[titleMode]+"</h3><div>"; 
 113:                 } 
 114:  
 115:                 html += "<p>" + titlePart + "<span style='float:right'>" + dateString + "</span></p>"; 
 116:             } 
 117:             if (html != "") { 
 118:                 html += "</div>"; 
 119:                 $placeholder.append(html); 
 120:                 //$placeholder.accordion({ 
 121:                 //    heightStyle: "content" 
 122:                 //}); 
 123:             } 
 124:             else { 
 125:                 $kw("#_WPQ_NoBirthdaysPlaceHolder").show(); 
 126:             } 
 127: } 
128: </script>
 129: <div id="_WPQ_BirthdaysPlaceHolder"></div> 
 130: <div id="_WPQ_NoBirthdaysPlaceHolder" style="display:none">No upcoming birthdays.</div> 
 131: <ul id="_WPQ_Birthdays" style="display:none">

5. Body: (This will be rendered for each item)

   1: <li data-title="{item:Title:value}" data-month="{item:Month:value}" data-day="{item:Day:value}"> 
   2: {item:Title:value} - {item:Month:value} - {item:Day:value} 
   3: </li>

6. Footer: (This will be rendered at the end)

   1: </ul>

Notes:

In the header script, you can find at the beginning options to configure the template, like translating the text and how many weeks of birthdays to show.

Step 4: Add the web part to your page

Now, all you got to do is add the data view plus web part to your page, connect to the birthdays list and select the new template you just created, and you are done!

Now, you see how easy it is to modify my template and brand it to what ever your customers are asking for? You got complete control over the HTML, and no need to mess with XSL.

I would love to hear your comments or thoughts, I will try to build a few more templates and share them here. If you got ideas or requests let me know!

Tuesday, July 30, 2013

New to SharePoint?

Want to learn about SharePoint, application development and solutions using this amazing platform?

I always run into people in the IT business who heard about SharePoint but want to know what it’s all about.

I used to answer in emails or private messages but decided it might be a good idea to share some good links to good online learning materials for the autodidacts among us.

Enjoy, and feel free to share and add more in comments!

(Links to other non related sites in comments will not be approved. Links to commercial sites won’t be approved either.)

My favorite, Microsoft’s Channel 9:

http://channel9.msdn.com/Tags/sharepoint

Super quick start on your own development environment, use cloudshare. You get 30 days free trial, and they have lots of templates to start from (incl. SharePoint 2007, 2010 and 2013)

http://www.cloudshare.com

And, if you have the hardware and just want a SharePoint virtual machine image to play with – you can download and install one from here, but you will have to install and configure your dev environment yourself:

http://technet.microsoft.com/en-us/evalcenter/hh973397.aspx

* This product key is good for 180 days, I suggest you take a snapshot of the virtual machine before you activate it to make sure you can restart your trial period. Obviously, this is great for dev but can’t be used for production as you need to revert and reactivate every 180 days.

There used to be a demo Hyper-V machine preinstalled and available from Microsoft.com, but it appears they have removed the link. I will post as soon as I find it.

Of course, you can also enjoy SharePoint online as a part of Office 365. This will allow you to use SharePoint, perhaps deploy some apps on it – but won’t allow you to develop on it (no full trust solutions and not even apps).

There is a developer version of this which allows you to use “Napa” in order to build SharePoint 2013 apps, and you can open your trial account here:

http://msdn.microsoft.com/en-us/library/fp179924.aspx

Depending on your relationship with Microsoft you can get anywhere from 30 days trial up to 1 year of free subscription. All information is at the abovementioned link.

I will post more info as I get it, please feel free to add stuff in the comments.

 

Good luck!

Saturday, October 29, 2011

Developer's Guide: How to enhance your SharePoint performance - Understand Caching

I have just finished my presentation at SharePoint Saturday Twin Cities!

I talked with developers and ITPro on how to enhance their SharePoint and SharePoint customization performance using some of the built in caching features, such as:
- BLOB cache
- Ghost files
- Object cache
- Page output cache
As well as other coding practices, such as:
- Query pagination
- Indexed columns
- Throttling
- Code cache in multi-threaded environment

Here is the complete presentation, download to read comments in each slide:

Monday, May 30, 2011

Setting default value to column in document library

Hi,

One question I hear a lot from developers and system designers is “How can I set a default value to a column in a document library”?

The same goes for form libraries in SharePoint, Apparently SharePoint does not support default values for document libraries.

The first thing that comes to mind, as a solution for this predicament, is to build an event handler that will set a default value to the fields you need whenever a new item (document) is added to the library.

An experienced developer will tell you you should use the ItemAdding event, in order to set the default values to the field during the same update that the user initiated, and under his credentials.

To do that, you will have to use the properties.AfterProperties["FieldName"] = “Default Value”; to set your value.

But – you will be surprised that document libraries, although they do support the ItemAdding event, do not support properties.AfterProperties use. This collection is always empty and ignored in document libraries!

So, the only solution to set a default value to a field in a document library is by using the ItemAdded event.

During this event, the SPListItem was already created and is accessible through properties.ListItem property (unlike ItemAdding, that happens before the item was created).

So, setting the field should be rather easy: properties.ListItem[“FieldName”] = “Default value”;

But you will have to update the file manually yourself, since this happens after SharePoint has already processed the update of the item.

Naturally, you will not want to update the modified date/time, modified by user, and also you will not want to create a new version or emails alerts to be sent out.

So, instead of using the properties.ListItem.Update() method, use these lines of code:

base.DisableEventFiring();
properties.ListItem.SystemUpdate(false);
base.EnableEventFiring();



Or the SharePoint 2010 code equivalent:



this.EventFiringEnabled = false;
properties.ListItem.SystemUpdate(false);
this.EventFiringEnabled = true;


This will allow you to use custom code and programmatically set a default value to any SharePoint library column. Note that the same code should also work for SharePoint Lists, but this is supported through the UI or during the ItemAdding event.



For those of you who are not developers, or would rather a 3rd party solution, you can use KWizCom List Forms Extension solution version 2.1.60 or higher, where you can find a settings page that allows you to set advanced default values using this workaround.



Thanks, Shai.

Tuesday, August 3, 2010

Assembly redirection in WSP

Recently I have started upgrading our utilities to the new SharePoint 2010 version,

One of my main goals there was to get rid of the MSI installer we had to use on our products for SharePoint 2007, and go with a "cleaner" installation process of using the SharePoint WSP package alone.

One of the challenges was that as an ISV we have no control over our customer's server, setup or versions installed. Which means, any customer may have any mix of products and versions at the same time.

For example: say we have 2 products - ProductA and ProductB (both at version 1.0.0.00) that were build using our shared utilities DLL: utilities.dll version 1.0.0.01

A month later, we add a new feature in our utilities.dll that is used on ProductB, so now we have upgraded our utilities to version 1.0.0.02 and our ProductB to version 2.0.0.00 and we publish that to the Internet.

Now our customer upgrades his copy of ProductB only.
We had 2 options here:
1. keep both utilities version
2. upgrade and keep only version 1.0.0.02

The first option was no good, since for example our utilities declare a feature called FeatureA. if 2 different packages declare that same feature, and one of them is retracted later on - the feature will be uninstalled with it (There are some other issues like this one, but this is not the scope of this article).

So, sticking with the second option was pretty simple: just install the latest version of utilities with no other older versions of it anywhere.
The only issue was, How will it "tell" all other older products (ProductA) to start using utilities.dll version 1.0.0.02?!

I have looked everywhere for a solution that was just under my nose.

Apparently in VS2010 and SharePoint 2010 there is a new XML node in the package XML definition, right next to the assembly "SafeControls" node.

This new XML node is called "BindingRedirect", and it allows you to specify in the solution package itself any Assembly version redirection you might need!

Problem is - the package designer does not expose this property, so you have to enter it in the Package.Template.Xml directly.

here is how my package.template.xml file looks like:

The end result is:

And this simple produces the following entree in the web.config:

Now, as far as I tested:
  1. Retracting solution cleans this entree up with no problem!
  2. Deploying a new version upgrades this entree and does not create duplicate entrees!
  3. It is safe (like in my example) to give a wide version range in the oldVersion property - even for future versions that do not exist yet. it will simply allow you not to update this every time you build a new version.
So far, this solution had worked out perfect for me, and it is by far the easiest and most simple way to do it in SharePoint than any other way I found on the web - so hope this helps any of you.

Cheers, Shai.