Friday, April 26, 2013

Working with SPUtility.js in SharePoint 2010


Let me discuss the use of SPUtility.js in SharePoint 2010 with simple examples.

Populate value for the Title field automatically 

Write the following script

Approach 1:
<script src="/Shared%20Documents/prototype.js" type="text/javascript"></script>
<script src="/Shared%20Documents/SPUtility.js" type="text/javascript"></script>
<script type="text/javascript">
Event.observe(window,'load',function(){
    SPUtility.GetSPField('Title').SetValue('Hello world!');
}); </script>

Approach 2:
<script src="/Shared%20Documents/prototype.js" type="text/javascript"></script>
<script src="/Shared%20Documents/SPUtility.js" type="text/javascript"></script>
<script type="text/javascript">
function MyCustomExecuteFunction()
{
     SPUtility.GetSPField('Title').SetValue('Hello world1!');
}
_spBodyOnLoadFunctionNames.push("MyCustomExecuteFunction");</script>

To install, you’d simply place the JavaScript above into a Content Editor Web Part on your NewForm.aspx or EditForm.aspx. Take a look at the SPUtility.js Installation page for detailed instructions.

Get the Title field value in EditForm.aspx

Approach 1:
<script src="/Shared%20Documents/prototype.js" type="text/javascript"></script>
<script src="/Shared%20Documents/SPUtility.js" type="text/javascript"></script>
<script type="text/javascript">
Event.observe(window,'load',function(){
    alert(SPUtility.GetSPField('Title').GetValue());
}); </script>

You can use approach 2 also to get the value.

Reference Links:
Installation documentation:
 
Download scripts

SPUtility.js details

Javascript PreSaveAction() in SharePoint 2010 Validation

Go to SharePoint List Defalut Edit or Newform.aspx.

Over there you have to put the HTML Form WebPart.

Inside the HTML Form Webpart you need add the following scripts tag and references.

Download js files from here  http://sputility.codeplex.com/

<script src="/Registry/JSFiles/prototype.js" type="text/javascript"></script>
<script src="/Registry/JSFiles/SPUtility.js" type="text/javascript"></script>

<script type="text/javascript">

function PreSaveAction() {
var item=SPUtility.GetSPField('Type of Report').GetValue(); // Choice filed Validation
if(item=="Informer")
{
     alert("Please select the Value");
     return false;

}
else
{
return true;
}
 }
</script>​

List Join operation in SharePoint 2007 / 2010


Approach 1


