lunes, 10 de mayo de 2010

jquery, ajax, json y sharepoint

Una forma de implementar una llamada AJAX desde jquery dentro de nuestro entorno MOSS es a través de un httplander.

La llamada jquery va a enviar un conjunto de datos en formato JSON y va a recibir otros datos también en JSON, por lo que tendremos que serializar y deserializar este json en nuestro código servidor.

Vamos a intentar describir todo el procedimiento a partir de un ejemplo, este ejemplo será la implementación de un cascading dropdownlist, primero tendremos un dropdownlist que muestra un conjunto de categorias y al seleccionar una categoria concreta luego otro dropdownlist mostrará las subcategorias presentes para esa categoria. (Típico ejemplo) Todo esto lo haremos dentro de un user control.

1. User control (ascx)





A continuación se muestra el código jquery para hacer la llamad ajax a un web handler llamado FooHandler.ashx.

Veremos que este código JavaScript tiene dos partes una es el bind de la acción change y keyup al dropdownlist categorias y otra es la llamada ajax al web handler.



$(function() {
// DropDownLists
var $ddlCategories = $("#<%= DDLCategories.ClientID %>");
var $ddlSubCategories = $("#DDLSubCategories");

// Labels
var $LBSubCategories = $("#<%= LBSubCategories.ClientID %>");

$ddlCategories.focus();
$ddlCategories.bind("change keyup", function() {
if ($(this).val() != "0") {

loadSubCategoriesProducts($("#<%= DDLCategories.ClientID %> option:selected").val());
$LBSubCategories.fadeIn("slow");
$ddlSubCategories.fadeIn("slow");

} else {
// Hide the others dropdownlists and labels
$LBSubCategories.fadeOut("slow");
$ddlSubCategories.fadeOut("slow");
}
});

});

function loadSubCategoriesProducts(selectedItem) {
$.ajax({
type: "POST",
url: '_layouts/Handlers/FooHandler.ashx',
data: "{ method: 'GetSubCategories', ID: '" + selectedItem + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function(data) {
$("#DDLSubCategories").children().remove();
for (var i = 0; i < val =" data[i].Id;" text =" data[i].Title;">").val(val).html(text));
}
}
});
}



1.1 User control (code behind)

Nuestro user control en el code behind sólo tendrá la carga inicial de las categorias en el primer dropdown:

 


public class FOOCodeBehind: UserControl
{

#region Protected Fields

protected DropDownList DDLCategories;

#endregion

#region Overriden Methods

protected override void CreateChildControls()
{

base.CreateChildControls();

DDLCategories.DataSource = GetCategories();
DDLCategories.DataTextField = "Title";
DDLCategories.DataValueField = "Id";
DDLCategories.DataBind();

}

#endregion

#region Private Methods

private List GetCategories()
{
var categories = new List();

categories.Add(new Category("1", "Category1"));
categories.Add(new Category("2", "Category2"));
categories.Add(new Category("3", "Category3"));
categories.Add(new Category("4", "Category4"));

return categories;
}

#endregion
}



2. Ahora toca definir el handler que hemos llamado FooHandler.ashx. Como podéis observar en la llamada Ajax, esto en realidad es una página (.ashx) que esta dentro del folder Handlers que a la vez esta dentro del folder layouts del folder 12 de MOSS.

Esta página simplemente contendrá lo siguiente:



2.1 Code Behind Web Handler

Aquí necesitaremos implementar nuestro handler, este será una clase que derive de IHttpHandler e implemente el método ProcessRequest.
Este método comprobará si el content type recibido es de tipo json, y entonces deserializará lo que hemos recibido en el inputstream a un diccionario key, value, donde las claves son strings y los values objects.

Para eso hemos creado un extensión de object que serializa y deserializa json. Esta extensión en el código lo tenemos cuando hemos añadido la referencia Core.JSON, esta es una referencia propia, pero tranquilos que también añado el código:

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Core.JSON;

namespace MyHandlers
{
public class FooHandler: IHttpHandler
{

#region IHttpHandler Members

bool IHttpHandler.IsReusable
{
get { return true; }
}

void IHttpHandler.ProcessRequest(HttpContext context)
{
if (context.Request.ContentType.Contains("json"))
{
var inputStream = new System.IO.StreamReader(context.Request.InputStream);
var inputJson = inputStream.ReadToEnd();

var collectionJson = inputJson.ToObject>();

context.Response.Clear();
context.Response.ContentType = "application/json";

if (!string.IsNullOrEmpty(collectionJson["method"].ToString()))
{
var json = string.Empty;

switch (collectionJson["method"].ToString())
{
case "GetSubCategories":
json = GetSubCategories(collectionJson["id"].ToString());
break;
}

context.Response.Write(json);
}
}

}

#endregion

#region Private Methods

private string GetSubCategories(String id)
{
var subcategories = new List();

subcategories.Add(new SubCategory("1", "SubCategory 1"));
subcategories.Add(new SubCategory("2", "SubCategory 2"));
subcategories.Add(new SubCategory("3", "SubCategory 3"));
subcategories.Add(new SubCategory("4", "SubCategory 4"));

return subcategories.ToJSON();
}
}
}





3. Extension methods para serializar/deserializar JSON

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

namespace Core.JSON
{
public static class ojectExtensionJSON
{
public static string ToJSON(this object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}

public static string ToJSON(this object obj, int recursionLimit)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RecursionLimit = recursionLimit;
return serializer.Serialize(obj);
}

public static T ToObject(this string json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize(json);
}
}
}





No hay comentarios: