EndUserSharePoint 2010 » WCF Data Services http://www.endusersharepoint.com/EUSP2010 Just another WordPress weblog Fri, 27 Aug 2010 14:00:36 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 Client Side AJAX Applications in SharePoint 2010 – Part 7: Live Bindings http://www.endusersharepoint.com/EUSP2010/2010/07/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-7-live-bindings/ http://www.endusersharepoint.com/EUSP2010/2010/07/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-7-live-bindings/#comments Mon, 12 Jul 2010 14:00:48 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=979 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

ASP.Net AJAX Templating is a compelling new client side technology from Microsoft that allows developers to more quickly build responsive and maintainable AJAX applications.  Because ASP.Net AJAX Templating and SharePoint 2010 both support the oData protocol they are a powerful combination.  This post in the series will focus on saving data back to SharePoint using the ASP.Net AJAX templating live binding syntax.

One-Way, Two-Way, Live!

The read-only {{ [FieldName] }} type template syntax we’ve explored previously is far more maintainable than string concatenation, which is the primary alternative to converting JSON data into HTML.  But where ASPNet AJAX Templating really shines is in saving data back to SharePoint (or any oData provider for that matter).  The syntax is called live binding and it comes in two flavors: two-way, and one-way data binding.  We’ll explore two-way data binding first.

In order to implement two-way data binding we simply place an INPUT element on the page and set its value to { binding [FieldName] }.  When it renders, the templating engine will replace the binding syntax with the current JSON object, just as it did with one-way binding.  But now when the user changes the value, the templating engine will automatically update the in-memory JSON objects behind the scenes.

So if we replace the master-details popup we wrote previously with live bindings like this:

<div id="userStoryDetails" class="sys-template">
    <table class="ms-formtable" width="100%">
        <tr>
            <td class="ms-formlabel" width="190">Title:</td>
            <td class="ms-formbody">
              <input type="text" sys:value="{ binding Title }" />
            </td>
        </tr>
        ...

Then the user can change the title.  But it won’t be too impressive yet because they won’t see the results of their changes in the user story cards.  We can fix that by replacing the titles of the cards with the one-way live binding syntax:

<div class="userStoryTitle">
    { binding Title }
    <span class="userStoryButtons">
    ...

Note how the one-way live binding syntax above looks identical to the two-way binding syntax.  That’s because ASP.Net AJAX Templating automatically uses two-way binding when the binding is located in an input form element. 

Our popup now looks like this:

When we mouse out of any field with two way data binding any elements on the page with one-way binding automatically reflect the change.

Saving to SharePoint

What we have so far is nice, but as soon as the user refreshes the page the values are reverted.  That’s because we never saved the values back to SharePoint.  Fortunately this is extremely easy to do with a call to dataContext.saveChanges(). 

We want the save to occur when the user clicks the OK button.  Assuming we pass in the function onDialogClose to the dialogReturnValueCallback parameter when we called SP.UI.ModalDialog.showModalDialog, then our code would look like this:

function onDialogClose(dialogResult, returnValue) {
	if (dialogResult == SP.UI.DialogResult.OK) {
		dataContext.saveChanges();
	}
}

That’s it!  The value is saved back to SharePoint and when we refresh the page the value has been updated.  But what’s going on behind the scenes?

Batch Processing

If we open up Fiddler to watch the HTTP traffic and click OK, we’ll see a post to _vti_bin/ListData.svc/$batch.  The post data looks like this:

--batch_e9ea-1b95-0f95
Content-Type: multipart/mixed;boundary=changeset_973c-961a-5b1e

--changeset_973c-961a-5b1e
Content-Type: application/http
Content-Transfer-Encoding: binary

MERGE http://localhost/Demo/_vti_bin/ListData.svc/UserStories(12) HTTP/1.1
If-Match: W/"10"
Host: nic-lee7
Accept: application/json
Accept-Charset: utf-8
Content-Type: application/json;charset=utf-8

{
    "__metadata": {
    "uri":"http://localhost/Demo/_vti_bin/ListData.svc/UserStories(12)",
    "etag":"W/\"10\"",
    "type":"Microsoft.SharePoint.DataService.UserStoriesItem"
},
"ContentTypeID":"0x010800B0CD2DCB798D704EA602F275139B7056",
"Title":"Story #12 UPDATED!",
"Priority":{"__deferred":{"uri":"http://nic-lee7/Demo/_vti_bin/ListData.svc/UserStories(12)/Priority"}},
"PriorityValue":"(2) Normal",
...
}
 ...
--changeset_973c-961a-5b1e--
--batch_e9ea-1b95-0f95--

ASP.Net AJAX Templating has kept track of all changes to all JSON objects, and on the call to saveChanges() it’s batched them all up and sent them across the wire as one big JSON post.  This means we can write applications that are less chatty and more performant with absolutely no extra effort.  That’s powerful!

Reverting Changes

The only thing that really remains to complete our user story application is to revert changes if someone clicks Cancel.  Unfortunately there is no elegant way to accomplish this.  The best we can do is re-retrieve all data from the server with a call to dataView.fetchData().  So our final onCloseDialog looks like this:

function onDialogClose(dialogResult, returnValue) {
	if (dialogResult == SP.UI.DialogResult.OK) {
		dataContext.saveChanges();
	}
	if (dialogResult == SP.UI.DialogResult.cancel) {
		dataView.fetchData();
	}
}

Conclusion

So far we’ve seen that templating is a more maintainable approach to displaying multiple list items on a page.   And we’ve seen that the master-details feature simplifies the job of cleaning up the UI.  In this post we’ve seen that the live bindings feature allows us to save data back to SharePoint in batches with a small amount of effort.  Implementing this functionality by hand would otherwise have required far, far more code.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/07/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-7-live-bindings/feed/ 0
Client Side AJAX Applications in SharePoint 2010 – Part 6: Master-Details http://www.endusersharepoint.com/EUSP2010/2010/06/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-6-master-details/ http://www.endusersharepoint.com/EUSP2010/2010/06/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-6-master-details/#comments Tue, 29 Jun 2010 14:01:34 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=949 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