private static void FetchAllListsDataJoinUsingLinq()
{
    using (SPSite _spSite = new SPSite("<Site Url>"))
    {
        using (SPWeb web = _spSite.OpenWeb())
        {
            SPList placeList = web.GetList(web.Url + "/lists/TouristPlace");
            SPQuery ospPlaceQuery = new SPQuery();
            DataTable dtPlace = placeList.GetItems(ospPlaceQuery).GetDataTable();
            SPList cityList = web.GetList(web.Url + "/lists/City");
            SPQuery ospCityQuery = new SPQuery();
            DataTable dtCity = cityList.GetItems(ospCityQuery).GetDataTable();
            SPList countryList = web.GetList(web.Url + "/lists/Country");
            SPQuery ospCountryQuery = new SPQuery();
            DataTable dtCountry = countryList.GetItems(ospCountryQuery).GetDataTable();

            List<TouristPlaceDetails> joinData = (from place in dtPlace.AsEnumerable()
                                                    join city in dtCity.AsEnumerable() onplace.Field<string>("CityName"equals city.Field<string>("Title")
                                                    join country in dtCountry.AsEnumerable() oncity.Field<string>("Country"equals country.Field<string>("Title")
                                                    select new TouristPlaceDetails
                                                    {
                                                        Name = place.Field<string>("Title"),
                                                        History = place.Field<string>("History"),
                                                        City = place.Field<string>("CityName"),
                                                        Population = city.Field<string>("Population"),
                                                        Country = country.Field<string>("Title"),
                                                        AgentName = country.Field<string>("AgentName"),
                                                        AgentNumber = country.Field<string>("AgentNumber")
                                                    }).ToList();
        }
    }
}


Approach 2
private static void JoinMultipleListsUsingLinqSharePoint2010()
        {
            LearnDataContext joinDataContext = new LearnDataContext("<Site Url>");
            List<TouristPlaceDetails> joinData = (from place in joinDataContext.TouristPlace.ToList()
                                                  join city in joinDataContext.City on place.CityNameequals city
                                                  join country in joinDataContext.Country on city.Countryequals country
                                                  select new TouristPlaceDetails
                                                  {
                                                      Name = place.Title,
                                                      History = place.History,
                                                      City = place.CityName.Title,
                                                      Population = city.Population,
                                                      Country = country.Title,
                                                      AgentName = country.AgentName,
                                                      AgentNumber = country.AgentNumber
                                                  }
                           ).ToList();

        }

Approach 3

private static void JoinMultipleListsUsingJoinsProperty()
{
    using (SPSite _spSite = new SPSite("<Site Url"))
    {
        using (SPWeb web = _spSite.OpenWeb())
        {
            SPList reportList = web.GetList(web.Url + "/lists/TouristPlace");
            SPQuery ospQuery = new SPQuery();
            ospQuery.Joins = @"<Join Type='LEFT' ListAlias='City'>
                                        <Eq>
                                            <FieldRef Name='CityName' RefType='Id' />
                                            <FieldRef List='City' Name='ID' /> 
                                        </Eq>
                                    </Join>
                                    <Join Type='LEFT' ListAlias='Country'>
                                        <Eq>
                                            <FieldRef List='City' Name='Country' RefType='Id' />
                                            <FieldRef List='Country' Name='ID' /> 
                                        </Eq>
                                    </Join>";
            ospQuery.ProjectedFields = @"<Field
                                            Name='Population'
                                            Type='Lookup'
                                            List='City'
                                            ShowField='Population'/>
                                            <Field
                                            Name='Country'
                                            Type='Lookup'
                                            List='Country'
                                            ShowField='Title'/>
                                            <Field
                                            Name='AgentName'
                                            Type='Lookup'
                                            List='Country'
                                            ShowField='AgentName'/>
                                            <Field
                                            Name='AgentNumber'
                                            Type='Lookup'
                                            List='Country'
                                            ShowField='AgentNumber'/>";
            ospQuery.ViewFields = @"<FieldRef Name='Title'/>
                                        <FieldRef Name='History'/>
                                        <FieldRef Name='CityName'/>
                                        <FieldRef Name='Population'/>
                                        <FieldRef Name='Country'/>
                                        <FieldRef Name='AgentName'/>
                                        <FieldRef Name='AgentNumber'/>";
            SPListItemCollection dtResult = reportList.GetItems(ospQuery);
            List<TouristPlaceDetails> joinResult = new List<TouristPlaceDetails>();

            for (int i = 0; i < dtResult.Count; i++)
            {
                joinResult.Add(new TouristPlaceDetails
                                    {
                                        Name = Convert.ToString(dtResult[i]["Title"]),
                                        History = Convert.ToString(dtResult[i]["History"]),
                                        City = Convert.ToString(dtResult[i]["CityName"]),
                                        Population = Convert.ToString(dtResult[i]["Population"]),
                                        Country = Convert.ToString(dtResult[i]["Country"]),
                                        AgentName = Convert.ToString(dtResult[i]["AgentName"]),
                                        AgentNumber = Convert.ToString(dtResult[i]["AgentNumber"])
                                    }
                                );
            }
        }
    }
}


 Set Joins property in SPQuery in the below mentioned format:

<Join Type='LEFT' ListAlias='customers'>
          <Eq>
                <FieldRef List='<Child List Name (Optional)>' Name='<Lookup Column Name>' RefType='Id' />
                <FieldRef List='<Parent List Name>' Name='ID' />
          </Eq>
 </Join>

SharePoint : Validate controls before the item is saved SharePoint 2007/2010 List


I do have one requirement in which I need to check if they check one of the checkbox then they must have to enter the value. Without eventhandler or any custom code how could we do that?
We can achieve this thing via Content Editor WebPart and write JavaScript inside that. PreSaveAction() is manly used to validate controls before the item is saved( new item or edit).
How to do that?
Let us edit the page and add one content editor webpart , and add the javascript code in that content editor webpart and save page.
Sample of Javascript Code.
<script type="text/javascript">
function PreSaveAction()
{
var control = getTagFromIdentifierAndTitle("input","BooleanField","Other available");
var control1 = getTagFromIdentifierAndTitle("input","TextField","Other Value");
if(control.checked)
{
var StrToCheck= control1.value.replace(/^\s+|\s+$/, '');
//then we check for the length of the string if its 0 or not
if( StrToCheck.length==0 || StrToCheck =='0')
{
alert('Enter the value for Other');
}
}
else
{
control1.value=0;
}
return false;
}

function getTagFromIdentifierAndTitle(tagName, identifier, title) {
  var len = identifier.length;
  var tags = document.getElementsByTagName(tagName);
  for (var i=0; i < tags.length; i++) {
    var tempString = tags[i].id;
    if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {
      return tags[i];
    }
  }
  return null;
}
</script>

JAVA SCRIPT SAMPLE CODE FOR SHAREPOINT LIST


JavaScript Errors in SharePoint Application Pages

Today was a day packed with investigation and troubleshooting weird JavaScript errors on a customer premise. I put this information on my blog so to help anyone who might have found in a similar journey.

SYMPTOMS

Problem 1: Views
You have a custom SharePoint 2010 master page. You assign that master page as the master page for a site, both for content and system pages. You face the following errors when dealing with list or library views:
  • You can't change the current view in the Ribbon view selector. The combo box doesn't drop down. Additionally, you do not have the view selector on the page title.
  • You edit the current view (or any other view). A JavaScript error is displayed in Internet Explorer and you can't save the changes. However, in Firefox you can modify the view without any problems.
Problem 2: File Upload page
You have a custom SharePoint 2010 application page. The page inherits from the default SharePoint file upload page. You want to replace the file upload control with a custom control. However, you have to maintain the original control because the inherited code relies on the presence of those controls. You hide the controls but you still face JavaScript errors due to the hidden control validation scripts.

CAUSES

Problem 1: the culprits are the new SharePoint 2010 master page placeholders and delegate controls.
In order to have view selector working, you have to add the following DelegateControl to the master page (as found on this thread):
<SharePoint:DelegateControl runat="server" ControlId="TreeViewAndDataSource">
</SharePoint:DelegateControl>
The weird JavaScript errors on the Edit View page were caused by a PlaceHolderUtilityContent that was misplaced. This content placeholder should be placed outside the <form>tag on the master page, as this MSDN article outlines.
</form>
<asp:ContentPlaceHolder id="PlaceHolderUtilityContent" runat="server"/>
It seems that the Internet Explorer breaks when a JavaScript error is found, and skips the execution of the remaining script block while Firefox just skips the current line and executes the remaining lines if they are correct. The errors were about the objects being null, as the IE skipped the object initialization commands due to the errors generated by a misplaced placeholder tag.
Problem 2: the culprit was the JavaScript emitted by the default validation controls for the file upload selector. The solution was to embed the default control inside an ASP.NET Panel control set to Visible="false". In this way the controls are present on the server but nothing is rendered back to the page, preventing JavaScript errors.

NumberField and getElementById



Just a quick lesson learnt today in field:

SCENARIO

You want to use JavaScript to validate certain fields when the SharePoint page is in Edit Mode. You use Control.ClientID ASP.NET property to emit the control ID from the server-side code using Page.ClientScript (usually in PreRender event). You’d usually use this ID to access the control on the client side using document.getElementById.

PROBLEM

I had issues with NumberField (the server-side control that is used to render a numeric column in SharePoint). Its ClientID property is not the same as the one that is finally rendered back. In fact, it’s a child control, two levels down from the NumberField. The reason for this behaviour is that NumberField is a composite templated control, with multiple child controls that compose it.

SOLUTION

Instead of using:
numberFieldCtrl.ClientID
use
numberFieldCtrl.Controls[0].FindControl("TextField").ClientID
to get your correct control ID for JavaScript validation code on the page.

Hiding List View Group Headers



It’s really annoying that SharePoint displays those pesky column names followed by a colon when you group by a column. In this example I use the the columns “Categoria” and “Titulo” to group a bunch of pages.
image




In addition, the gray header row is ugly, too.
We can hide it with some Content Editor Web Part (CEWP) and JavaScript magic.
The offending elements can be identified:
image
We have to hide the following elements:
  • a TR element with class name ms-viewheadertr (the header row)
  • the fourth and the fifth child of a TD element with class names ms-gb (the column name of the first group by and a colon)
  • the fourth and the fifth child of a TD element with class names ms-gb2 (the column name of the second group by and a colon)
I use the excellent getElementsByClassName function developed by Robert Nyman in order to get those elements by class name.
This is the code to be pasted in a CEWP at the same page where you have the “ugly” list view. Please note that the text node which contains the colon must be removed instead of being hidden.
<script type="text/javascript" language="javascript">
_spBodyOnLoadFunctionNames.push("HideHeaders");
function HideHeaders()
{
  var elements = getElementsByClassName(document, "td", "ms-gb");
  var elem;
  for(var i=0;i<elements.length;i++)
   {
     elem = elements[i];
     elem.childNodes[3].style.display = "none";
     elem.removeChild(elem.childNodes[4]);
   }
  elements = getElementsByClassName(document, "td", "ms-gb2");
  for(var i=0;i<elements.length;i++)
   {
     elem = elements[i];
     elem.childNodes[3].style.display = "none";
     elem.removeChild(elem.childNodes[4]);
   }
  elements = getElementsByClassName(document, "tr", "ms-viewheadertr");
  for(var i=0;i<elements.length;i++)
   {
     elem = elements[i];
     elem.style.display = "none";
   }
}
/*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com
*/
function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }
    }
    return (arrReturnElements)
}
</script>







