Lakkakula's Blog

June 26, 2009

Developing Web 2.0 Portal using Asp.Net MVC, Microsoft Ajax Client Templates and jQuery with drag and drop widget personalization – Part 2

Filed under: Ajax Client Templates, Asp.Net, Asp.Net MVC, jQuery, MVC — Venkata Uma lakkakula @ 6:46 pm

In this series:
1. Introduction
2. Part 1 – Portal Core Functionality
3. Part 2 – Drag and Drop Widget Personalization
4. Part 3 – Building Widget Gallery
5. Part 4 – Introduce Tabs and Users
6. Part 5 – Enhancements and Conclusion

Note: Check out the working portal at http://aspspider.info/lakkakula/local.aspx.

In my previous post I have explained how to design and re-use a widget-client-template. Also I have shown you, how to load the widget-body through declarative way of using jQuery and Microsoft Ajax. The advantage of using jQuery load method (GET) and asp.net MVC call over updatepanel/web forms is that, jQuery load method by-default uses GET method and asp.net MVC does not have viewstate, page load lifecycle and server control reconstruction overheads.

Moreover we are returning only the required html to render the widget body through a partial view unlike asp.net page. In asp.net, when you use updatepanel, even though it makes an async call to web server, entire page is posted back and all the response is sent to client and finally only the portion inside the updatepanel is re-rendered.

So our approach through jQuery load and asp.net MVC would definitely be faster and cleaner.

In this post we will examine how to provide drag and drop functionality to widgets. Drag and drop gives web pages dynamic behavior. Drag and drop is basically achieved through mousedown, mousemove and mouseup JavaScript events. There are several articles and libraries available out there on the web. You can read detailed explanation about drag and drop using plain-old javascript by Mark Kahn. Or just bing-it for Javascript Drag and Drop. Here is a list of some fo the javascript libraries: jquery, prototypejs, dojotoolkit, mootools, qooxdoo, Yahoo! User Interface Library (YUI), extjs, UIZE JavaScript Framework, openrico,mochikit, SproutCore, My Library, javascriptian’s ajax library

jQuery’s sortable found in UI library makes our life easier. Through this UI plug-in we can attach drag and drop to selected HTML element just by calling

    1         $("selector").sortable();

When attached, sortable can raise 12 events: start, sort, change, beforeStop, stop, update, receive, remove, over, out, activate, deactivate. Among these; we are interested only in two events: start and stop.

As we have arranged widgets (div tags) in 3 columns. We will be hooking sortable to each column and specify that items to drag are Widgets. Let us see how to do that just right here:

    1         $('.col').each(function() {     2             attachDragDrop($(this))     3         });

Above code calls attachDragDrop($(this)) for each column in our page

    1         function attachDragDrop(col) {     2             var all-cols = $('.col');     3             $('.col').sortable({     4                     connectWith: all-cols,     5                     items: '.widget:not(.ad-holder)',     6                     handle: 'h2',     7                     helper: 'original',     8                     placeholder: 'placeholder',     9             });    10         }

Then each column being hooked-up to sortable; is connected with all other columns;  in this line

    4 connectWith: all-cols,

Then we specify “items to drag” are widgets in this line

    5 items: '.widget:not(.ad-holder)'

One interesting thing to note here is :not(.ad-holder). This specifies that we want to enable dragging for all widgets but not for ad-holder div. Who calls it a web portal without an ad 😉 but the idea here is to demonstrate how to make some of the widgets non-dragable.

As you could guess “handle” specifies the handle for widget. i.e., the area where user can click and start dragging on a widget. Helper specifies the element to be used while dragging. Helper accepts two values, original and clone (by default it is original). We will go with original so that we can use this element in “start” event. Finally placeholder specifies a class name which defines how to display the place-holder area when user is moving the widget.

Time to talk about sortable events: event “start” is raised as soon as user click’s on the handle element and starts dragging. We will use this event to capture original element and re-set its width and also to set the height of placeholder element. As soon as user starts moving widget, sortable changes the position of the widget’s div element on screen thus by changing its width to fill out entire screen.

image001

Start event code:

    1         start: function(e, ui) {     2             ui.helper.css("width", ui.item.parent().outerWidth());     3             ui.placeholder.height(ui.item.height());     4         },

To avoid this we will capture helper element and re-set its width to original. First line in above code does exactly same. Second line specifies the height of the placeholder. Now we have nice moving widget

image003

Now that we have width problem fixed, let us move to “stop” event. We will use “stop” event to calculate new widget position, get the column where the widget is dropped and widget’s id for database update.