ASP.Net AJAX Templating is a compelling new client side technology from Microsoft that allows developers to more quickly build responsive and maintainable AJAX applications.  Because ASP.Net AJAX Templating and SharePoint 2010 both support the oData protocol they are a powerful combination.  This post in the series will focus on a particularly nice feature of ASP.Net AJAX Templating: master-details views.

Showing .selectedData

In order to show the currently selected item we will need some HTML that we can pop up that will bind to the currently selected list item.  Here’s the simplest possible example that will still work:

<div id="userStoryDetails" class="sys-template">{{ Title }}</div>

Notice the class of sys-template?  As mentioned in a previous post that class is required for any elements that a dataView attaches to.  It sets the element to display: none when the page is loaded, but the dataView sets it back to display: block when it renders.

Next, we’ll need a second dataView object that we’ll bind to the HTML above using the jQuery syntax:

detailsDataView = $("#userStoryDetails").dataView().get(0);

Note that we didn’t set the dataProvider or fetchOperation as we did for the main dataView.  The reason is that we will bind its data property to the main dataView’s selectedData property like this:

$create(Sys.Binding, {
	source: dataView,
	path: "selectedData",
	target: detailsDataView,
	targetProperty: "data"
});

selectedData is a special property on dataView that represents the currently selected item.  We’re pretty close to completing the master-details scenario.  The main item that remains is telling the master dataView when to update the selectedData.  We can accomplish this by simply adding sys:command="select" onto an element within the main dataView’s template.  Adding it to the button that opens the modal dialog is a logical location:

<a href="#" onclick="javascript:openDialog(); return false;" sys:command="select">
	<img src="/_layouts/images/edititem.gif" />
</a>

And now we’re in business:


Flushing out the Master’s Details

So far the details view is a bit sparse.  In the next article we will allow editing the fields of a particular user story and support saving it back to SharePoint.  For now, however, let’s add some additional read-only fields:

<div id="userStoryDetails" class="sys-template">
  <table class="ms-formtable" width="100%">
    <tr>
      <td class="ms-formlabel" width="190">Title:</td>
      <td class="ms-formbody">{{ Title }}</td>
    </tr>
    <tr>
      <td class="ms-formlabel" width="190">Points:</td>
      <td class="ms-formbody">{{ Points }}</td>
    </tr>
    <tr>
      <td colspan="2" nowrap>
        <span>Created at <span>
        <span>{{ String.format("{0:M/d/y h:m tt}", Created) }}</span>

        <input type="button" name="OK" value="OK" class="ms-ButtonHeightWidth"
          onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK); return false;" />
        <input type="button" name="Cancel" value="Cancel" class="ms-ButtonHeightWidth"
          onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel); return false;" />
      </td>
    </tr>
  </table>
</div>

There are two things to note about the details view above.  The first is that we can display fields like Points that are not displayed by the main dataView (assuming they exist in the list).  This works because the master dataView downloaded all fields off of the main list by default.  How to retrieve data from related lists will the topic of a future article.

The second item to note is how easily we can deal with dates and times.  String.format is a method provided by the AJAX Library that can format the dates provided by SharePoint exactly like the C# / VB format specifiers readers are likely used to.  Here’s what the new details view looks like:


Here is the source for the entire application so far

<%@ Assembly Name="PreDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a3e0ca56c5f97ba" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UserStories.aspx.cs" Inherits="PreDemo.Layouts.PreDemo.UserStories" DynamicMasterPageFile="~masterurl/default.master" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
	<STYLE type="text/css">
		.sys-template
		{
			display: none;
		}
		.userStoryBackground
		{
			background-image: url('Images/corkboard4.png');
			width: 100%;
			height: 600px;
			position: relative;
		}
		.userStoryCard
		{
			border: 1px solid #777777;
			width: 200px;
			cursor: move;
			background-image: url('Images/blankcard4.png');
			position: absolute;
		}
		.userStoryDescription
		{
			font-size: 13px;
			padding: 0px 5px 5px 5px;
		}
		.userStoryTitle
		{
			font-size: 15px;
			font-weight: bold;
			padding: 0px 0px 0px 0px;
			padding: 0px 5px 0px 5px;
		}
		.userStoryButtons
		{
			position: absolute;
			right: 0px;
			padding: 2px 2px 0 0;
		}
		.userStoryButtons img
		{
			border: 0 none;
		}
	</STYLE>

	<script
		src="../Scripts/jquery-ui-1.8.1.custom/js/jquery-1.4.2.min.js"
		type="text/javascript"></script>

	<script
		src="../Scripts/jquery-ui-1.8.1.custom/js/jquery-ui-1.8.1.custom.min.js"
		type="text/javascript"></script>

	<script
		src="../Scripts/MicrosoftAjax/jQueryStart.js"
		type="text/javascript"></script>

	<script
		src="../Scripts/MicrosoftAjax/MicrosoftAjax.js"
		type="text/javascript"></script>

	<script type="text/javascript">
		Sys.require([
			Sys.scripts.jQuery,
			Sys.components.dataView,
			Sys.components.openDataServiceProxy
			]);

		var dataView;
		var detailsDataView;
		var dataContext;
		var userStoryDetails;

		Sys.onReady(function () {
			userStoryDetails = document.getElementById('userStoryDetails');

			dataContext = Sys.create.openDataContext({
				serviceUri: "/Demo/_vti_bin/ListData.svc"
			});

			dataView = $("#userStories").dataView({
				dataProvider: dataContext,
				fetchOperation: "UserStories",
				fetchParameters: { orderby: 'Title' },
				autoFetch: "true",
				rendered: onRendered
			}).get(0);

			detailsDataView = $("#userStoryDetails").dataView().get(0);

			$create(Sys.Binding, {
				source: dataView,
				path: "selectedData",
				target: detailsDataView,
				targetProperty: "data"
			});
		});

		function onRendered() {
			$(".userStoryCard").draggable({
				stop: onDragStop
			});
		}

		function onDragStop(event, ui) {
			var userStoryCard = ui.helper[0];
			var selectedUserStoryJsonObject = dataView.findContext(userStoryCard).dataItem;

			var newX = ui.position.left;
			var newY = ui.position.top;

			Sys.Observer.setValue(selectedUserStoryJsonObject, "X", newX);
			Sys.Observer.setValue(selectedUserStoryJsonObject, "Y", newY);

			dataContext.saveChanges();
		}

		function openDialog() {
			var options = {
				html: userStoryDetails,
				width: 500,
				height: 200,
				title: "User Story",
				dialogReturnValueCallback: onDialogClose
			};
			SP.UI.ModalDialog.showModalDialog(options);
		}

		function onDialogClose(dialogResult, returnValue) {
			if (dialogResult == SP.UI.DialogResult.OK) {

			}
			if (dialogResult == SP.UI.DialogResult.cancel) {

			}
		}
	</script>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
	<div id="userStoryDetails" class="sys-template">
		<table class="ms-formtable" width="100%">
			<tr>
				<td class="ms-formlabel" width="190">Title:</td>
				<td class="ms-formbody">{{ Title }}</td>
			</tr>
			<tr>
				<td class="ms-formlabel" width="190">Points:</td>
				<td class="ms-formbody">{{ Points }}</td>
			</tr>
			<tr>
				<td colspan="2">
					<span>Created at <span>
					<span>{{ String.format("{0:M/d/y h:m tt}", Created) }}</span>
					<span>
					<input type="button" name="OK" value="OK"
						onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK); return false;" accesskey="O" class="ms-ButtonHeightWidth" target="_self" />
					<input type="button" name="Cancel" value="Cancel"
						onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked'); return false;" accesskey="C" class="ms-ButtonHeightWidth" target="_self" />
					</span>
				</td>
			</tr>
		</table>
	</div>

	<div id="userStories"
		class="sys-template userStoryBackground"
		xmlns:sys="javascript:Sys">

		<div class="userStoryCard"
			sys:style="{{ 'left: ' + X + 'px; top: ' + Y + 'px;'}}">

			<div class="userStoryTitle">
				{{ Title }}
				<span class="userStoryButtons">
					<a href="#" onclick="javascript:openDialog(); return false;" sys:command="select">
						<img src="/_layouts/images/edititem.gif" />
					</a>
				</span>
			</div>
			<div class="userStoryDescription"><div>{{ Description }}</div>
		</div>
	</div>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Pre Demo
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
Pre Demo
</asp:Content>

