Pages

Sunday, October 9, 2011

SharePoint 2010: Get Full or Relative Url of web using EcmaScript

Sometimes from client side, you need to know the current web url. And for this little information you don’t want to call EcmaScript’s load function to get information from server side. Actually the information can be found without any server call. You can access the information from ClientContext as shown below.

var context = new SP.ClientContext();
var relativeWebUrl = context.get_url();

Remember the get_url method will only return relative url of the site. As shown in the following table:

Site Collection Url Site Url context.get_url() response
http://mysite.com http://mysite.com /
http://mysite.com http://mysite.com/site1 /site1
http://mysite.com/sites http://mysite.com/sites/site1 /sites/site

 

So if you need to know the full url of the site you can do so easily with the following script:

function getFullWebUrl() {
var context = new SP.ClientContext();
var relativeWebUrl = context.get_url();
var fullWebUrl = window.location.protocol + '//' + window.location.host + relativeWebUrl ;
alert(fullWebUrl);
}

Saturday, September 17, 2011

SharePoint 2010: Access WCF Service with jQuery

In one of my earlier post I described how to develop a custom WCF service. Today I’ll cover how you can invoke the SharePoint WCF Service from jQuery. In my last post I described to develop a SOAP web service but for using WCF service from jQuery I’m going to use REST web service. For the list of service types and factories supported in SharePoint you can visit the link in MSDN. You can download source code from the link given at the end of the post.

Prepare the service to call from jQuery