This is the result of this code:
image

IE and The Mysterious ‘The page took too long to save’ Message





Another one of those “oh my god” moments in SharePoint programming, although it had nothing to do with SharePoint proper.

The Background

I want to dynamically add a DIV alongside a SharePoint field in Publishing page. The intended purpose is to extend the built-in control without any server-side code. I want the DIV to hold a simple hand-crafted AJAX call to add new items.
Everything is okay, I add my code to the SharePoint _spBodyOnLoadFunctionNames.push function, I find the control to be extended and I yank the DIV from its previous location to the parentNode object of the control. It nicely shows the new DIV below the original control:
image
The DIV contains an anchor element that has href=”#” and onclick=”SomeFunction();”. It’s created dynamically when the page loads:
var link = document.createElement("a");
link.href="#";
link.innerHTML = "Agregar nuevo elemento";   
link.onclick = "SomeFunction();";
div.parentNode.appendChild(link);

The Symptoms

When you click the anchor in the added DIV, there’s a 30-second pause during which IE responds to no clicks, after which the following message appears:
Are you sure you want to navigate away from this page?
The page took too long to save. You can click “Cancel”, and then try to save the page again. If you click “OK”, you might lose unsaved data.
Press OK to continue, or Cancel to stay away on the current page.
image
After you click OK, the anchor works well, calling the SomeFunction flawlessly.