Summary

We’ve seen how to data bind a details dataView to the currently selected item of a master dataView and formatting options for different data types.  The next article in the series will update the detailsView to support editing list items.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/06/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-6-master-details/feed/ 0
Client Side AJAX Applications in SharePoint 2010 – Part 5: Modal Dialogs http://www.endusersharepoint.com/EUSP2010/2010/05/27/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-5-modal-dialogs/ http://www.endusersharepoint.com/EUSP2010/2010/05/27/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-5-modal-dialogs/#comments Thu, 27 May 2010 14:02:21 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=663 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

A significant portion of SharePoint 2010’s Web 2.0 look and feel derives from its use of modal popups.  This post deviates briefly from the ASP.Net AJAX Templating discussion to explore how to open remote pages as modal dialogs, how to open dialogs based on local HTML, and how to respond to OK or Cancel events.

Modaling to Another Page

To get started let’s throw an edit icon onto the index cards we’ve built previously that will open a modal dialog:

<div class="userStoryTitle">
    {{ Title }}
    <span class="userStoryButtons" sys:command="select">
        <a href="#" onclick="javascript:openDialog(); return false;">
            <img src="/_layouts/images/edititem.gif" />
        </a>
    </span>
</div>

There’s nothing fancy going on here yet, just a call to an as yet unimplemented openDialog() function.  The result looks like this:


To open an AJAX modal dialog in SharePoint 2010 either specify a remote page to open, or specify an HTML element in the page.  Opening a remote page is a little easier.  The openDialog() function would look like this:

function openDialog() {
	var options = {
		url: "../../Lists/User%20Stories/DispForm.aspx?Id=1",
		width: 800,
		height: 600,
		title: "User Story",
	};
	SP.UI.ModalDialog.showModalDialog(options);
}

Obviously hard coding an id in the url parameter isn’t exactly best practice, but it works for demonstration purposes.  The result looks like this:


This is a useful technique for opening existing SharePoint pages as in the example above or for opening pages as a dialog that a user might also navigate to directly.  However, in our application we want to edit information that is in-memory in the browser (which is where ASP.Net AJAX Templating stores its data).  The showModalDialog() function will support this scenario, but it’s slightly more complicated.

Modaling to Your Own Page

First we’ll need an HTML element that we’re going to pop up.  A first draft might looks like this:

<div id="userStoryDetails">
    Hello World!
</div>

Since the options parameter that we passed to showModalDialog() supports an ‘html’ parameter instead of a ‘url’ parameter it might seem like we could simply retrieve the userStoryDetails element inside of openDialog and pass that to options.  However, there’s a problem with this approach.  By default SharePoint’s showModalDialog() function will destroy the DOM element that are passed to it.  The result is that the dialog can be opened once, but it fails each subsequent time it is opened.

To avoid this behavior we can cache the DOM element in a global variable rather than keeping it as a local variable scoped at the function level.  The code to will look like this:

var userStoryDetails;

Sys.onReady(function () {
    userStoryDetails = document.getElementById("userStoryDetails");
    ...
});

function openDialog() {
    var options = {
        html: userStoryDetails,
        width: 600,
        height: 300,
        title: "User Story",
    };
    SP.UI.ModalDialog.showModalDialog(options);
}

With this code we can close and open the modal dialog multiple times.  The result looks like this:


The only thing we’re missing now is the ability to close the dialog and handle the results.

Goodbye World

Closing the dialog and handling results is also pretty simple.  It takes two steps.  First we’ll need to call commonModalDialogClose() in our popup code and next we’ll implement a callback method that SharePoint will call when the dialog has been closed. 