Consider developing a service as described in my earlier post with the following changes:

  • For  using json I’ve used REST service factory ‘Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory’ as shown below. You can use SOAP factory but you then need to parse data in different way.
    <%@ ServiceHost Language="C#" Debug="true"
    Service="AccessSPServiceFromJQuery.MyService, $SharePoint.Project.AssemblyFullName$"
    CodeBehind="MyService.svc.cs"
    Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0,
    Culture=neutral, PublicKeyToken=71e9bce111e9429c"
    %>


  • Next you need to specify the return type to json in the service interface as shown below. I’ve specified both request and response type to json in WebInvoke attribute:

    [ServiceContract]
    public interface IMyService
    {
    [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    List<Product> SearchProduct(string productName);


    [OperationContract]
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    bool Save(Product product);
    }

One thing to notice here is that you can’t access the service in browser with mex endpoint. For example if you service is http://myserver/myservice.svc, then the url http://myserver/myservice.svc/mex will not work for service created with MultipleBaseAddressWebServiceHostFactory.
 

Call Service with jQuery

The next step is to call the service with jQuery. The url of the service to be used in jQuery will be service url and method name. For example if you service url is ‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc’ and the method name you want to invoke is ‘Search’ then the full url will be ‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/Search’. As shown in the code below, you can invoke the service Search by passing the parameter in data field of ajax call of jquery

function getProductFromService(searchText) {
try {
$.ajax({
type: "GET",
url: '/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/SearchProduct',
contentType: "application/json; charset=utf-8",
data: { "productName": searchText },
dataType: 'json',
success: function (msg) {
WCFServiceGetSucceeded(msg);
},
error: WCFServiceGetFailed
});
}
catch (e) {

alert('error invoking service.get()' + e);
}
}
function WCFServiceGetSucceeded(result) {
alert('success');
}
function WCFServiceGetFailed(error) {
alert('Service Failed.');
}

Download and use code

I’ve uploaded the code for this post in my skydrive. You can download the code from the link below. To use the code please ensure you have internet connection as I’ve used jqery from Microsoft CDN. The search functionality get all products matching name. You can try to search just by typing a single character. You can debug and test the code. In save I’ve just shown you can pass value from browser to service using POST method.

Wednesday, August 24, 2011

SharePoint 2010: Postback to the same page from Ribbon

Most of the examples related to ribbon button actions involve opening dialog. However, if you need to send post back request to the same page/dialog where the ribbon exists, you need to trick a bit. Let’s explain how you can do so.

Define Ribbon XML

You can define the postback action in the command action in Ribbon xml file. To do so, you can use javascript function _doPostBack(‘token’,’’). This will send a postback request to the same page.

<CommandUIHandler
Command="MyButton.Command"
CommandAction="javascript:__doPostBack('MyButtonPostback','');"
EnabledScript="true" />
Figure 1: PostBack action defined in Ribbon xml

 

Identify the PostBack request in the page

The second step is to identity from code behind file, if the postback occurred from ribbon button’s action. From the page load, you can check if the postback occurred due to the command “MyButton.Command”. To do so we can have a check shown below in the page load method.

if (Page.Request["__EVENTTARGET"] == "MyButtonPostback")
{
//The ribbon button initiated the postback
}

 

 

Though this is very simple trick but might be helpful for someone.

Tuesday, August 23, 2011

SharePoint 2010: Modifying and Deploying Ribbon doesn’t update the ribbon

Recently I’ve been working extensively with Ribbon. So what I did, I developed a ribbon and attached the ribbon to a feature. Then after modifying the ribbon in Visual Studio I deployed the ribbon again to see the changes. But interestingly the modification was not working. The ribbon was deployed successfully for the first time. But later I updated the ribbon xml in Visual studio and redeployed and the update to the ribbon was not showing in the site though the deployment was successful. Event I tried to deactivate/activate the ribbon feature but no luck. So the problem was ribbon update was not showing in effect in the site event after successful deployment.

 

Solution

Finally I found the solution from Sandrino Di Mattia’s post here. Basically, You need to modify the feature version every time you modify the ribbon and redeploy. First find which feature the ribbon is associated with. Then open the feature properties window and modify the feature version as shown below:

image

Figure 1: Change Feature Version

Another solution might be to clear your browser cache.

 

Conclusion

So changing the feature version or clearing the browser cache or private browsing might be solution for getting ribbon update in browser.

Sunday, June 26, 2011

SharePoint 2010: Approve/Reject dialog customization, show changed values

SharePoint provide rich support for approval process. You can maintain version of changes, you can use built-in workflows or develop your own for approval process. You can even create custom workflow activities and use it in SharePoint Designer to create your own approval workflow. Unfortunately, SharePoint doesn’t provide a nice UI where approver can get a snapshot of what’s changes he’s going to approve/reject. What we are familiar with the following UI:

image

Figure 1: Very generic UI to approve/reject

 

What if we could have a dialog as shown below:

image

Figure 2: Custom Approve/Reject dialog with modification highlighted

As shown in figure 2, the approver will have the better look of what’s the changes he’ll approve/reject. As shown in figure 2, the person who will approve/reject, can get a snapshot of what changes are waiting for his/her approval.

 

What’s the cost of custom approve/reject dialog?

Now the question comes what’s the development cost of such a custom approve/reject dialog? I’ve just developed few classes for returning a list of items with three fields (Field Name, Old Value and new Value) which can be bound to a grid. I’ve already provide the source code in here. But the development process is described below:

Create a custom action menu: You can hide the custom approve/reject menu or you can keep it in place. What I’ve done is included a new custom action menu ‘Approve/Reject Single’ as shown in the image below.

image

Figure 3: Custom action menu (Approve/Reject Single)

 

Create custom Application Page: Next you need to develop a custom application page which will be shown in the dialog when the custom action menu (show in figure 3) will be clicked. The custom application page will show the changes (field name, old value and new value) as shown in figure 2.

Download and test the code

If you have downloaded my last code from blog “Approve/Reject Multiple Items” please uninstall the solution first. Either you may find conflict as I’ve used the source code from that post and modified for this post. You can download the code for this post from my MSDN code gallery http://archive.msdn.microsoft.com/SP2010ApproRejectExt. Then from download tab download the second file “SharePoint.ApproveRejectTestWithVisual”.

Conclusion

The provided code is not something that you can just download and deploy in production. The code is just for can-do sample which shows such a nice view of changed items possible.

Wednesday, June 15, 2011

SharePoint 2010: Customize SharePoint Add/Edit/Display Form

When you create a SharePoint list the default SharePoint add/edit/display form get its looks by its own. For example the fields appears in the add/edit/display form based on the sequence you added the fields. Also by default all fields of the list are shown in the forms. Sometimes you may need to give a hand to customized that look and feel. I’ll try to give some light on how you can customize the default add/edit/view form of SharePoint list.

 

Enable Content type Management First

To customize the List forms you need to enable ‘content type management’. You can do so from List settings Page and then click ‘Advance Settings’. Then select yes for “Allow management of content types” as shown below:

image

Figure 1: Enable content type management.

 

Once you have enabled the content type for a list you will find a available content types associated with the lists under ‘content types’ section of list settings page as shown below:

image

Figure 2: Content type management section in list settings page

 

Hide fields from add/edit/display form

Sometimes you may want to hide some fields from add/edit/display form. Scenario might be you don’t want users to edit the field directly, rather the hidden field’s data will be populated differently (maybe from event receiver or timer job). To do so click on the Content Type (usually Item) and then you will be landed in a page as shown below:

image

Figure 3: Item Content Type editing page

 

As you see from figure 3, the content type page is showing all my field but only Product Name (internally the field name is Title) is coming from Item content type. Other fields are added by myself. Now let’s say you want to hide the launchDate field from add/edit/view form. To do so click the field link ‘Launch Date’ and you will be taken to a page as shown below. From that page you can hide a field.

image

Figure 4: Hide fields if needed

 

For your information, the hidden field will not appear in add/edit/display from but you can still access the field in list views.

 

Reorder Fields in add/edit/display form

You can reorder how the fields will appear in the list add/edit/display from. To do so take a look a the figure 3. You will find a link “Column Reorder” at the bottom of the item. Click the link and you will be moved to a page as shown below where you can reorder the presence of the fields in add/edit/display form.

image

Figure 5: Reorder fields in add/edit/view forms

 

Want more customization?

If you are not even happy you can create your own custom add/edit/display from as described my another post. Also you can even edit the add/edit/display from in infopath. To do so open the site in IE browser and the navigate to list settings page. And then click “Form Settings” as shown below:

image

Figure 6: From settings option in list settings page.

 

Clicking on the form settings page, you will be navigated to a page as shown below:

image

Figure 7: Form settings page.

 

Clicking ok in the page as shown in figure 7, you will be asked to open the page in InfoPath editor as shown below. However you need to use IE browser to open the InfoPath editor directly from browser:

image

Figure 8: Edit form in InfoPath.

 

I’m not going to bring InfoPath in today’s discussion as this can be more complex. However If I get chance I’ll come back to you with a post on “how to use InfoPath to edit the form”.

Tuesday, June 14, 2011

SharePoint: Custom add/edit/display form for list

Sometimes we don’t want to use SharePoint’s custom add/edit/display form. We want our own custom form when user will try to view, edit or add an item. I’ll show you today how easily we can do so.
For this post I’ll consider I’ll have a list with three fields: Product Code, ProductName and ProductDescription. I’ll show how we can create a list with these two fields with custom add/edit/display form. The list’s fields are described in the table below:
Field name Field Type Comments
Product Code Text Title field will be used instead of creating a new one
Produce Name Text
Product Description Text
Table 1: Custom list template/Content Type’s fields

The first step of this approach is to create a content type with required fields associated with the content type. The noticeable point here is that In the content type declaration, we can define custom forms for add/edit/display.

Step 1: Create a content type for your list

To create content type right click on your project and click ‘add new item’ and then select content type as shown below:
image
Figure 1: Add content type

Next you will be prompted for the base content type as shown below: If you want to create a custom list, you can select Item as shown below:
image
Figure 2: ‘Item’ is the base content type for custom/generic list

Then you will have provided the content xml file. You need to modify the content type xml file as shown below. Please modify the Inherits=”False” from the content types.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!--Defined fields-->
  <Field ID="{30C3D21A-A7C9-410E-A896-82875475F697}" Name="ProductName"
         DisplayName="Product Name" Type="Text" Required="FALSE" >
  </Field>
  <Field ID="{9621763e-3494-4a86-a3eb-fd2593f1a1f1}" Name="ProductDescription"
         DisplayName="Product Description" Type="Text" >
  </Field>
  <!-- Parent ContentType: Item (0x01) -->
  <ContentType ID="0x0100c5e54b7f62ad451a92f9235d43ec9082"
               Name="ProductContentType"
               Group="Custom Content Types"
               Description="My Content Type"
               Inherits="false"
               Version="0">
    <FieldRefs>
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" 
                DisplayName="Product Code" Sealed="TRUE"/>
      <FieldRef ID="{82642ec8-ef9b-478f-acf9-31f7d45fbc31}" Name="LinkTitle" 
                DisplayName="Product Code" Sealed="TRUE"/>
      <FieldRef ID="{BC91A437-52E7-49E1-8C4E-4698904B2B6D}" Name="LinkTitleNoMenu" 
                DisplayName="Product Code" Sealed="TRUE" />
      <FieldRef ID="{30C3D21A-A7C9-410E-A896-82875475F697}" Name="ProductName" 
                DisplayName="Product Name" Required="False" />
      <FieldRef ID="{9621763e-3494-4a86-a3eb-fd2593f1a1f1}" Name="ProductDescription" 
                DisplayName="Product Description" Required="False" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
        <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
          <Display>_layouts/blogtest/Product.aspx?mode=display</Display>
          <Edit>_layouts/blogtest/Product.aspx?mode=edit</Edit>
          <New >_layouts/blogtest/Product.aspx?mode=new</New>
        </FormUrls>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>
Figure 3: Content Type xml file with fields and add/edit/display form declared

Now let’s explain what’s in the xml shown in figure 3.
  • Firstly I’ve modified Inherits to false in ConentType tag.
  • I’ve defined two fields inside the <Elements> tag that I’ve used later in content types
  • Then used those fields in <FieldRefs> of <ContentType> tags. These fields will be available in Content type. I’ve also used three existing fields (for Title) from base Content Type (Item).
  • Finally I’ve defined New, Edit and Display form for these content types in <XmlDocuments> section.


Step 2: Create a list Template based on Content type

Now you have defined content types with three fields. Next step is to define a list template based on the content type. To do so click add new item from visual studio context menu and select “List Definition From Content Type” as shown below:
image
Figure 4: Create list definition from content type in ‘Create new Item’ dialog.

Next you will be prompted for available  content types in the project as shown below. Remember to uncheck the button ‘Add a list instance for this list definition’ for this demo now.
image
Figure 5: Create list definition from Content Type

Now you will find two files Elements.xml and Schema.xml files are added. Our full focus will be now on Schema.xml.

Modify the content in <Fields> tag:
Ensure Title fields with display name ‘product code’ exists as shown below:
<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" DisplayName="Product Code" Sealed="TRUE" Type="Text" />

image
Figure 6: Add title field in the list template (if not exists)

Then find two fields LinkTitle and LinkTitleNoMenu. Then change their display name to ‘Product Code’ as shown below. These two fields are link to edit menu.
image
Figure 7: Rename the displayName for linkTitle and LinkTitleNoMenu field

Modify the content in <Views> tag
Open the views tag and add the fields you want to display in default view under <View> with Default value is true as shown below.
image
Figure 8: Define the fields to be shown in default view

 

 

Step 3: Create Custom add/edit/display form

Next step is to develop a custom application page to use for add/edit/display. As sown in figure 3, you can three different pages for add, edit and view. However for brevity I want to use a single page for all these three operations. You need to create an application page in appropriate location (in my case this is _layouts/blogtest folder). Rather than using three different files for add/edit/display, you can use a single page for all these three tasks as shown below:
<XmlDocuments>
  <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
    <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
      <Display>_layouts/blogtest/Product.aspx?mode=display</Display>
      <Edit>_layouts/blogtest/Product.aspx?mode=edit</Edit>
      <New >_layouts/blogtest/Product.aspx?mode=new</New>
    </FormUrls>
  </XmlDocument>
</XmlDocuments>

By passing different parameter to a single page we can identity the page’s mode (add, edit or view). Also SharePoint by default add the list and item id at the end of the page. So your page’s url will look like for new item:
_layouts/blogtest/Product.aspx?mode=new&List=LISTGUID&ID=ITEMID
So from the page (Product.aspx) you can identity the list id and item id from querystring.
I’m not showing details of the product.aspx page here.
You can download the full source code from this skydrive link.

How to use the project attached with this post?

  1. Download the code from here.
  2. Deploy the solution to a SharePoint site.
  3. Create a new list with “ProductListDefinition” template. This template will be installed in the site as you deploy the SharePoint solution.
  4. Now try to add/edit/view items in the list. You will find the custom form product.aspx is used for add/edit/view.

Hope some persons might find the post useful..

Tuesday, June 7, 2011

SharePoint: Disable Event Receiver From non-receiver code

When we are in List Item Event Receiver code, we can modify/update the same item which will fire the event receiver again. For disabling event receiver to get fired again we can use the property ‘’ as shown below:

public class TestEventReceiver:SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
//disable event receiver firing
EventFiringEnabled = false;


//do something



//enalbe event receiver firing
EventFiringEnabled = true;

}
}
Figure 1: Sample code to enable/disable event receiver firing inside event receiver handler.