The First Suspect

I though that the issue was caused by another function I called, that uses “AJAX” call to owssvr.dll to filter cascading dropdown controls (more on that in next posts). It might leave the HTTP request in a undefined state so that the IE thinks it’s still not loaded.
I commented it out but the error persisted.

The Second Suspect

Then I thought that it has something to do with the appendChild method I use to move the DIV from its placeholder to the new position below the control it’s extending.
I changed the call to dynamically create a new DIV instead of moving the old one to a new position in DOM tree. But, the same error persisted.

The Real Culprit

After David GutiĆ©rrez, one of my colleagues (whose mileage in JavaScript is much greater than mine) revised the code, and after a perfunctory “brain processing” period (which lasted about an hour, in this case), he appeared and outlined the malfunction.
The error message is caused by IE trying to “execute” the new onClick event, which is set to a JavaScript function in this case. But, the syntax is wrong, wrapped inside double-quotes, like in inline HTML.
link.onclick = "SomeFunction();";
The correct syntax is written just like a method call, using only the function name:
link.onclick = SomeFunction;






















































IE seems to “compile” the string into a method call, but only after you confirm that you want to navigate away. Weird enough.

Add a Submit Button Confirmation to an ASP.NET Web Form



I've been asked many times how to add a confirmation dialog for a simple (or complex, why not?) ASP.NET web form. It's simple:
  • Find the OnClientClick property of the button control
  • Type return confirm('are you sure?') as the value of the property

"I Need To..." Web Part and JavaScript error



