Monday, May 26, 2014

Creating a SharePoint Survey using Existing Questions


Background


I introduced my team members to SharePoint Surveys and created one for us to use.  Unfortunately, our SharePoint admins (for whatever reason) will not allow us to make templates, so we would potentially have had to re-use the same questionnaire for multiple projects and many of our projects run concurrently.

Initial Solution


My initial solution to this problem was to create a field that asked the survey takers which project they were taking the survey for.  This worked, but I could see this becoming a mess.  Also, during this time, some of my co-workers came to me asking if questions could be removed or questions specific to their projects added.  I had to tell them that they would have to create a new survey for that.  They seemed okay with that and I wrote a rather detailed internal blog post about how to create their own surveys.  However, as I was doing that I realized that they would be, essentially, re-inventing the wheel, having to put the same questions in the same surveys.  Not an ideal solution.

Survey Creator


I decided to create an application that would:
  1. Allow a user to create a survey
  2. Allow users to build the survey by picking from an existing ‘bank’ of questions and/or
  3. Allow users to edit an existing survey by adding questions from a ‘bank’ of questions
This is the interface.  You know me. I’m not a UX girl, I get it to work. Pretty takes a back seat if it works.
There are far more questions than this, but for brevity I went with the first 4.
[Create Survey] is the button that triggers everything.
Results-Shows the results of the operation.

I decided to put the questions in a regular custom list instead of using the original survey.  I figured it would be easier for the rest of the team to maintain. I used a dataview webpart to pull the questions from that list.  
I knew I would have to construct at least two (2) commands to give to SPServices so that it could execute the SharePoint webservices to:
  1. Create the survey list
  2. Update the created list with questions (fields) from the question list

Creating the list

I tied the creation of the list and the addition of the questions to the ‘crtSurvey’ button on-click function.
I used AddList to create the list and UpdateList to create the entries (fields) for the list.
The textbox (probably should rename this to something useful later) is the textbox that the user uses to enter the name of the survey they want to create or update.
uStat is an object I created to build the command for adding the questions to the survey.
AddToView is absolutely crucial to using the UPDATELIST command.  You MUST have this in your command or UPDATELIST will not work.


Creating the List with SPServices

Notice that method, defined above as ‘AddList’ is used here for our operation.
templateID is set to 102 to identify this as a Survey list.
migrateQs is used to call the function that will move the selected questions to the survey list.


Updating the Survey List



Keep in mind that using the DataView WebPart with checkboxes creates a series of <INPUT> statements with sibling <LABEL> statements.


This snip of code shows how I set up SPServices to update the list with the new questions.
Allthelabels holds the results of a jQuery…query for all of the lines that are NEXT (siblings) for EACH of the INPUT statements.
Building the UpdateList XML command for SPServices was a little easier using the uStat object I created earlier.  This allowed me to not worry about syntax as much and to build the command as needed.
In the end it should create an xml command that looks like this:
<Fields>
 <Method>
 <Field/>
 </Method>
<Fields>
Required Attributes:
Fields-None
Method- ID and AddToView
Field-Name, Text and MaxLength


Survey Creator in Action

The user enters the name of the survey they’d like to create (or update).
They then select the questions that they would like to include on the survey.
This is the UPDATELIST XML statement that is created.
The debuggr function shows the result of the WebService call.
Meanwhile back at the ranch…
The new survey is now in your survey group.  Remember we defaulted the words ‘auto-gen survey’ when we created the list.
Clicking the TestSurvey hyperlink shows us this.
Select ‘Settings’->’Survey Settings’ to reveal this.
Notice that all of the questions that we selected are now in the created survey.


The Code

<%@ Page Language="C#" %>
<%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register tagprefix="WebPartPages" namespace="Microsoft.SharePoint.WebPartPages" assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<html dir="ltr">