However, if you are in a webpart and want to modify an item but don’t want to fire event receiver, then? Don’t worry there’s a way out. I’ll explain this today.

 

What happens when Event Receiver disabled?

When you disable event receiver, SharePoint internally set a data field in current Thread. So if you can set your current’s thread’s data to the required value before/after updating item, you can control the event receiver. However, setting current thread data manually might be risky and I’ll not use that path. Rather I’ll show how we can use existing power of ‘SPEventReceiverBase’ to control event receiver firing.

 

Create your own Event Receiver Controller

I’ve create a custom class inherited from ‘SPEventReceiverBase’. From this base class I get a properties ‘EventFiringEnabled’ which allows me to control the event receiver firing. The following code snippet shows my custom EventReceiverManager:

public class EventReceiverManager : SPEventReceiverBase, IDisposable
{
public EventReceiverManager(bool disableImmediately)
{
EventFiringEnabled = !disableImmediately;
}

public void StopEventReceiver()
{
EventFiringEnabled = false;
}
public void StartEventReceiver()
{
EventFiringEnabled = true;
}

public void Dispose()
{
EventFiringEnabled = true;
}
}
Figure 2: A EventReceiverManager custom class to control event receiver firing.

The code snippet above is derived from SharePoint’s SPEventReceiverBase to use the ‘EventFireingEnabled’ property.

 

