Lakkakula's Blog

January 2, 2011

2010 in review

Filed under: Uncategorized — Venkata Uma lakkakula @ 10:09 am

The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads Wow.

Crunchy numbers

Featured image

The average container ship can carry about 4,500 containers. This blog was viewed about 21,000 times in 2010. If each view were a shipping container, your blog would have filled about 5 fully loaded ships.

In 2010, there was 1 new post, growing the total archive of this blog to 7 posts.

The busiest day of the year was September 15th with 1 views. The most popular post that day was Google instant? Big deal! check out Bing Instant..

Where did they come from?

The top referring sites in 2010 were aspspider.ws, aspspider.info, code.google.com, stackoverflow.com, and forums.asp.net.

Some visitors came searching, mostly for lakkakula, linksgrid, mvc portal, asp.net mvc widgets, and asp.net mvc drag and drop.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Google instant? Big deal! check out Bing Instant. September 2010
24 comments and 3 Likes on WordPress.com

2

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

3

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

4

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

5

Linksgrid – Enhancements and Conclusion September 2009
6 comments

Advertisement

September 20, 2009

Linksgrid – Enhancements and Conclusion

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

As with any software product there is always scope for enhancements, linksgrid is no exception. What I tried to do here is to show a different approach for developing Web 2.0 portal with dynamic content loading and user personalization. I also tried to achieve balance between complexity of coding and ease of implementation. Asp.net MVC , Ajax Client Templates and jQuery brings this balance very well by drastically improving productivity of client side programming which is rather complex when written in conventional plain old javascript. Asp.net MVC’s RESTful url based services enhances ease of implementation of AJAX.

If you followed this series from the beginning you might have noticed that, I incrementally added features to the portal. The first enhancement I would do is to clean up javascript framework and improve initial page load behavior. For example the current implementation doesn’t load any JSON on first call to the server, then multiple subsequent calls are made to load widget-list, tab-list, gallery-list etc., All these can be combined into one single JSON object and can be returned on the first call itself. This will improve a little bit of performance as it reduces number of calls to server.

I encourage you to download the latest code and play with it. If you find any problem or have a question, please use http://code.google.com/p/linksgrid/issues/list to post your issues; you are welcome to post a comment in this blog also.

If you find this project helped in one or other way please let me know… I will list your implementation in this blog.

Finally, most important… If any one of you fixed any problem or added a cool new feature to linksgrid, please share code with me.

I wish you enjoyed this series as much as I enjoyed writing and sharing my ideas with you on the project.

Thanks for the support and encouragement I got from you all.

September 9, 2009

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

Filed under: Ajax Client Templates, Asp.Net, Asp.Net MVC, jQuery, MVC, OpenID — Tags: — Venkata Uma lakkakula @ 7:43 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

Working portal at: http://aspspider.info/lakkakula/local.aspx

Alright, finally I’ve got some time to write about users and tabs. In previous posts we have seen the core functionality of the portal which is to load widgets through ajax calls and displaying widget gallery. Once we have the core functionality ready, its time to tie it to Users and Tabs. Talking about users, it is typical to implement forms based authentication  for public web sites. When it comes to asp.net or asp.net MVC the natural way is to go through Membership, Role and Profile “Providers“. Let us do it something different here, the latest buzz is “Open ID“, so why not implement it?

Guest User Screenshot

lg-guest

Authenticated user screen-shot

lg-auth

This is what we will do here:lg-flow

To keep things simple, we will not be storing guest user’s activity, such as new widget creation, widget location move etc. For the logged in users we will allow to create new tabs, add widgets, move widgets and delete widgets.

Now for some code: Open ID implementation is straight forward, you can download samples from dotnetopenid project site. What I want to show is, generally after authentication we would be interested to know more about the user such as email, full name etc. DotnetOpenId library has an response extension method which will pull this extra information for us. (note: the extra user information depends on the actual open id provider, in other words its not guaranteed that we will always get response for extra user info.)  Here is the simple implementation of authentication:

[ValidateInput(false)]
public ActionResult Authenticate()
{
var openid = new OpenIdRelyingParty();
var response = openid.GetResponse();
if (response == null)
{
// Stage 2: user submitting Identifier
/*var req = openid.CreateRequest(Request.Form["openid_identifier"]);
var fields = new DotNetOpenAuth.OpenId.Extensions.SimpleRegistration.ClaimsRequest();// .SimpleRegistrationRequestFields();
fields.Email = DotNetOpenAuth.OpenId.Extensions.SimpleRegistration.ClaimsRequest;
fields.Nickname = DotNetOpenId.Extensions.SimpleRegistrationRequest.Request;
fields. .AddToRequest(req);
req.RedirectToProvider(); */
Identifier id;
if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
{
try
{
//return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
var request = openid.CreateRequest(Request.Form["openid_identifier"]);

request.AddExtension(new ClaimsRequest
{
BirthDate = DemandLevel.Request,
Country = DemandLevel.Request,
Email = DemandLevel.Require,
FullName = DemandLevel.Request,
Gender = DemandLevel.Request,
Language = DemandLevel.Request,
Nickname = DemandLevel.Request,
PostalCode = DemandLevel.Request,
TimeZone = DemandLevel.Request
});

return request.RedirectingResponse.AsActionResult();

}
catch (ProtocolException ex)
{
ViewData[“Message”] = ex.Message;
return RedirectToAction(“Index”, “Home”);
}
}
else
{
ViewData[“Message”] = “Invalid identifier”;
return RedirectToAction(“Index”, “Home”);
}
}
else
{
var res = response.GetUntrustedExtension<ClaimsResponse>();
//var res = response.GetExtension<ClaimsResponse>();
// Stage 3: OpenID Provider sending assertion response
switch (response.Status)
{
case AuthenticationStatus.Authenticated:
var name = response.ClaimedIdentifier.ToString();

if (res != null && res.Nickname != null)
Session[“FriendlyIdentifier”] = res.Nickname;
else if(res!=null && res.Email!=null)
Session[“FriendlyIdentifier”] = res.Email;
else
Session[“FriendlyIdentifier”] = name;

//user setup
using (LinksgridDataContext db = new LinksgridDataContext())
{
var userId = (from u in db.LGUsers
where u.Name == name
select u.Id).SingleOrDefault();
if (userId <= 0)
{
LGUser newUser = new LGUser();
newUser.Name = name;

newUser.BirthDate = res.BirthDate.ToString();
newUser.Country = res.Country;
newUser.Email = res.Email;
newUser.FullName = res.FullName;
newUser.Gender = res.Gender==null?string.Empty:res.Gender.Value.ToString();
newUser.Language = res.Language;
newUser.Nickname = res.Nickname;
newUser.PostalCode = res.PostalCode;
newUser.TimeZone = res.TimeZone;

db.LGUsers.InsertOnSubmit(newUser);

db.SubmitChanges();

repoWidget.NewUserSetup(newUser.Id);

}

}

FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
return RedirectToAction(“Index”, “Home”);
case AuthenticationStatus.Canceled:
ViewData[“Message”] = “Canceled at provider”;
return RedirectToAction(“Index”, “Home”);
case AuthenticationStatus.Failed:
ViewData[“Message”] = response.Exception.Message;
return RedirectToAction(“Index”, “Home”);
}
}
return new EmptyResult();
}

}

Here is the configuration required for OpenId response extension

<configSections>

<section name=”uri” type=”System.Configuration.UriSection, &#xD;&#xA;            System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″
/>
<section name=”dotNetOpenAuth” type=”DotNetOpenAuth.Configuration.DotNetOpenAuthSection”
requirePermission=”false” allowLocation=”true”/>
</configSections>
<uri>
<idn enabled=”All”/>
<iriParsing enabled=”true”/>
</uri>
<dotNetOpenAuth>
<openid maxAuthenticationTime=”0:05″>
<relyingParty>
<security
requireSsl=”false”
minimumRequiredOpenIdVersion=”V10″
minimumHashBitLength=”160″
maximumHashBitLength=”256″
requireDirectedIdentity=”false”
requireAssociation=”false”
rejectUnsolicitedAssertions=”false”
rejectDelegatingIdentifiers=”false”
ignoreUnsignedExtensions=”false”
privateSecretMaximumAge=”07:00:00″ />
<behaviors>
<add type=”DotNetOpenAuth.OpenId.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth” />
</behaviors>
</relyingParty>
</openid>
<messaging>
<untrustedWebRequest>
<whitelistHosts>
<!– since this is a sample, and will often be used with localhost –>
<add name=”localhost” />
</whitelistHosts>
</untrustedWebRequest>
</messaging>
</dotNetOpenAuth>

July 27, 2009

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

Filed under: Ajax Client Templates, Asp.Net, Asp.Net MVC, jQuery, MVC — Venkata Uma lakkakula @ 9:33 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

Working portal at: http://aspspider.info/lakkakula/local.aspx

In this post we will see how to render widget gallery and touch a little bit on CSS. CSS has limited set of keywords on which almost all web pages on the internet are being rendered. As a web programmer every body should spend some to time learning and understanding CSS.

At the beginning of my career I worked as a Desktop Publishing Designer for a short while (Don’t ask me why).  What I use to do is; to take a well designed magazine and try to re-produce a page with same results using PageMaker and Photoshop. After repetitive reworks I started to understand the original designer’s intent and how to design good pages for magazines. Finally I have applied the knowledge I’ve gained to my real work on web development for designing elegant web pages.

Widget gallery is straight forward to implement. Just get the list of (n) widgets per page and render them on the top section of the page, like:

wiz-gal

We would do this by reusing a client template:

<div id=”wizGallery”>
<div class=”left-nav”>
<input type=”text” value=”Search for widgets” style=”width: 150px; />
<button>Go</button>
<ul> <li class=”selected”><a href=”#”>Widget Gallery</a></li>
<li><a href=”#”>Cool Widgets</a></li>
<li><a href=”#”>New Feed Widget</a></li>
</ul>
</div>
<div class=”wiz-lib” style=”float:left;“>
<a href=”#” class=”wiz-close” >X</a>
<h4 style=”margin-left:10px”>Widget Gallery</h4>
<a href=”#” class=”prev” title=”Previous Page” onclick=”javascript:getGallery(‘prev’);” ><</a>
<div style=”float:left;margin-right:5px; width:690px; overflow:hidden; sys:attach=”dataview” dataview:data=”{{gallery}}” class=”sys-template”>
<div class=”wiz-holder”>
<img code:if=”icon!=”” sys:src=”{{‘../../Content/images/’ + icon}}” /><br />
<span>{{name}}</span><br />
<a href=”#” class=”link-button”>Add</a>
<a href=”#” class=”link-button”>Preview</a>
</div>
</div>
<a href=”#” class=”next” title=”Next Page” onclick=”javascript:getGallery(‘next’);”>></a>
</div>
</div>

Here is the CSS for Widget Gallery:

#wizGallery{border-bottom:1px solid #ccc; border-top:1px solid #ccc; background-color:#000;display:block; padding:0px; width:1000px; height:150px; color:#fff; display:none; float:left; }
.left-nav{padding:10px;width:200px;height:130px;background-color:#2E2E2E;float:left;}
.left-nav
ul{line-height:30px;list-style-position:inside;}
.left-nav li.selected {background-color:#424242;}
.left-nav li.selected a{font-size:14px;font-weight:bold;text-decoration:none;color:#fff; }
.left-nav
a{font-size:14px;font-weight:bold;text-decoration:none; }
.left-nav
a:visited{ }
.left-nav a.selected:visited{ }
.page-options
{list-style:none;width:265px; }
.page-options
li {float:left;padding:0px;margin:0px; }
.page-options
li a, .page-options li a:visited{color:#000;text-decoration:none;padding:2px 10px 2px 10px;margin-right:15px;border:1px solid #fff;background-color:#ccc; }
.page-options
li a.selected, .page-options li a:hover {color:#fff;background-color:#666; }
.wiz-lib
{width:775px}
.wiz-lib
.wiz-close {float:right;color:Red; text-decoration:none; padding:10px 5px;}
.wiz-lib
.prev {float:left;text-decoration:none;padding:38px 10px;margin-left:10px;margin-right:10px;background-color:#2e2e2e}
.wiz-lib
.next {float:left;text-decoration:none;padding:38px 10px;background-color:#2e2e2e}
.wiz-lib .wiz-holder{float:left;display:block;background-color:#424242; padding:5px; margin-right:10px; width:75px; }
.wiz-lib
.wiz-holder img{margin-left:auto; margin-right:auto; float:none;}
.wiz-lib
.wiz-holder span{overflow:hidden;}

Server Code:

1 public class LocalController : Controller

2 {

3 IWidget repoWidget;

4 public JsonResult WidgetGallery(int page)

5 {

6 var wiz = repoWidget.WidgetGallery(page);

7 return Json(wiz);

8 }

9 }

repository method:

1 public object WidgetGallery(int page)

2 {

3 return (from wizBase in db.WidgetBases

4 select new {

5 id = wizBase.Id,

6 name = wizBase.Name,

7 icon = wizBase.Icon

8 }).Skip((page-1) * 7).Take(7).ToList();

9 }

Client Code:

1 <script language=“javascript” type=“text/javascript”>

2 var gallery = [];

3 var gallery_page = 1;

4

5 $(function() {

6 getGallery(‘first’); //get first page

7 });

8

9 function getGallery(way) {

10 if (way == ‘next’)

11 gallery_page = gallery_page + 1;

12 else

13 gallery_page = gallery_page – 1;

14

15 if (gallery_page == 0) gallery_page = 1;

16

17 $.getJSON(‘/Local/WidgetGallery?page=’ + gallery_page, null, function(json) {

18 Sys.Observer.clear(gallery);

19 Sys.Observer.addRange(gallery, json);

20 });

21 };

22 </script>

When page loads getGallery(‘first’); //get first page javascript method makes an ajax call to Local controller’s WidgetGallery action. This loads first page JSON to gallery[] array.

Only important thing to notice here is the following lines:

18 Sys.Observer.clear(gallery);

19 Sys.Observer.addRange(gallery, json);

When previous or next page is requested from controller; line 18 clears existing values in gallery[] array and line 19 re-fills with new values. This actions are really magical, because Sys.Observer automatically re-binds the changes in gallery[] to our template. That is all we have to do, really!

Ain’t that cool? 🙂

Shout it

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.