To call commonModalDialogClose() we can modify the code that we are going to pop up like this:

<div id="userStoryDetails">
  <input
    type="button"
    value="OK"
    onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, 'Ok clicked'); return false;"
    class="ms-ButtonHeightWidth"
    target="_self"
    />
  <input
    type="button"
    value="Cancel"
    onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancel clicked'); return false;"
    class="ms-ButtonHeightWidth"
    target="_self"
    />
</div>

Notice the first parmeter to commonModalDialogClose().  It’s a DialogResult.  This parameter is important because our callback method will need to differentiate the ways in which a user could close the dialog.  For instance when a user clicks the X in the upper right of the dialog SharePoint passes DialogResult.cancel for the first parameter. 

The second parameter to commonModalDialogClose() is simply passed through as the second parameter to our handler as we’ll see shortly.

To handle the results of closing the dialog we can pass a function to the dialogReturnValueCallback argument in the options parameter of showModalDialog.  The result would look like this:

function openDialog() {
	var options = {
		html: userStoryDetails,
		width: 800,
		height: 600,
		title: "User Story",
		dialogReturnValueCallback: onDialogClose
	};
	SP.UI.ModalDialog.showModalDialog(options);
}

function onDialogClose(dialogResult, returnValue) {
	if (dialogResult == SP.UI.DialogResult.OK) {
		alert('goodbye world!');
	}
	if (dialogResult == SP.UI.DialogResult.cancel) {
		alert(returnValue);
	}
}

And now we can open and close SharePoint modal dialogs and handle the results.  If needed there are other adjustments we can make to modal dialogs through the options parameter.  For instance X, Y, allowMaximize, showMaximized and showClose.  The documentation is sparse, but hopefully this page on MSDN will eventually be updated with more details.

Summary

This post should provide everything needed for opening dialogs that look like the ones SharePoint uses.  And more importantly it will provide a foundation for the next post in the series in which we will edit user story information using a master-details view inside of a modal popup.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/05/27/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-5-modal-dialogs/feed/ 7
Client Side AJAX Applications in SharePoint 2010 – Part 4: jQuery Integration and Persistence http://www.endusersharepoint.com/EUSP2010/2010/05/20/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-4-jquery-integration-and-persistence/ http://www.endusersharepoint.com/EUSP2010/2010/05/20/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-4-jquery-integration-and-persistence/#comments Thu, 20 May 2010 14:00:48 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=601 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

In parts one and two of this series I described how WCF Data Services in SharePoint 2010 exposes list data as both XML and JSON.  In part three, I showed how to set up ASP.Net AJAX Templating and how to write a simple application that displays a list of user story list items.

In this part of the series I’ll show how to integrate with jQuery to display the user stories as draggable index cards on a virtual cork board and how to persist the X and Y coordinates back to SharePoint.

Cards on a Corkboard

The first step in making our application a little more interesting is to set up some CSS styling in the PageHead (or better yet a separate .css file of course) to display the user stories as index cards.

<STYLE type="text/css">
  .sys-template
  {
    display: none;
  }
  .userStoryBackground
  {
    background-image: url('Images/corkboard.png');
  }
  .userStoryCard
  {
    border: 1px solid #777777;
    width: 200px;
    cursor: move;
    background-image: url('Images/blankcard.png');
  }
  .userStoryDescription
  {
    font-size: 13px;
    padding: 0px 5px 5px 5px;
  }
  .userStoryTitle
  {
    font-size: 15px;
    font-weight: bold;
    padding: 0px 0px 0px 0px;
    padding: 0px 5px 0px 5px;
  }
</STYLE>

And update the Main section use the styles:

<asp:content id="Main" contentplaceholderid="PlaceHolderMain" runat="server">
    <div id="userStories" class="sys-template userStoryBackground">
        <div class="userStoryCard">
            <div class="userStoryTitle">{{ Title }}</div>
            <div class="userStoryDescription"><div>{{ Description }}</div>
        </div>
    </div>
</asp:content>

The result looks like this:


Looks good, but we need to absolute position the cards to make them draggable.  First we add X and Y number fields to the User Stories list in SharePoint.  Next we set position to absolute in the CSS style.  Finally, we set the X and Y with the following:

<div id="userStories"
	class="sys-template userStoryBackground"
	xmlns:sys="javascript:Sys">

	<div class="userStoryCard"
		sys:style="{{ 'left: ' + X + 'px; top: ' + Y + 'px;'}}">

		<div class="userStoryTitle">{{ Title }}</div>
		<div class="userStoryDescription"><div>{{ Description }}</div>
	</div>
</div>

There are a couple of interesting things going on here.  First is the sys namespace declaration at the top and its use on the style attribute.  The reason you can’t just use a regular style attribute is that the DataView can’t natively replace certain HTML attributes (if you’re interested in why see this article by Bertrand La Roy).  The sys namespace allows the DataView to get around this HTML limitation.

The second interesting thing is the string concatenation inside of the style attribute’s binding expression.  You can put any JavaScript you like inside of the binding expression, which turns out to be a very powerful feature. 

Now, if we manually set X and Y values in SharePoint for a user story, its card shows in the right place. But we’re still missing the ability to drag cards.

Making Cards Draggable with jQuery

jQuery makes dragging ridiculously simple.  The first step is to download and reference the draggable jQuery UI pluggin (in my case jquery-ui-1.8.1.custom.min.js).  Next we’re supposed to call the draggable() function on the DOM elements we want to make draggable. 

This should be simple enough, but if we call draggable() from within the Sys.onReady function it won’t work.  The reason is that the ASP.Net AJAX Templating engine hasn’t had a chance to render the new DOM elements yet.  Fortunately the DataView has the JavaScript equivalent of an OnRendered event that you can tie into:

var dataContext;
var dataView;

Sys.onReady(function () {
    dataContext = Sys.create.openDataContext({
        '/PreDemo/_vti_bin/ListData.svc'
        );

    dataView = $("#userStories").dataView({
        dataProvider: dataContext,
        fetchOperation: "UserStories",
        fetchParameters: { orderby: 'Title' },
        autoFetch: "true",
        rendered: onRendered
    }).get(0);
});

function onRendered() {
    $(".userStoryCard").draggable();
}

Incidentally, you may have noticed that this code has been updated slightly from the code in part three.  The biggest change is that we are now using an openDataContext instead of an openDataServiceProxy.  The reason is that the openDataContext knows how to write data back to SharePoint (which we will be doing shortly).

But more importantly we can now drag user stories all over the page:


It’s pretty amazing what jQuery can do.  But we still have a problem.

Saving Non-Visible Properties

The problem is that every time we refresh the page the nice card layout disappears and everything goes back to being stacked one on top of the other in the upper left.  

One approach to saving the X and Y coordinates would be to use the live binding syntax that I’ll discuss in more detail in the next post.  However, for non-visible properties the more appropriate way is to manually edit the templating engine’s underlying, in-memory, JSON objects.  This will additionally give us a little more insight into what’s happening behind the scenes.

Step one is to register an “event” for when the user stops dragging a card.

function onRendered() {
    // from http://jqueryui.com/demos/draggable/
    $(".userstorycard").draggable({
        stop: onDragStop
    });
}

Once we wire that up the onDragStop() function is where all the interesting stuff happens:

function onDragStop(event, ui) {
    var userStoryCard = ui.helper[0];
    var selectedUserStoryJsonObject =
        dataView.findContext(userStoryCard).dataItem;

    var newX = ui.position.left;
    var newY = ui.position.top;

    Sys.Observer.setValue(selectedUserStoryJsonObject, "X", newX);
    Sys.Observer.setValue(selectedUserStoryJsonObject, "Y", newY);
    dataContext.saveChanges();
}

The first line gets the DOM element that the user just completed dragging (from jQuery UI). The second line retrieves the in-memory JSON object represented by that DOM element. The next couple of lines get the X and Y coordinates that the user story card was dragged to (relative to their parent DOM element).  Then something odd happens.

Sys.Observer.setValue looks so complicated. Why couldn’t we just call selectedUserStoryJsonObject.X = newX?  If we’d done that, the DataView wouldn’t know about the change we just made and dataContext.saveChanges() wouldn’t know to send anything back to the server.  

Sys.Observer.setValue notifies any interested parties that a value has been changed, in this case the DataView.  This notification technique enables a wonderful feature of ASP.Net AJAX Templating wherein the dataView batches up changes.  Specifically, if we watch what happens over the wire with Fiddler when we call dataContext.saveChanges() we’ll see that it only sends records that have changed back to SharePoint.  This feature can save a lot of network traffic and speed up the responsiveness of applications.

Now with this code in place, we can move user story cards around on the page and when we refresh the page or come back days later our layout has persisted back into SharePoint!

Conclusion

In this post I’ve shown how nicely ASP.Net AJAX Templating interacts with jQuery and how to directly modify in-memory JSON objects and send them back to SharePoint.  The application is beginning to look like a useful application.  And it’s remarkable how little code it’s taken.   In the next post in the series I’ll show how to do master-detail scenarios for editing user story cards.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/05/20/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-4-jquery-integration-and-persistence/feed/ 1
Client Side AJAX Applications in SharePoint 2010 – Part 3: ASP.Net AJAX Templating 101 http://www.endusersharepoint.com/EUSP2010/2010/05/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-3-asp-net-ajax-templating-101/ http://www.endusersharepoint.com/EUSP2010/2010/05/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-3-asp-net-ajax-templating-101/#comments Wed, 12 May 2010 14:00:13 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=588 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

As I’ve described in Part One and particularly Part Two of this series, WCF Data Services is an extremely compelling element of SharePoint 2010.  However, as powerful as it is, programming against it directly would still be somewhat painful.  Fortunately, a new related technology – ASP.Net AJAX Templating – integrates beautifully with WCF Data Services and allows for quickly building pretty, maintainable and responsive AJAX applications.

In this part in the series I’ll describe ASP.Net AJAX Templating, give a tutorial of building a simple application page in Visual Studio 2010, and then build out a very simple page using ASP.Net AJAX Templating that displays SharePoint 2010 list data exposed as JSON by WCF Data Services.

What Isn’t Templating?

It’s probably easier to describe ASP.Net AJAX Templating in terms of how you would solve a problem without the technology.  If SharePoint handed you an array of JSON objects in JavaScript today, how would you convert that into HTML? 

The most common answer seems to be JQuery .append()statements.  Probably something like this:

for (var i = 0; i < userStories.length; i++) {
$("#userStories").append("<div class='userStoryCard'>" +
userStories[i].Title + "</div>");
}

The problem with this type of solution, or really anything that doesn’t use a templating engine, is that it fails to cleanly separate presentation from data access logic.  In fact you’re likely to very quickly end up with a classic Active Server Pages style, non-maintainable mess.  It gets even messier when we try to address persisting data back to SharePoint (which I’ll address in the next post in the series).

The goal of Templating is to allow you to instead write something like this:

<div class="userStoryCard">{{ Title }}</div>

Nice and tidy.  Ideally templating provides a solution that:

  • Minimizes plumbing code
  • Cleanly separates presentation from data access logic
  • Simplifies saving data back to the server
  • And has no ViewState!

Past, Present and Future of ASP.Net AJAX Templating

If you’ve read Scott Guthrie’s recent blog post on the jQuery templating engine, or you’re having difficulty finding accurate documentation you may be wondering about how ASP.Net AJAX templating fits in with Microsoft’s vision of building client side AJAX applications.

First of all it used to live in the main ASP.Net AJAX project when it was in beta.  When ASP.Net AJAX 4.0 moved from beta to release, the templating JavaScript files were moved into the AJAX Control Toolkit CodePlex project (and the syntax changed slightly).  This is why most examples you’ll find on the Internet today are slightly out of date.

As far as the jQuery templating engine, according to Stephen Walther, the Project Manager of the ASP.Net MVC team they “won’t be investing into [ASP.Net AJAX Templating] in the future” because they will be focusing on the jQuery templating engine.  So why bother learning a technology that won’t be moving forward?  For one thing the jQuery templating engine is still extremely young (a prototype as of this writing) while ASP.Net AJAX Templating is released and ready to use in production today.  For another thing the syntaxes appear to be close enough that an upgrade won’t be a major undertaking (theoretically).

Visual Studio 2010 and SharePoint 2010

Before jumping right into templating let’s take a quick detour and give a tutorial of how to build an application page in Visual Studio 2010 that will provide a foundation for all of the future code in this series.  As I mentioned in part 1 you can reproduce everything in this series in a content editor web part.  However, Visual Studio provides better intellisense and debugging support, so everything going forward will be in an application page.

To build a simple application page in Visual Studio 2010 select “new project” and navigate to SharePoint then 2010 to select the template.  Notice the large number of SharePoint templates now out of the box in Visual Studio.  Select “Empty SharePoint Project”.


When you Click OK Visual Studio opens up the SharePoint Customization Wizard:


This screen asks you to select the site you’d like to use for debugging.  It’s asking because when you hit F5 (“Start Debugging”), Visual Studio 2010 will package up your wsp file, deploy it to the URL you enter here, attach to the w3wp process, and open a browser into SharePoint, and you’re immediately in debug mode!

If you aren’t deeply impressed then you probably haven’t developed much in WSS 3.0 – but trust me this saves us an enormous amount of effort.  While we won’t write any server side code in this series, it’s still extremely impressive how much work Microsoft has put into making SharePoint 2010 a first class citizen.

Once Visual Studio generates an initial project select Project -> Add New Item and select Application Page.


Visual Studio then generates a page that’s 100% ready to go including the correct Content controls for the SharePoint master page:

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ApplicationPage1.aspx.cs" Inherits="MyAppPage.Layouts.MyAppPage.ApplicationPage1" DynamicMasterPageFile="~masterurl/default.master" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">

</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
Hello World!
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Application Page
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
My Application Page
</asp:Content>

(“Hello World!” is custom).  Now if you hit F5 or click Build -> “Deploy Solution” then Visual Studio packages up the application page into a wsp file and deployes it out to SharePoint. And if you navigate to the application page (e.g. http://localhost/mysite/_layouts/MyAppPage/ApplicationPage1.aspx) then you should see something like this:


Impressed?  You really should be.  We didn’t write a line of verbose, duplicative, error prone CAML, didn’t have to write any DOS (or PowerShell) scripts, didn’t have to deploy to the GAC, we probably didn’t even notice that a feature.xml file was created behind the scenes. Yet already we’re deployed!

Installing ASP.Net AJAX Templating

ASP.Net AJAX Templating is a little tricky to install.  To get it first download the source version of the latest release of the AJAX Control Toolkit on CodePlex (it should look something like AjaxControlToolkit.Binary.NET4.zip).  Extract and build the project in Visual Studio (it has both Visual Studio 2008 and 2010 versions).  Then either copy the JavaScript files directly into the SharePoint layouts directory:

  • Copy
    • AjaxControlToolkit.Source\SampleWebSites\AjaxClientWebSite\Scripts; to
    • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ \14\TEMPLATE\LAYOUTS\Scripts
  • And
    • AjaxControlToolkit.Source\Client\MicrosoftAjax\Templates; to
    • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ \14\TEMPLATE\LAYOUTS\Scripts

Or better yet to do it the more correct and repeatable way, copy the files into a Scripts folder under Layouts in your Visual Studio project.

Show Me the Code

Once we’ve made the JavaScript files that we need available we can write the following, which is about the simplest templaing page you can write:

<asp:content id="PageHead" contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
<STYLE type="text/css">
.sys-template {
display: none;
}
</STYLE>

<script
src="../Scripts/MicrosoftAjax/jQueryStart.js"
type="text/javascript"></script>
<script
src="../Scripts/MicrosoftAjax/MicrosoftAjax.js"
type="text/javascript"></script>

<script type="text/javascript">
Sys.require([
Sys.components.dataView,
Sys.components.openDataServiceProxy
Sys.scripts.jQuery,
]);

Sys.onReady(function () {
var dataSource = $.openDataServiceProxy(
'/PreDemo/_vti_bin/ListData.svc'
);

$("#userStoriesList").dataView({
dataProvider: dataSource,
fetchOperation: "UserStories",
fetchParameters: { orderby: 'Title' },
autoFetch: "true"
});
});
</script>
</asp:content> 

<asp:content id="Main" contentplaceholderid="PlaceHolderMain" runat="server">
<ul id="userStoriesList" class="sys-template" >
<li>{{ Title }}</li>
</ul>
</asp:content>

Skip over the JavaScript for now and notice unordered list named userStoriesList in the Main content section.  Inside of the li elements is an interesting notation: {{ Title }}.  This specifies a binding to the Title field in a SharePoint ListItem.  We could also have put in “PriorityValue” or any of the other columns shown in Part 2, or we could also put in JavaScript like {{ String.format("{0:M/d/yyyy}", Modified) }}.

Now notice the script references in the PageHead.  The MicrosoftAjax.js reference gets us the core ASP.Net AJAX functionality.  And jQueryStart.js enables the Sys.require function which can import additional JavaScript dependencies.

So far we haven’t imported enough JavaScript files to provide templating capabilities.  It’s the Sys.require statement that brings in 1. the dataView object, which does the main templating work;  2. openDataServiceProxy that knows how to speak to SharePoint’s ADO.Net Data Services; and 3. jQuery.  If you watch the page load in FireBug you’ll notice that the Sys.require figures out which additional .js files are needed like MicrosoftAjaxTemplates.js and adds them in the correct order.  This approach ensures the page doesn’t pull more JavaScript than needed.

The real magic happens in Sys.onReady, whose function is called once the DOM is loaded.  The first thing it does is instantiate an openDataServiceProxy object which is responsible for communicating with an oData endpoint, in our case ADO.Net Data Services.

The second thing it does is instantiate a DataView object and associate it with the userStoriesList element.  The fetchOperation parameter tells it which list to retrieve ListItems from (the UserStories list in our case) and the fetchOperation parameter tells it how to sort, filter, or paginate the data.

After the DataView is instantiated (because autoFetch is set to true) the DataView retrieves JSON data from its dataProvider, and then duplicates the innerHtml of its associated DOM element for each row returned while replacing the binding syntax with real data.  Seems simple enough, but it gets sophisticated very quickly as we’ll see in future posts.

One last thing to notice is the sys-template class.  This is a pre-specified CSS class that ASP.Net AJAX sets to display: block when it is finished rendering.  It’s necessary to create a CSS class for sys-template with display: none so that end users don’t see your template code while the page is loading.

So now if you click Build -> Deploy Solution you should see something like this:


Summary

Certainly this could have been done much more easily with server side code.  But hang in there; this has a lot of potential.  For instance to what extent can we combine this with jQuery to make it pretty?  How do Data Contexts write data back to the server?  How do master detail views work? I’ll explore these questions in the next and future posts in the series.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/05/12/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-3-asp-net-ajax-templating-101/feed/ 3
Client Side AJAX Applications in SharePoint 2010 – Part 2: WCF Data Services http://www.endusersharepoint.com/EUSP2010/2010/04/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-2-wcf-data-services/ http://www.endusersharepoint.com/EUSP2010/2010/04/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-2-wcf-data-services/#comments Thu, 29 Apr 2010 14:00:59 +0000 Lee Richardson http://www.endusersharepoint.com/EUSP2010/?p=459 This entry is part of a series, Client Side AJAX Applications in SharePoint 2010»

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

As I mentioned in Part 1, WCF Data Services is one of the most compelling new features of SharePoint 2010 from a developer’s perspective.  In this post I’ll describe what it is and how it works.  I’ll leave implementing something with it using ASP.Net AJAX Templating to subsequent articles in the series.

Confused Yet?

The chances are good you’re familiar with the technology, but not with the name WCF Data Services.  The reason for the confusion is that there are currently four terms that all refer to essentially the same thing.  The technology debuted with the codename Astoria in 2007 – a term still in use today.  It launched as ADO.Net Data Services in December of 2007.  The name was changed to WCF Data Services in 2009.  And in March of this year Microsoft released a group of specifications collectively known as the Open Data Protocol, or oData, of which WCF Data Services is an implementation (for more detail on oData check out Scott Hanselman’s excellent podcast on the topic).

Unfortunately SharePoint 2010 doesn’t come with WCF Data Services out of the box.  But fortunately it’s free and easy to add: just download and install the Data Services Update for .NET Framework 3.5 SP1 (or ADO Data Services v1.5 if you’re still running SharePoint 2010 Beta).   You can confirm it’s installed on your server by navigating to http://[server]/[optional site]/_vti_bin/ListData.svc.  If it’s installed correctly you’ll see an ATOM feed of all of the lists you have permission to view.  The result will look like this:

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<service xml:base="http://localhost/mySite/_vti_bin/ListData.svc/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:app="http://www.w3.org/2007/app"
    xmlns="http://www.w3.org/2007/app">
  <workspace>
    <atom:title>Default</atom:title>
    <collection href="Iterations">
      <atom:title>Iterations</atom:title>
    </collection>
    <collection href="UserStories">
      <atom:title>UserStories</atom:title>
    </collection>
  </workspace>
</service>

Navigating a Sea of XML

By default WCF Data Services displays its data as ATOM feeds which include links to URL’s that can provide more data.  For instance the href=”UserStories” attribute shown above tells us that we can append “/UserStories” to the end of our existing URL to view list items in the User Stories list.  The result looks like this:

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<feed xml:base="http://localhost/mySite/_vti_bin/ListData.svc/"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="http://www.w3.org/2005/Atom">
  <title type="text">UserStories</title>
  <id>http://localhost/mySite/_vti_bin/ListData.svc/UserStories</id>
  <updated>2010-03-20T02:20:26Z</updated>
  <link rel="self" title="UserStories" href="UserStories" />
  <entry m:etag="W/&quot;3&quot;">
    <id>http://localhost/mySite/_vti_bin/ListData.svc/UserStories(2)</id>
    <title type="text">Do Something</title>
    <updated>2010-03-19T15:13:28-05:00</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="UserStoriesItem" href="UserStories(2)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Predecessors"
        type="application/atom+xml;type=feed"
        title="Predecessors"
        href="UserStories(2)/Predecessors" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Priority"
        type="application/atom+xml;type=entry"
        title="Priority"
        href="UserStories(2)/Priority" />
    <link
        rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Status"
        type="application/atom+xml;type=entry"
        title="Status"
        href="UserStories(2)/Status" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Iteration"
        type="application/atom+xml;type=entry"
        title="Iteration"
        href="UserStories(2)/Iteration" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments"
        type="application/atom+xml;type=feed"
        title="Attachments"
        href="UserStories(2)/Attachments" />
    <category
        term="Microsoft.SharePoint.DataService.UserStoriesItem"
        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ContentTypeID>0x01080070E2807D369BD94FBD6C057D3110E6D3</d:ContentTypeID>
        <d:Title>Do Something</d:Title>
        <d:PriorityValue>(2) Normal</d:PriorityValue>
        <d:StatusValue>Not Started</d:StatusValue>
        <d:Complete m:type="Edm.Double" m:null="true" />
        <d:AssignedToID m:type="Edm.Int32" m:null="true" />
        <d:TaskGroupID m:type="Edm.Int32" m:null="true" />
        <d:Description>&lt;div&gt;&lt;/div&gt;</d:Description>
        <d:StartDate m:type="Edm.DateTime">2010-02-20T00:00:00</d:StartDate>
        <d:DueDate m:type="Edm.DateTime" m:null="true" />
        <d:Points m:type="Edm.Double">3</d:Points>
        <d:IterationID m:type="Edm.Int32">3</d:IterationID>
        <d:ID m:type="Edm.Int32">2</d:ID>
        <d:ContentType>Task</d:ContentType>
        <d:Modified m:type="Edm.DateTime">2010-03-19T15:13:28</d:Modified>
        <d:Created m:type="Edm.DateTime">2010-02-20T15:32:26</d:Created>
        <d:CreatedByID m:type="Edm.Int32">1</d:CreatedByID>
        <d:ModifiedByID m:type="Edm.Int32">1</d:ModifiedByID>
        <d:Owshiddenversion m:type="Edm.Int32">3</d:Owshiddenversion>
        <d:Version>3.0</d:Version>
        <d:Path>/mySite/Lists/User Stories</d:Path>
      </m:properties>
    </content>
  </entry>
</feed>

That’s showing us that there is one list item in the list with a title of “Do Something” and among other things a Priority of “(2) Normal”.

If we had more list items we could retrieve the data in different ways by appending different query string parameters.  The most common operations are filtering, sorting, and paginating.  For example http://localhost/site/_vti_bin/ListData.svc/UserStories?$filter=(PriorityValue eq ‘(2) Normal’)&$orderby=Title will return list items whose priority is normal sorted by title. 

If you’re interested in details on the URL syntax you can read more about Query Expressions on MSDN.  However, more often than not you won’t be using URL’s directly.  For instance you could use the beta version of LINQPad which now supports querying WCF Data Services.


Or better yet, as we’ll see in future articles, ASP.Net AJAX 4 contains JavaScript objects that know how to query WCF Data Services natively.

WCF Data Services: More than Just XML

If thus far you’ve been turned off by all this XML, there’s some good news.  WCF Data Services exposes its data in other formats too.  For instance if you modify the HTTP header of your request you can retrieve all of the same data you’ve seen so far as JSON.  How do you modify the HTTP headers?  Microsoft has a tool called Fiddler that does just that.

If you’ve installed Fiddler you can open it from the add-in in your browser and navigate to the WCF Data Services URL for a list.  You can drag the last request to the Request Builder (ensure “Automatically Authenticate” is checked in options), and replace “Accept: */*” with “Accept application/json”. And if you click Execute you should see something like this:

{
"d" : {
"results": [
{
"__metadata": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)",
"etag": "W/\"3\"",
"type": "Microsoft.SharePoint.DataService.UserStoriesItem"
}, "ContentTypeID": "0x01080070E2807D369BD94FBD6C057D3110E6D3",
"Title": "Blah",
"Predecessors": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Predecessors"
}
}, "Priority": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Priority"
}
}, "PriorityValue": "(2) Normal", "Status": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Status"
}
}, "StatusValue": "Not Started",
"Complete": null,
"AssignedToID": null,
"TaskGroupID": null,
"Description": "<div></div>",
"StartDate": "\/Date(1266624000000)\/",
"DueDate": null,
"Points": 3,
"Iteration": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Iteration"
}
}, "IterationID": 3,
"ID": 2,
"ContentType": "Task",
"Modified": "\/Date(1269011608000)\/",
"Created": "\/Date(1266679946000)\/",
"CreatedByID": 1,
"ModifiedByID": 1,
"Owshiddenversion": 3,
"Version": "3.0",
"Attachments": {
"__deferred": {
"uri": "http://localhost/demoprep/_vti_bin/ListData.svc/UserStories(2)/Attachments"
}
}, "Path": "/demoprep/Lists/User Stories"
}
]
}
}


That’s SharePoint data as lightweight JavaScript Object Notation. Notice the etag for caching.  Cool.

But ListData.svc isn’t just for reading data. To experiment with it try deleting a list item. To do this in fiddler set the HTTP verb to “DELETE”, set the URL to a particular list item’s URL (e.g. http://localhost/site/_vti_bin/ListData.svc/UserStories(2) where 2 is the ID for a list item), leave Request Headers empty, and hit Execute. Refresh the list of items and it’s gone. Permanently. The item isn’t even in the recycle bin.

More than Just a Data Access Layer

So at this point you are undoubtedly concerned about security.  Who is keeping users out of sensitive data?  Who is keeping them from accidentally or even maliciously deleting data?  The good news is that SharePoint is without any additional effort on your part.

SharePoint handles the security for WCF Data Services the same way it does when users navigate through the web.  If a user doesn’t have access to a list then they won’t see links to it.  If they try to access the list anyway, they’ll get a 404.  If they modify the row level permissions for a list item to deny read permissions for a particular user, then WCF Data Services will omit that row when it returns its data.  And if they try to modify or delete a list item they don’t have permissions to, then SharePoint returns a 401 Unauthorized.

But WCF Data Services does even more than just security.  It also handles validation.  If a user tries to insert null into a required field, they get back an HTTP error code.  If they violate one of the SharePoint 2010’s new list level validation rules, they get back an HTTP error code.  If they try to violate SharePoint 2010’s wonderful new uniqueness constraint, they get an HTTP error code.

That’s powerful.  And that’s also a lot of code you don’t have to write – or maintain.

Summary

So far we’ve seen a behind-the-scenes view of a technology that enables some powerful client side AJAX applications in SharePoint 2010.  We haven’t seen anything beautiful yet (from an end user’s perspective) but we’ve set the scenes for writing responsive, pretty, web based applications that end users will love.  And that’s where ASP.Net AJAX Templating comes in – which, conveniently enough, happens to be the subject of the next post in this series.

Guest Author: Lee Richardson
http://rapidapplicationdevelopment.blogspot.com/

Lee Richardson is a Senior Software Engineer at Near Infinity Corporation, an enterprise software development and consulting services company based in Reston, Virginia. He is a Microsoft Certified Solution Developer (MCSD), a Project Management Professional (PMP), a Certified SCRUM master and has over ten years of experience consulting for the public and private sector. You can follow Lee on Twitter at @lprichar

]]>
http://www.endusersharepoint.com/EUSP2010/2010/04/29/client-side-ajax-applications-in-sharepoint-2010-%e2%80%93-part-2-wcf-data-services/feed/ 0