Now you can use this EventReceiverManager to control the event receiver. To stop firing the event receiver on any changes, you need to wrap the code block inside EventReceiverManager as shown below:

using (var eventReceiverManager = new EventReceiverManager(true))
{
var list = GetList("listName");
var listItem = list.GetItemById(itemId);
listItem["field"] = "value";
listItem.Update();
}
Figure 3: How to use EventReceiverManager to disable event receiver firing.
 

As shown above even if he list has event receiver for ItemUpdated/ItemDating the event receiver will not get fired because of putting the code in EventReceiverManager block. Please notice of ‘using’ block, as soon as you leave the ‘using’ block, the event firing in enabled automatically. This is because in Dispose method of EventReceiverManager I’ve enabled the event firing.

Sunday, May 22, 2011

SharePoint 2010: Approve/Reject Multiple Items

You can approve/Reject an item from SharePoint ribbon. But only one item can be approved or rejected. But I’ve found requirements from few of my clients that they want to approve/reject in batch rather than one by one. This is logical. If there’s 100 of items to approve/reject, doing this one by one is tedious. In this post I’ve described  how I’ve implemented the idea and at the end of the blog you can find the link to download the source code.

 

My approach to allow multiple approve/reject in batch is following the steps:

  • Add a new ribbon “Approve/Reject Selection” as shown below. The new ribbon will be active when more than one item will be selected.
    image
    Figure 1: New ribbon “Approve/Reject Selection” added

  • When multiple item will be selected from grid the “Approve/Reject Selection” will be active as shown below:
    image
    Figure 2: “Approve/Reject Selection” will be active when multiple items will be selected

  • Clicking on “Approve/Reject Selection” will bring up a new custom window developed my me as shown below:
    image
    Figure 3: Approve/Reject Multiple items dialog

  • Finally, the custom dialog shown in figure 3, is an application page where we need to write code to approve/reject selected items programmatically.