<head runat="server">
<meta name="WebPartPageExpansion" content="full" />
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Survey Creator</title>
<script type="text/javascript" src=" jquery-1.7.2.min.js">
</script>
<script type=" jquery.SPServices-0.7.1a.min.js">   
</script>
<style type="text/css">
.basic {
    color: Blue;
    font-family: Arial, Helvetica, sans-serif;
}
.bigLetter { color:maroon; letter-spacing:10px; font-family:Arial, Helvetica, sans-serif; display:none; font-size:medium}
.instructions {
    color:maroon; font-family:Arial, Helvetica, sans-serif; font-size:x-small;
}
.error {
    color:red;
    font-family:Arial, Helvetica, sans-serif;
    font-size:small;
}
    .topmarg { margin:50px }
    .floater {font-family:Arial, Helvetica, sans-serif;}
    a:link {text-decoration:none;}
    a:visited {text-decoration:none;}
    a:hover {text-decoration:none;}
    a:active {text-decoration:none;}
.style1 {
    text-align: left;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div id="HEADER" class="bigLetter"></div>
<div id="instruct" class="instructions">Please follow these instructions to create your survey.<br/>  After the survey's creation you may add questions specific to your teams needs
    in SharePoint.<br/>
(1) Enter a name for your survey <br/>
(2) Select the starter questions for your survey by clicking a checkbox in the 'Select' next to the question.<br/>
</div>
<table class="basic" style="width: 100%">
    <tr>
        <td style="width: 238px; height: 75px;">What would you like to name your survey?</td>
        <td style="height: 75px">
        <asp:TextBox runat="server" id="TextBox1" Width="522px"></asp:TextBox>
        &nbsp;</td>
    </tr>
    <tr>
        <td style="width: 238px" valign="top" class="style1">
        What questions would you like to import into this survey?
        </td>
        <td>
        <asp:CheckBoxList runat="server" id="CheckBoxList1" Width="516px" Height="25px" DataSourceID="spdatasource1" DataTextField="Questions" DataValueField="Selected"></asp:CheckBoxList></td>
        <tr>
            <td style="width: 238px">
                <button id="crtSurvey" name="crtSurvey">Create Survey</button>
            </td>
        </tr>
</table>
//This is the code that is produced when you create the DataView
<SharePoint:SPDataSource runat="server" DataSourceMode="List" UseInternalName="true" UseServerDataFormat="true" selectcommand="&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name=&quot;Questions&quot;/&gt;&lt;FieldRef Name=&quot;ID&quot;/&gt;&lt;FieldRef Name=&quot;Selected&quot;/&gt;&lt;FieldRef Name=&quot;PermMask&quot;/&gt;&lt;/ViewFields&gt;&lt;/View&gt;" id="spdatasource1"><SelectParameters><asp:Parameter Name="ListID" DefaultValue="{542EF89B-60D2-41FF-9B68-9DD9D264A29C}"/></SelectParameters><DeleteParameters><asp:Parameter Name="ListID" DefaultValue="{542EF89B-60D2-41FF-9B68-9DD9D264A29C}"/></DeleteParameters><UpdateParameters><asp:Parameter Name="ListID" DefaultValue="{542EF89B-60D2-41FF-9B68-9DD9D264A29C}"/></UpdateParameters><InsertParameters><asp:Parameter Name="ListID" DefaultValue="{542EF89B-60D2-41FF-9B68-9DD9D264A29C}"/></InsertParameters></SharePoint:SPDataSource>
<script type="text/javascript">
        jQuery(document).ready(function($) {        //READY
                           var thisUserName = $().SPServices.SPGetCurrentUser({
                            fieldName: "Title",
                            debug: false
                            });
                            ShowWelcome(thisUserName);
        });// End READY
        /********** Show the Welcome *************/
            function ShowWelcome(thisUserName)
            {
                 $("#HEADER").append("<p>Welcome, " + thisUserName + "</p>");
                 $("#HEADER").show();
                 $("#instruct").show();  
            }
           
        //When user selects 'Create Survey'
        $("#crtSurvey").click(function()
               {
                //alert("survey button clicked");
                //--Begin Function
               var tmpSurvey = new Object();
               //The Web Service method we are calling
               var method = "AddList";
               var method2= "UpdateList";
               //Supply the location and name of the list we are reading data from
               var myWebURL = "[your SharePoint directory]";
               //Name of Survey
               var list = $('#TextBox1').val();
               //UpdateListItems update statement
                var uStat = new Object();
                uStat.method = "<Method";
                uStat.methodID = " ID=";
                uStat.CMD = " Cmd=";
                uStat.A2V = " AddToView=";
                uStat.fields = "<Fields>";
                uStat.fldOpen = "<Field";
                uStat.fldType = " Type=";
                uStat.fldName = " Name=";
                uStat.fldDName = " DisplayName=";
                uStat.maxL = " MaxLength=";
                uStat.fbt = " FromBaseType=";
                uStat.fldClose= "/>";
               uStat.name = "<Name=";
               uStat.nameEnd= "</Name>";
               uStat.fieldsEnd = "</Fields>";
                uStat.methodEnd= "</Method>";
               var nuQ = new Object();

       //Create the Survey...
       //Here is our SPServices Call where we pass in the variables that we set above
       $().SPServices({
               debug: true,
               operation: method,
               webURL: myWebURL,
               listName: list,
               description: "auto-gen survey",
               templateID: "102",
               async: false,  
                   //this basically means "do the following code when the call is complete"
                   completefunc: function (xData, Status)
                      {
                        if (Status === 'error')
                            {
                                debuggr(xData, Status);
                           }
                      }//End  CompleteFunct
                     });//--End SPServices
                 migrateQs(list, method2, uStat, myWebURL);
                 });// end function

        function migrateQs(list, method2, uStat, myWebURL)              
       {
           //Enumerate all checked checkboxes
           var cntr = 1;
            var quote = "'";
            var clsbrkt = '>';
            var opnbrkt = '<';
            var allinputs = $('input').html();
            var alllabels = $('label').html();
           $('input').each(function()
           {
               if ($(this).prop('checked'))
               {
                    var findme = $(this).attr('id');
                   var allthelabels = $(this).next().html();
                    //alert('selected checkbox = ' + findme + ' and label value =' + allthelabels);
                   var dothis = uStat.fields + uStat.method +
                   uStat.methodID + quote + '1' + quote + uStat.A2V + quote + ' ' + quote +
                   clsbrkt +
                   uStat.fldOpen + uStat.fldName + quote + 'Question' + cntr + quote +
                   uStat.fldDName + quote + allthelabels + quote +
                   uStat.fldType + quote + 'Text' + quote +
                   uStat.maxL + quote + '255' + quote +
                   uStat.fbt + quote + 'True' + quote + uStat.fldClose +
                   uStat.methodEnd + uStat.fieldsEnd;
                   //alert(dothis);
                        //Copy a question to the survey
                       $().SPServices({
                       //debug: true,
                       operation: method2,
                       webURL: myWebURL,
                       listName: list,
                       listProperties: "",
                       updateFields: "",
                       newFields: dothis,
                       deleteFields: "",
                       listVersion: "",
                       async: false,
                       //this basically means "do the following code when the call is complete"
                               completefunc: function (xData, Status)
                               {
                                        //alert('Question transfer attempt result: ' + Status);
                                       debuggr(xData, Status);
                               }//End  CompleteFunct
                          });//--End SPServices
                }//End If
                cntr = cntr+1;
            });// End each.function
        }//End MigrateQ function
        function debuggr(xData, Status)
        {
            //if (Status == 'error')
            //{
                 $("#debugMe").append(Status);
                 if($().SPServices.SPDebugXMLHttpResult({ node:xData.responseXML })==null)
               {
                   var showmetext = $().SPServices.SPDebugXMLHttpResult({ node:xData.responseText });
                    $("#debugMe").append(showmetext);
                  }
               else
               {
                   var showmestuff = $().SPServices.SPDebugXMLHttpResult({ node:xData.responseXML });
                    $("#debugMe").append(showmestuff);
                  }
                $("#debugMe").show("slow");
            //}
        }
</script>
<table id="floatMe" border="1" class="floater">
</table>
<div id="debugMe">
<div class="error">Result(s):</div>
</div>
</form>
</body>
</html>