If you try to customize the "I Need To..." web part, as outlined by Gary in his blog post, you might experience a JavaScript error, just like this one:
Line: 1
Char: 1
Error: Object expected
Code: 0 
This error is launched by the TATWP_jumpMenu JavaScript function, because it attempts to execute a function defined in another .js file that hasn't been loaded.
Workaround:
Add a hidden Content Editor Web Part with the following HTML source text:
<script language="javascript" src="/_layouts/portal.js?rev=INhSs9mWTnUTqdwwIXYMaQ%3D%3D"></script>
This will ensure that the referenced script file loads correctly.

Hide a field from NewForm.aspx



I was faced with this problem lately: you have a optional field in your list that you'd like to leave hidden from the user (it's used for workflow status keeping).

The first solution is to customize NewForm.aspx from SharePoint Designer and replace the default list form with Custom List Form, in which you can remove the fields you don't need. The inconvenience is that you lose the ability to attach files to the list item. As I had to attach files to the list, this option was unacceptable.

Fortunately, there is another way to hide a field. You can customize NewForm.aspx and add a JavaScript code that hides the whole row the field is placed. I used the code snippet from SharePoint Designer blog and I came out with this small code block, to be placed on NewForm.aspx (or EditForm.aspx, as you wish).

You have to replace these fields (see the SPD blog entry for more information):
  • TAGNAME: HTML element that is being rendered ("SELECT", "INPUT"...)
  • IDENTIFIER: SharePoint field type identifier ("TextField", "DropDownChoice"...)
  • FIELD NAME: Display name of the field (e.g. "Status", "Customer Name"...)



<script language="javascript" type="text/javascript">

_spBodyOnLoadFunctionNames.push("hideFields");


function hideFields() {

var control = getTagFromIdentifierAndTitle("TAGNAME","IDENTIFIER","FIELD NAME");

control.parentNode.parentNode.parentNode.style.display="none";

}


function getTagFromIdentifierAndTitle(tagName, identifier, title) {

var len = identifier.length;

var tags = document.getElementsByTagName(tagName);

for (var i=0; i < tags.length; i++) {

var tempString = tags[i].id;

if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {

return tags[i];

}

}

return null;

}

</script>

Add JavaScript Date Validation into List Item forms

I want to validate two fields on a new list item form by invoking JavaScript custom function. They are two date fields and I want to ensure that the end date can't happen before the start date. My first idea was to attach a validation function on the onclick event of the Submit button.
I started by inspecting the generated HTML of the form. The Submit button already has a onclick() code which is:
if (!PreSaveItem()_) return false;WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$ctl13$g_740c1963_b0da_4b45_9b71_0dcca5d082b0$ctl00$toolBarTbl$RightRptControls$ctl00$ctl00$diidIOSaveItem", "", true, "", "", false, true))
Searching in the SharePoint JavaScript files in the LAYOUT folder, I found the definition of PreSaveItem function in FORMS.JS file. It simply invokes PreSaveAction function, if defined.
Finally, it was just a matter of inserting a custom function named PreSaveAction in a <SCRIPT> block of the NewForm.aspx (and EditForm.aspx). I also used the date parse code from this forum.
The code I put in NewItem.aspx is like this

function PreSaveAction()
{
    var date1 = getTagFromIdentifierAndTitle("INPUT","DateTimeFieldDate","Contract Date"); 
    var date2 = getTagFromIdentifierAndTitle("INPUT","DateTimeFieldDate","Contract End Date");
    var arrDate1 = date1.value.split("/");
    var useDate1 = new Date(arrDate1[2], arrDate1[1]-1, arrDate1[0]);
    var arrDate2 = date2.value.split("/");
    var useDate2 = new Date(arrDate2[2], arrDate2[1]-1, arrDate2[0]);
    if(useDate1 > useDate2)
    {
        alert("The end date cannot happen earlier than the start date");
        return false; // Cancel the item save process
    }
    return true;  // OK to proceed with the save item }



// getTagFromIdentifierAndTitle: Find a form field object using its tagName, identifier, and title to find it in the page  

// Arguments:  
//        tagName:            The type of input field (input, select, etc.)  

//        identifier:         The identifier for the instance of the fieldName (ff1, ff2, etc.)  

//        title:              The title of the list column  
//  

function getTagFromIdentifierAndTitle(tagName, identifier, title) {  
    var len = identifier.length;  
    var tags = document.getElementsByTagName(tagName);  
    
    for (var i=0; i < tags.length; i++) {  
        var tempString = tags[i].id;  
        if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {  
            return tags[i];  
        }  
    }  
    return null;  
}  
    
</script>