So let’s start with the process of implementing the idea!!!!!!!!!!!

 

Step 1: Create a custom ribbon

First add a new empty element as shown below:

image

Figure 4: Add new empty element

 

Then add the following xml in the elements.xml file:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="COB.SharePoint.Ribbon.NewControlInExistingGroup"
Location="CommandUI.Ribbon.ListView"
RegistrationType="List"
RegistrationId="100">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListItem.Workflow.Controls._children">
<Button Id="COB.SharePoint.Ribbon.NewControlInExistingGroup.Notify"
Command="COB.Command.NewControlInExistingGroup.Notify"
Sequence="21"
Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png"
Image16by16Top="-48" Image16by16Left="-240"
Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png"
Image32by32Top="-448" Image32by32Left="-384"
Description="Uses the notification area to display a message."
LabelText="Approve/Reject Selection"
TemplateAlias="o1"/>
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler
Command="COB.Command.NewControlInExistingGroup.Notify"
EnabledScript="javascript:enableApprovalAll();"
CommandAction="javascript: showApproveAll(); "/>
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<CustomAction
Id="COB.Command.NewControlInExistingGroup.Notify.Script"
Location="ScriptLink"
ScriptSrc ="/_layouts/SharePoint.ApproveRejectTest/Scripts/ApproveReject.js"/>
</Elements>

Figure 5: Code snippet for Custom Ribbon

I’m not going to describe the code snippet at figure 5 elaborately. However the basic things are that, I’m adding a button with label “Approve/Reject Selection” and I’ve associated two commands with the button. One is when to enable/disable the button with CommandUIHandler’s EnableScript attribute. The buttton click event action is defined with CommandAction attribute. If you notice I’ve just mentioned two javascript function enableApproveAll and showApproveAll. These two functions are not defined in this xml. Rather they are defined in another file “/_layouts/SharePoint.ApproveRejectTest/Scripts/ApproveReject.js” which is referenced in xml file.

 

Step 2: Create the script file to show/hide approve/reject dialog

The content of the  ApproveReject.js file is show below. The command to show the approve/reject dialog is declared in this script. The function showApproveAll() will show a custom application page that I’ve described in step 3. The reference section in the file helps to get intellisense. I’ve not explained the script that much as it’s not in the scope of this post.

/// <reference path="/_layouts/MicrosoftAjax.js"/>
/// <reference path="/_layouts/SP.debug.js"/>
/// <reference path="/_layouts/SP.Core.debug.js"/>
/// <reference path="/_layouts/SP.Ribbon.debug.js"/>
/// <reference path="_layouts/SP.UI.Dialog.debug.js"/>

/// <reference path="/_layouts/actionmenu.js" />
/// <reference path="/_layouts/ajaxtoolkit.js" />
/// <reference path="/_layouts/CUI.debug.js" />
/// <reference path="/_layouts/portal.js" />
/// <reference path="/_layouts/SP.Exp.debug.js" />
/// <reference path="/_layouts/SP.Runtime.debug.js" />
/// <reference path="/_layouts/SP.UI.Dialog.debug.js" />

//used to show approve/reject dialog
function showApproveAll() {
var ctx = new SP.ClientContext.get_current();
var ItemIds = "";
//get current list id
var listId = SP.ListOperation.Selection.getSelectedList();
//get all selected list items
var selectedItems = SP.ListOperation.Selection.getSelectedItems(ctx);

//collect selected item ids
for (var i = 0; i < selectedItems.length; i++) {
ItemIds += selectedItems[i].id + ",";
}

//prepare cutom approval page with listid
//and selected item ids passed in querystring
var pageUrl = SP.Utilities.Utility.getLayoutsPageUrl(
'/SharePoint.ApproveRejectTest/ApproveAll.aspx?ids=' + ItemIds + '&listid=' + listId);
var options = SP.UI.$create_DialogOptions();
options.width = 420;
options.height = 250;
options.url = pageUrl;
options.dialogReturnValueCallback = Function.createDelegate(null, OnDialogClose);
SP.UI.ModalDialog.showModalDialog(options);
}

//used to determine whether the 'approve/reject selection'
//ribbon will be enalbed or disabled
function enableApprovalAll() {
var ctx = new SP.ClientContext.get_current();
return SP.ListOperation.Selection.getSelectedItems(ctx).length > 1;
}


//called on dialog closed
function OnDialogClose(result, target) {
//if ok button is clicked in dialog, reload the grid.
if (result == SP.UI.DialogResult.OK) {
location.reload(true);
}
}

 
Figure 6: ApproveReject.js  file
 
In the method showApproveAll, I’ve collected the selected Items’ IDs and passed to “ApproveAll.aspx” page as querystring. I’ve also passed the current list id in querystring.
 
 

Step 3: Create custom Approve/Reject application page

Finally I’ve developed a application page named as “ApproveAll.aspx”. The partial markup of the page is shown below:

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<script type="text/javascript">
   1:  
   2:         function closeDialog() {
   3:             SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
   4:         }
   5:         function finisheDialog() {
   6:             SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, 'Cancelled clicked');
   7:         }
   8:     