Stop event code:

    1         stop: function(e, ui) {     2             ui.item.css({ 'width': 'auto' }); // reset widget width     3             var position = ui.item.parent().children().index(ui.item); // get position of the widget     4             var col_id = ui.item.parents('.col:first').attr('id'); // get the column element where the widget is placed     5             var widget_id = ui.item.attr('id'); //get widget id     6             updateWidgetLocation(widget_id, col_id, position); //interface to update widget location on server     7         },     1         function updateWidgetLocation (widgetId, colId, position) {     2             //call to widget controller -> post method to update widget location     3         };

Above code is executed as soon as the user drops the widget in to new location in a column. What we do here is to get widget position, column-id and widget-id. Finally we make an ajax post call to widget controller to update the new widget location in the server.

Other widget status change events are, widget minimize, widget maximize, widget removed. These events can be directly hooked to the controls on the widget header and call appropriate action method inside widget controller to update the status in the server.

wiz_controls

    1         function removeWidget (ctrl) {     2             if (!confirm('Are you sure, you really want to remove this widget?')) return;     3             var widget = $(ctrl).parents('.widget:first');     4             widget.slideUp('fast'); //animation before removing widget from page.     5             var remove = function() { deleteWidget(widget) };     6             setTimeout(remove, 500);     7             //call to widget controller -> post method to update widget status     8         };     9    10         function deleteWidget(widget) {    11             $(widget).remove();    12         };    13    14         this.toggleWidget = function(ctrl) {    15             var widget = $(ctrl).parents('.widget:first');    16             widget.children('.widget-body:first').slideTogle('fast');    17             //call to widget controller -> post method to update widget status    18         };

In this post we have seen how to provide drag and drop functionality to widgets and interfaces to save widget status on server. In my next post we will examine how to build Widget Gallery. Trust me, its going to be interesting as I will cover some CSS stuff.
Shout it kick it on DotNetKicks.com

June 18, 2009

Developing Web 2.0 Portal using Asp.Net MVC, Microsoft Ajax Client Templates and jQuery with drag and drop widget personalization – Part 1

Filed under: Ajax Client Templates, Asp.Net, Asp.Net MVC, jQuery, MVC — Venkata Uma lakkakula @ 2:35 pm

Note: Check out the working portal at http://aspspider.info/lakkakula/local.aspx.

In this series:
1. Introduction
2. Part 1 – Portal Core Functionality
3. Part 2 – Drag and Drop Widget Personalization
4. Part 3 – Building Widget Gallery
5. Part 4 – Introduce Tabs and Users
6. Part 5 – Enhancements and Conclusion

Where do we start? Well, I prefer to start with database. Portal database-design itself is very simple. We need to have containers for Widgets (basic building blocks of the portal), Tabs (logical grouping of Widgets) and Users (so that we can assign Widgets to users through tabs). Below is a simple relational diagram between these entities.

Each Widget is derived from WidgetBase and is associated to Tab. Users will have access to one or more Tabs.

linksgrid_db

This design is self explanatory, we will use WidgetBase table to store and display widget gallery something similar like this: (courtesy netvibes.com). We will implement this some time later

wiz_list.png.

Once we have the database ready, its time to build core functionality of the portal, which is “to display widgets from list of widgets on a web page”. Let us just do that right here. We will then introduce widget gallery, tabs and finally users.

This is what we will do here. First; get the list of widgets in JSON format to client, second; design a widget client template and finally bind JSON to widget client template.

Getting the list of widgets in JSON format to client:

  • Client Code
var widgets = [];
$(function() {
$.getJSON('Local/WidgetList', null, function(json) {
            Sys.Observer.addRange(widgets, json);
        });
});

When the page is loaded first time, above code makes a call to WidgetList action method inside Local controller. Once the call completes, the resulting JSON will be assigned to widgets[]array.

Below is the sample JSON returned to client

{ id = 4, col = "col1", order = 1, domain = "http://yelp.com", title = "Local Reviews", minimize = false, showsetup = true, controller = "Reviews", action = "Index", footerlink = "footer-link" ... }
{ id = 5, col = "col1", order = 2, domain = "http://wikihow.com", title = "Wiki - How To", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
{ id = 6, col = "col1", order = 3, domain = "http://cnn.com", title = "CNN.com", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
{ id = 7, col = "col2", order = 1, domain = "http://yahooapis.com", title = "Weather", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
{ id = 11, col = "col2", order = 2, domain = "http://flickr.com", title = "Flickr", minimize = false, showsetup = true, controller = "Flickr", action = "Index", footerlink = "footer-link" ... }
{ id = 8, col = "col2", order = 3, domain = "http://bbc.co.uk", title = "BBC News", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
{ id = 10, col = "col3", order = 1, domain = "http://topix.com", title = "Topix", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
{ id = 9, col = "col3", order = 2, domain = "http://google.com", title = "Google News", minimize = false, showsetup = true, controller = "Feed", action = "Index", footerlink = "footer-link" ... }
  • Server Code
public class LocalController : Controller    {
        IWidget repoWidget;

        // Dependency Injection enabled constructors
        public LocalController() : this(new WidgetRepository()) { }
        public LocalController(IWidget repo) {
            repoWidget = repo;
        }

        public JsonResult WidgetList(){
            var wiz = repoWidget.WidgetList();
            return Json(wiz);
        }
}

Only interesting thing to note here is that we are returning the results in JSON format as the action method WidgetList() is declared to return JsonResult.  The line

var wiz = repoWidget.WidgetList();

returns a list of widgets. And then next line

return Json(wiz);

converts the results to JSON format which then be sent to client.

Designing widget client template:
This actually is a widget container template, original widget will be returned by server through an ajax call. This is explained below on how to do it through declarative jQuery.

<div id="widget-template" class="sys-template">
     <div code:if="col==$element.id" id="{{'widget-' + id}}" class="widget">
          <div class="widget-header">
              <div class="widget-controls hide-controls">
                  <button class="widget-ctrl ctrl-setup" type="button"></button>
                  <button class="widget-ctrl ctrl-refresh" type="button" onclick="{{'return $.ajaxUtil.navigate(this, \'widget-content\',\'' + controller + '/' + action + '/' + id + '\');'}}"></button>
                  <button class="widget-ctrl ctrl-collapse" type="button" onclick="linksgrid.toggleWidget(this);"></button>
                  <button class="widget-ctrl ctrl-close" type="button" onclick="linksgrid.removeWidget(this)"></button>
              </div>
              <a sys:href="{{domain}}" target="_blank"><img sys:src="{{domain + '/favicon.ico'}}" style="height:16px; width:16px; padding-right:5px; vertical-align:middle; float:left;" /></a>
              <h2>{{title}}</h2>
              <div class="wiz-head-sep"></div>
          </div>
          <div class="widget-body" id="{{'widtet' + id + 'body'}}">
                <div id="{{'widget-' + id + '-content'}}" class="widget-content" sys:attach="ajaxload" ajaxload:url="{{'' + controller + '/' + action + '/' + id}}">
                       <div style="text-align: center; padding: 20px; margin: 5px;"><img src="/Content/images/loading.gif" alt="loading widget" /></div>
                </div>
          </div>
          <div class="widget-footer" id="{{'widget-' + id + '-footer'}}">
                 <a href="#">{{footerlink}}</a>
          </div>
     </div>
</div>

Widget Container:

widget-container

Points to note in above Client Template are

1. the line here <div id=”{{‘widget-‘ + id + ‘-content’}}” class=”widget-content” sys:attach=”ajaxload” ajaxload:url=”{{” + controller + ‘/’ + action + ‘/’ + id}}”> is of special interest. This line of code is using declarative way of specifying jQuery load method. You can read about this on Brian J. Cardiff’s blog. And also on Bertrand Le Roy’s blog. Bertrand is the brains behind Microsoft Ajax Client Templates, I suggest following his blog for up-to-date news.
The idea here is to make an ajax (get) call to specified action in the specified controller with any query parameters. Once the call is made; the resulting html will be placed inside widget container.

Here is the declarative jQuery code for your reference:

/*
* jQuery Declarative plug-in 0.1 (3/12/2008)

*
* Copyright (c) 2008
* Brian J. Cardiff – http://weblogs.manas.com.ar/bcardiff/
*
* Built upon
* jQuery 1.2.6 (http://jquery.com)

* Microsoft Ajax (MicrosoftAjax.js)
* Microsoft Ajax Templates (MicrosoftAjaxTemplates.js)
*
*/
(function($) {

Type.registerNamespace(“jQueryDeclarative”);

var template = “jQueryDeclarative.{0} = function(element) {{ jQueryDeclarative.{0}.initializeBase(this, [element]); }}; jQueryDeclarative.{0}.prototype = {{ initialize: function() {{ jQueryDeclarative.{0}.callBaseMethod(this, ‘initialize’); jQuery(this.get_element()).{0}(this); }}, dispose: function() {{ jQueryDeclarative.{0}.callBaseMethod(this, ‘dispose’); }} }}; jQueryDeclarative.{0}.registerClass(‘jQueryDeclarative.{0}’, Sys.UI.Behavior); if (typeof (Sys) !== ‘undefined’) Sys.Application.notifyScriptLoaded();”;

function $declare(functionName) {
eval(String.format(template, functionName));
$(‘body’).attr(‘xmlns:’ + functionName.toLowerCase(), ‘javascript:jQueryDeclarative.’ + functionName);

}

$.extend({ declare: $declare });

})(jQuery);

widget

2. Notice that eventhough the template is assigned to the class=”sys-template” , it is not bound yet. We will do that in next step.

Reusing widget client template

<div id=”col1″ class=”col” sys:attach=”dataview” dataview:data=”{{ widgets }}” dataview:itemtemplate=”widget-template”></div>
<div id=”col2″ class=”col” sys:attach=”dataview” dataview:data=”{{ widgets }}” dataview:itemtemplate=”widget-template”></div>
<div id=”col3″ class=”col” sys:attach=”dataview” dataview:data=”{{ widgets }}” dataview:itemtemplate=”widget-template”></div>

These above div tags are actually binding JSON array to widget client template.

One important thing to note in above code is the line <div code:if=”col==$element.id” id=”{{‘widget-‘ + id}}” class=”widget”>. This ensures that only the associated widgets are placed in correct columns. In other words, all widgets associated to Col1 are placed in Col1 DIV tag, Col2 widgtes are placed in Col2 DIV tag and hence forth.

In my next blog post, I will walk you through on how to provide drag and drop functionality to widgets and prepare interfaces for storing widget location and status in the server.

Shout it

kick it on DotNetKicks.com

/*
* jQuery Declarative plug-in 0.1 (3/12/2008)
*
* Copyright (c) 2008
* Brian J. Cardiff – http://weblogs.manas.com.ar/bcardiff/
*
* Built upon
* jQuery 1.2.6 (http://jquery.com)

* Microsoft Ajax (MicrosoftAjax.js)
* Microsoft Ajax Templates (MicrosoftAjaxTemplates.js)
*
*/
(function($) {

Type.registerNamespace(“jQueryDeclarative”);

var template = “jQueryDeclarative.{0} = function(element) {{ jQueryDeclarative.{0}.initializeBase(this, [element]); }}; jQueryDeclarative.{0}.prototype = {{ initialize: function() {{ jQueryDeclarative.{0}.callBaseMethod(this, ‘initialize’); jQuery(this.get_element()).{0}(this); }}, dispose: function() {{ jQueryDeclarative.{0}.callBaseMethod(this, ‘dispose’); }} }}; jQueryDeclarative.{0}.registerClass(‘jQueryDeclarative.{0}’, Sys.UI.Behavior); if (typeof (Sys) !== ‘undefined’) Sys.Application.notifyScriptLoaded();”;

function $declare(functionName) {
eval(String.format(template, functionName));
$(‘body’).attr(‘xmlns:’ + functionName.toLowerCase(), ‘javascript:jQueryDeclarative.’ + functionName);

}

$.extend({ declare: $declare });

})(jQuery);

June 15, 2009

Web 2.0 Portal using Asp.Net MVC, Microsoft Ajax Client Templates and jQuery with drag and drop widget personalization

Filed under: Ajax Client Templates, Asp.Net, Asp.Net MVC, jQuery, MVC — Venkata Uma lakkakula @ 12:38 am

A few years back when I saw web 2.0 Ajax start pages like netvibes I was fascinated by the Ajax capabilities and coolness in dynamic web portals. As an enthusiastic Asp.Net developer I always wanted to develop my own Ajax Portal. While searching on web I came across several implementations and samples. Two of those samples are worth mentioning here. First one is from DHTML Goodies and other is from Omar Al Zabir. First one is mostly developed using plain old javascript, thus making it fairly complex to code and maintain. Though it lacks database implementation it can be added easily and server side php code can be replaced by Asp.Net webservices or page-methods. Later one is developed using cutting edge Asp.Net technologies, Omar did an excellent job implementing an Ajax web 2.0 portal using Asp.Net, you can read about it on Omar’s blog. As this implementation uses Asp.Net update panels it can not be treated as pure Ajax solution.

Here I will walk you through my lightweight and robust implementation of Web 2.0 Portal using Asp.Net MVC, Microsoft Ajax Client Templates and jQuery with drag and drop widget personalization. jQuery and Microsoft Ajax Client Templates makes client side programming extremely easy.

In coming weeks I will be blogging on how to develop this portal. Below is an image of the portal end state. You can access this portal at http://aspspider.info/lakkakula/local.aspx (note that the portal is partially implemented, I will continue to work on it as I blog in coming weeks).

In this series:
1. Introduction
2. Part 1 – Portal Core Functionality
3. Part 2 – Drag and Drop Widget Personalization
4. Part 3 – Building Widget Gallery
5. Part 4 – Introduce Tabs and Users
6. Part 5 – Enhancements and Conclusion

Shout it

kick it on DotNetKicks.com

lg_small


Blog at WordPress.com.