Showing posts with label solution. Show all posts
Showing posts with label solution. 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!

Friday, March 28, 2014

SharePoint 2010 Deferred site collection upgrade with custom SharePoint solutions


We have been struggling with this concept for a while, being an ISV with many customers who use our products on SharePoint 2007 and 2010 and are interested in upgrading to SharePoint 2013, but using the deferred site collection upgrade approach.
You see, in this approach you upgrade to a SharePoint 2013 farm but still run your 2010 sites in SharePoint 2010 user interface, while allowing site owners to gradually upgrade to 2013 interface gradually.
The problem this poses for us was simple: which version of my solution do I install on that hybrid farm?
SharePoint 2010 solution will work on the 2010 experience sites, but will not work on those that were already upgraded to 2013 or on new sites created in 2013 experience.

SharePoint 2013 solution will work on the upgraded sites or new sites, but not on sites still using the 2010 user interface.

First try (didn't work)

Installing both versions seemed to be the solution, but we had a few issues with that approach:
1. Our 2010 and 2013 WSP solutions have the same solution ID, thus cannot be installed on the same farm at the same time
2. Both 2010 and 2013 WSP packages contain the same DLLs assemblies, and so if we retract one – it will remove the shared DLLs and break the other. So, when upgrade is done and we want to remove the 2010 package it will break the 2013 package.

Working approach

After working closely with the good people at Microsoft, we run some tests and come to the following procedure that would work for us (and possible for everyone in this situation):
1. Install the 2013 solution
2. Create a new package that adds 2010 backward compatibility (called “2010 BC”) that installs only the needed resources and use it during the deferred site collection upgrade period
3. Once that period is over and everything was upgraded – remove the “2010 BC” package *

This approach seems to be working great on our testing, but we still had the 2 issues to deal with (DLLs and solution ID) and I didn’t want to burden our R&D with maintaining and producing another package for every product.

Tools of trade

So, I am happy to share with you a new codeplex project I just released for this purpose:
“WSP REpackage tool” found here: https://wsprp.codeplex.com/
image
image
This tool will take your existing 2010 solution package, and repackage it as a new WSP file with a new solution ID and without the assemblies inside. This new package will be the “2010 BC” package that  you can safely install on your SharePoint 2013 farm along with the SharePoint 2013 solution to be able to support both 2013 native sites and upgraded sites that still use 2010 user interface.
I hope this tool helps you guys support this great new upgrade experience for SharePoint, I am happy to announce KWizCom products were tested and now support the deferred site collection upgrade also using our Web Installer experience that allows you to directly download and install our products and (now) add support for 2010 BC sites with just a few clicks (tool available here: ClickOnce installer)
If you have thoughts, comments please feel free to either comment here or on the discussion in the codeplex project.
I would love to hear what you think about this tool and this upgrade approach in general.
Shai.

* Very important edit note: after discussing with Microsoft, if you retract the 2010BC solution or the 2013 solution using the central administration - even though these solutions now do not share the same solution ID and are set to different versions of SharePoint, they will remove each other's files from both SharePoint root folders (14 and 15). This is a know issue, and MS advised me that the only supported way to retract packages is by using PowerShell with the correct -CompatibilityLevel version flag. http://technet.microsoft.com/en-us/library/ff607873(v=office.15).aspx So please be advised.

Tuesday, May 14, 2013

One solution to rule them all

My prezi is ready for SharePoint Saturday LA!
This session will be heavy on the visual studio live demo, hope that part goes well :)
But for the first part of the talk I thought I could use prezi to explain the challenge in building a solution that can be deployed on both SharePoint 2010 and 2013, without doubling the R&D efforts, QA efforts and overall maintenance.
We had a very long discussion about this in house, and we are still not entirely convinced this is the best solution to this problem, but it is the best we’ve got so far.
In the past we used to have 2 different solutions for each version of the product. This forced us to constantly sync code between the two versions, having to fix and retest every issue on both versions, which of course wasn’t done perfectly so we ended up with bugs that were fixed in one version only, features that were missing from the other version and basically it was very hard to maintain them.
Now, with the introduction of versioned root folders in SharePoint 2013 this have become a bit more challenging since the code would be different and target different folders in 2010 and 2013. While in server code its rather simple to test the version and use the right path, doing it in config xml files (like web part gallery icon, feature icon for example) is not something we can change in runtime.
This is why we came up with a set of tools that allows us to keep working on one solution, and producing 2 packages from the same source code in one build. One for SharePoint 2010 and the other for SharePoint 2013.
It didn’t take a long time before we then learned about the challenges in trying to debug this code on the SharePoint 2013 machine. Since it wasn’t build on that machine, and didn’t target the .NET framework 4 – this proved to be a bit more complex than what we expected.
To find out more on how we got everything working – come see my session!

Please feel free to leave a comment here if you want more info, or if you been to my session and would like me to add or change something.
Code sample:
http://sdrv.ms/14kRdt3

More info on deferred site collection upgrade:
http://kwizcom.blogspot.ca/2014/03/sharepoint-2010-deferred-site.html

Since I get asked a lot during this session, "are FTC solutions dead?"
Here is a short presentation with points to consider:


Friday, January 9, 2009

Global Assembly Cache (GAC) folder suddenly appears empty? Technical problem solved!

A few days ago I was working with Visual Studio and suddenly I was "under attack", a technical problem so persistent that I had to find an immediate solution.

What happened? Suddenly, the Assembly folder (AKA "GAC folder" located at C:\WINDOWS\assembly) appeared empty. In addition, I could not deploy or run any of my web parts.

I restarted my virtual machine, hoping that the assembly folder contents would miraculously reappear after rebooting. That did the trick but it turned out to be a very temporary solution. As I continued working this problem intensified, occurring and greater and greater frequency.
Eventually it happened at intervals of about 10 minutes and it became impossible to continue.

Searching for a more long-lasting solution I came across a forum where many other developers complained about the same problem.

The suggestion I found there was to disable the Indexing Service (located in Start -> Programs -> Administrative Tools -> Services).

I tried this and thankfully it worked! All I had to do is to stop the service in the “services” screen.



Thing is – this service has a knack for “magically” restarting itself every now and then, so if you want to make sure you've gotten rid of it for good – I suggest also changing its start-up type to “Disabled”.



Since I implemented these changes on my computer everything has returned to normal and I've been able to work in Visual Studio freely and easily.

Hope this helps,
Shai Petel