</script>
<h2 id="divMessage" runat="server">
</h2>
<table>
<tr>
<td>
Status:
</td>
<td>
<asp:DropDownList ID="ddlAprovalOptions" runat="server">
<asp:ListItem Text="Approve" Value="Approved" />
<asp:ListItem Text="Pending" Value="Pending" />
<asp:ListItem Text="Reject" Value="Denied" />
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
Comments:
</td>
<td>
<asp:TextBox ID="txtComments" runat="server" TextMode="MultiLine" Columns="40" Rows="5" MaxLength="255" />
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="btnSubmit" runat="server" Text="OK" OnClick="btnOk_Click" />
<input type="button" runat="server" id="btnCancel" value="Cancel" onclick="closeDialog()" />
</td>
</tr>
</table>
</asp:Content>

Figure 7: ApproveAll.aspx page’s markup

In the code behind of the page, you need to extract the list id and list item ids. Then you need to invoke a method like shown below to approve/reject items:

private void ApproveRejectItems(SPWeb web, string listId, SPModerationStatusType moderationStatusType, List<int> itemIDs)
{
web.AllowUnsafeUpdates = true;
SPList spList = web.Lists[new Guid(listId)];
foreach (var itemId in itemIDs)
{
SPListItem spListItem = spList.GetItemById(itemId);

//disable workflow
foreach (SPWorkflow workflow in spListItem.Workflows)
{
if (workflow.ParentAssociation.Id == spList.DefaultContentApprovalWorkflowId)
{
SPWorkflowManager.CancelWorkflow(workflow);
}
}

//update moderation status
spListItem.ModerationInformation.Comment = txtComments.Text;
spListItem.ModerationInformation.Status = moderationStatusType;
spListItem.Update();
}
}
Figure 8: Approve/Reject items

As shown in the code snippet in figure 8, first we need to make sure we disable content approval workflow, if exists. Then we can update the moderation status.

 

Download Source Code

You can download the code for this post from my MSDN code gallery http://archive.msdn.microsoft.com/SP2010ApproRejectExt. Then from download tab download the first file “SharePoint.ApproveRejectTest”.

Monday, April 25, 2011

SharePoint Development Environment: Virtual Machine Or Virtual Hard Disk (VHD) with Dual boot

It’s true that SharePoint team has made the SharePoint rich enough to be useful in any organization. But they have taken less care of developers (my personal opinion). Developing with SharePoint was really a nightmare in old days (in SharePoint 2007) and the situation has not been changed that much today. I reminisce the days back in 2008 when four members of our SharePoint team worked in a single SharePoint server by logging in remotely. When one developer needed to reset IIS he needed to to inform others either he may interrupt some others’ debugging session.

From that nightmare development experience of my first SharePoint project, I’ve come to a better place. Now I’ve Core I7, 8GB ram laptop. But I used to work in Virtual Machine till few months ago and I had got slower disk access in Virtual Machine. So compiling, debugging and deploying was relatively slow. I don’t want to install SharePoint in my laptops’ Windows 7 and I hope fewer (possibly fewest)  people want to do so.

I’ve personally found developers who are coming to SharePoint Development from Asp.net, has got it difficult to get used to this environmental complexity. Anyway I’ve come to know about Virtual Hard Disk (VHD) solution few months ago and I’ve found it really a healthy approach. Let’s dig it deeper.

SharePoint Development in Virtual Machine

If you use Virtual Machine or any other virtual solution, you will have to realize that you will not the full processing power of your computer in SharePoint development. Even if in my Core I7 with 8GB ram, I get the development in Virtual Machine slower. If you do a lot of debugging and deployment you may loose your patience soon. However the real benefits include you can save virtual machine state. You can backup your virtual machine and restore.

SharePoint Development with Virtual Hard Disk (VHD)

Though I knew the concept of  Virtual Hard Disk about a year about ago, I didn’t get interested about it till few months ago. Basically the concept if you will have a Hard Disk (virtual obviously) and you will mount that virtual disk as a drive in your computer. Then you will install OS in that drive and add that OS in boot menu in your computer. So you will have more than one operating system in your computer but the OS will be in Virtual Hard Disk (which is a .vhd file). I’m going to describe it in details:

Create and Initialize a Virtual Hard Disk

For your information, the following option for creating VHD file from “Computer Management” is only available in Windows Server 2008 R2 and Windows 7. I’ve not explored if the option shown below is available for other operating systems.

  1. Open the “Computer Management” from Administrator tools and right click on the “Disk Management” and click “Create VHD” as shown below:

    image
    Figure 1: Create VHD option in disk management

  2. Then in the New VHD window, enter appropriate value as shown below:

    image

    Figure 2: Create new VHD settings page

  3. After that you will find a new disk is added as shown below:

    image
    Figure 3 New disk created for VHD

  4. So you have found you new VHD as new disk but the disk need to initialized. To do right click on the new disk and click initialize as shown below:

    image
    Figure 4: Initialize Virtual Hard Disk

  5. However when you’ll try to initialize the disk you will prompted for partition style. Its recommended MBR as shown below:

    image
    Figure 5: Create MBR partition in new VHD

  6. After that you will find the disk (disk 1 in above figure) online. After that create a new volume in that virtual disk as shown below:

    image
    Figure 6: Create new sample volume in Virtual (but online) disk.

  7. In the “New Sample Volume Wizard”, you can go with default settings and finally you will get a new drive in your computer which is virtual.

 

Mount a VHD and Install OS

Once you have your Virtual Hard Disk (VHD) ready you can try to install an OS in the VHD. To do so insert a Bootable CD/DVD in the CD/DVD-ROM and reboot your computer. To boot from CD/DVD make sure boot from CD/DVD enabled. I had tried to install Windows Server 2008 R2 in VHD. The process is described below:

  1. First, let the OS to start from bootable disk. Then when the following window comes up, press Shift + F10 to bring command prompt.
    image

    Figure 7: Windows Server 2008 R2 installation window.

  2. When the command prompt comes up (after press Shift + F10), type diskpart and press enter. And then type list volume and press enter to see all volumes available.
    image
    Figure 8: Use diskpart command to list volumes.

  3. You will find from “list volume” command that your drive letter is shifted by a letter (so, C becomes D, D becomes E and so on). Now type Select vdisk file=”VhdFilePath” as shown in the image below:
    image
    Figure 9: Select VHD file command

  4. Now you have selected the vhd file and you need to attach the file. To do so, run the command “attach vdisk” as shown below
    image
    Figure 10: Attach Vdisk command

  5. You have selected vdisk and attached it. Now close the diskpart by typing Exit and then close the command prompt by typing exit again.
  6. Now you can click Next in the “Install Windows” wizard as shown in figure 7. As you have attached the vdisk in the system, Installer will show the vhd as an disk and you can then choose to install OS in that vhd disk.
  7. When the Installation options come to choose the drive where to install OS, you can choose the VHD mounted disk (as shown in the image below). However you may get an warning saying “Windows Cannot be installed…” if you select the VHD for installing OS. Ignore the warning and install the OS in the vhd mounted disk.
    image
    Figure 11: Select VHD disk to install OS

  8. And when the installation will be finished, you will find your another OS is added in your boot menu.

So the final output is a file (VHD file) which is used for dual boot. You can copy the vhd file and attach it to another pc.

 

Attach an Existing VHD to boot option

Now say you have a vhd file and you need to attach the vhd file in boot option in your pc. You can do so with command. Fortunately, there’s GUI tools available to edit boot loader options. One such tool I’ve used is EasyBCD. I’ve shown below how to add a VHD file in boot menu.

  1. Run EasyBCD and click “Add New Entry”.
  2. From the bottom click “Virtual Disk” tab and then select the vhd file from disk.
  3. Finally click “Add Entry” to add the entry in boot option.

The following image shows process in a glance:

image

Figure 12: Add VHD file in boot option with EasyBCD

 

Now when you will restart your pc, you will find the new newly added entry is in boot option. Be cautious while you edit your boot menu. Improper editing of boot menu may fail your booting system.

 

Conclusion

If you are working with SharePoint frequently (as I do), you need to care about every minutes you are loosing for working in Virtual Environment. Since few months ago I had used Virtual Environment in my powerful laptop (Core-i7, 8GB RAM). However, disk access in VM environment is slow and as Visual Studio performance is somehow related to disk access (as during build a lot of disk read/write access operations are performed) so finally performance was a major problem.

Now I’ve moved my work to VHD and I’ve two VHD files (one for SharePoint Foundation and another is for SharePoint Server). I’ve three OS in my boot options: Windows 7 (installed with my laptop), SharePoint Foundation and SharePoint Server. I can remove any boot option from my boot menu any time with EasyBCD. And most of all, with VHD option, I get the full power of my laptop. If you guys have doubt about VHD option, I’ll ask you to give VHD option a try and I do believe you will like it. You will have to like it. FYI, I’m not a marketing guy anyway so maybe it’s hard for me to convenience you.

Please post your feedback.