Live Demos

Monday, June 14, 2010

jQuery AJAX with ASP.NET Web Forms & Sitefinity



My team and I are working with Sitefinity to create our new portal. Well, since Sitefinity doesn’t currently support MVC, we’re having to use the “good” ole web forms. Sitefinity is a really nice CMS and allows for full customization and we’re still learning how to handle the custom user controls. So…this is how we’re doing it right now.

Download Source

We wanted to allow our users to add quick links to their home screen, so that’s the sample I’m going to use. First, I created two projects, one called UserControlSample.Core (class library) and the other called UserControlSample.UI (a blank Web project).

I started with the domain model, which looks like this:

public class QuickLink
{
public Guid Id { get; set; }
public string DisplayName { get; set; }
public string URL { get; set; }
public string UserId { get; set; }

public string BuildHyperlink()
{
return string.Format("<a href=\"{0}\" title=\"{1}\">{1}</a>", URL, DisplayName);
}
}

Generally, I wouldn’t put the UserId in this class, but for this example it just made it easier.

After the domain model, I added the repository interface, which is this:

    public interface IQuickLinkRepository
{
QuickLink[] GetAllBy(string userId);
void Add(QuickLink quickLink);
void Delete(Guid quickLinkId);
}

You can download the project to see the implementation of the interface. I used L2S and again, you can download the project to see the implementation. Alrighty, so let’s get to the real code that you can use.

I added a user control, which looks like this:

<div id="quicklinks">
<
div>
<
div class="loader" id="loading" style="display: none"></div>
<
asp:Repeater ID="rQuickLinks" runat="server">
<
HeaderTemplate><h3>Quick Links</h3><ul></HeaderTemplate>
<
ItemTemplate><li id="li<%# ((QuickLink)Container.DataItem).Id %>"><img src="/_a/i/ico-delete.png" width="16" height="16" alt="Delete <%# ((QuickLink)Container.DataItem).DisplayName %>" id="<%# ((QuickLink)Container.DataItem).Id %>" /><%#((QuickLink)Container.DataItem).BuildHyperlink() %></li></ItemTemplate>
<
FooterTemplate></ul></FooterTemplate>
</
asp:Repeater>
<
a href="#" id="addQuickLink" title="Add Quick Link">Add Quick Link</a>
</
div>
<
div style="display: none">
<
fieldset>
<
legend>Add Quick Link</legend>
<
p><label for="<%=tbDisplayName.ClientID %>" title="Display Name:">Display Name:</label><br />
<
asp:TextBox ID="tbDisplayName" runat="server" /> <asp:RequiredFieldValidator ValidationGroup="addQuickLink" ControlToValidate="tbDisplayName" Display="Dynamic" ID="rv1" SetFocusOnError="true" runat="server">*</asp:RequiredFieldValidator></p>
<
p><label for="<%=tbURL.ClientID %>" title="Website Address:">Website Address:</label><br />
<
asp:TextBox ID="tbURL" runat="server" /> <asp:RequiredFieldValidator ValidationGroup="addQuickLink" ControlToValidate="tbURL" Display="Dynamic" ID="rv2" SetFocusOnError="true" runat="server">*</asp:RequiredFieldValidator> <asp:RegularExpressionValidator ControlToValidate="tbURL" Display="Dynamic" ID="re1" runat="server" SetFocusOnError="true" ValidationGroup="addQuickLink" ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)?">*</asp:RegularExpressionValidator></p>
</
fieldset>
<
asp:Button ID="bSubmit" runat="server" CausesValidation="true" Text="Add Quick Link" ValidationGroup="addQuickLink" OnClick="AddQuickLink" /> <a href="#" title="Cancel Quick Link Addition" id="cancelAddQuickLink">Cancel</a>
</
div>
</
div>

That looks really messy, but that’s web forms for ya :D

Here’s the interesting part, instead of having a code-behind and inheriting from a partial, we added a class to the Core.UI.Controls called QuickLinksControl. Here’s the code:

 

public class QuickLinksControl : BaseControl
{
private IQuickLinkRepository _repository;

protected void Page_Load(object sender, EventArgs e)
{
_repository = DependencyResolution.
DependencyRegistrar.Resolve<IQuickLinkRepository>();

if (Request.Form["QLID"] != null)
DeleteQuickLink(
new Guid(Request.Form["QLID"]));

if(!Page.IsPostBack)
LoadQuickLinks();
}

private void DeleteQuickLink(Guid quickLinkId)
{
_repository.Delete(quickLinkId);
Response.Write(quickLinkId);
Response.End();
}

protected void AddQuickLink(object sender, EventArgs e)
{
if (!Page.IsValid)
return;

var tbDisplayName = (TextBox)Page.FindControl("tbDisplayName");
var tbURL = (TextBox)Page.FindControl("tbURL");
var button = (Button) sender;
var quickLink = new QuickLink {DisplayName = tbDisplayName.Text, URL = tbURL.Text, UserId = button.CommandArgument};
_repository.Add(quickLink);

tbDisplayName.Text =
"";
tbURL.Text =
"";

LoadQuickLinks();
}

private void LoadQuickLinks()
{
var rQuickLinks = (Repeater) FindControl("rQuickLinks");
rQuickLinks.DataSource = _repository.GetAllBy(Page.User.Identity.Name);
rQuickLinks.DataBind();
}
}

The interesting parts…

  1. DeleteQuickLink() is checked in the Page_Load. We’re doing this here for an AJAX call from the ascx file. We’re probably going to add some type of validation token to the if statement as well. We also might create some type of AJAX call handler instead of throwing them in the page_load, but it works for now.
  2. In the DeleteQuickLink method, we’re calling Response.Write(quickLinkId) and Response.End(). This is used for the AJAX call too to return the guid sent. There’s probably a better way, but so far this is working.
  3. In the AddQuickLink, you’ll notice that we’re having to find the controls because it’s not a partial and doesn’t know anything about the ascx page. This part kinda stinks, but it’s not too bad.

Here are the AJAX calls from the ascx page:

<script language="javascript" type="text/javascript">
$(document).ready(
function() {
$(
"#addQuickLink,#cancelAddQuickLink").click(function() {
$(
"div#quicklinks div").toggle();
});

$(
"#loading").ajaxStart(function() {
$(
this).show().text("Deleting...");
}).ajaxStop(
function() {
$(
this).hide().text("");
});

$(
'#quicklinks ul li img').click(function() {
if (!confirm('Are you sure you want to delete?'))
return;

$.post(window.location.href, { QLID: $(
this).attr('id') }, function(data) {
$(
"#li" + data).remove();
});
});
});
</
script>

I’ve never used the ajaxStart or ajaxStop before, but they’re pretty cool features. I also wanted to note that I started using StructureMap 2.6.1 and I’m liking it. It’s a pretty big difference from the last blog post on StructureMap. Now the ForRequestedType<> in the registry looks like this:

For<IQuickLinkRepository>()
.Use<
QuickLinkRepository>()
.Ctor<
string>("connstring")
.Is(
@"Data Source=.\SQLEXPRESS;AttachDbFilename=""..\LearnerSample.mdf"";Integrated Security=True;User Instance=True");

 

Here’s the finished product:

image

image 

So, any thoughts or ideas on what we’re doing? I’d appreciate any advice or comments. It’s probably easier to understand by downloading the sample code.

Thanks for reading!

Download Source

Shout it

8 comments:

  1. Each listing includes the skills taught and the suggested age for the activity.
    Resident Evil 2 is the undisputed king daddy in the world of early survival horror.
    The reason for this rather strange feature is
    that, as described above, apps in the Android Market are listed as they
    are submitted, without any testing.

    Here is my site: youtube converter
    My website > spiele spielen kostenlos

    ReplyDelete
  2. Usually, a brand new website takes about six months to one year to appear in
    the SERPs of Google, assuming the service provider is worth their salt.
    If the executives promise high traffic then understand you are talking with a non-SEO person.
    This is what professionals do. While you’re at it, remove all or fix 404 errors.

    Is professional search engine marketing the thing
    that you need. Search engines are getting smarter at detecting sites that are spamming keywords or made solely for the purpose of advertising.
    The tips are as follows:-. The thing that needs to be emphasized is
    to create text of your website in such a way that the algorithms find them easily.

    Isn't that something you and your business should be a part of. Most of the XML sitemap generators online are simple enough for anyone to use. So, most move slowly when deciding on who becomes the company's SEO.
    He has also mentioned each and every seo service. Moving your hosting to a nearby country such as Canada or an offshore Caribbean host may provide the same latency times, but reduce the
    risk of having your website brought down by a mistake.

    Regardless of whether you like it, love it, or hate it, social media has
    become a major player in the SEO world, and it is a costly
    mistake to ignore it. These professionals follow ethical
    SEO strategy and effectively implement it that finally increases your website visibility.

    The sooner a site is presented in the search result, or the higher it “ranks”, the more searchers
    will visit the site. 4) Managing your online business.
    Once someone clicks on your site, they should see tons of unique informative content.
    The website serves as a way for customers to find the business and be able to see what services are offered.
    ============ More at: Comment "Smartly" & Increase Page Views: Writing Essentials 8.


    Have a look at my webpage ... http://www.kseane.org/
    my site :: http://portland.freedesktop.org/

    ReplyDelete
  3. I was wondering if you ever thought of changing the layout
    of your blog? Its very well written; I love what youve got to say.
    But maybe you could a little more in the way of content so people could connect
    with it better. Youve got an awful lot of
    text for only having 1 or two pictures. Maybe you could space it
    out better?

    Here is my blog :: youtube videos downloaden

    ReplyDelete
  4. Tennis balls, wiffle balls, ping pong balls, and golf balls can also be used.
    Naturally the ideal situation is to be able to lose
    weight really fast with a little amount of discomfort.

    Even when things seem hopeless, Kiko's narration provides some great comedy relief.

    Here is my page ... radiosender

    ReplyDelete
  5. These аre also avaіlable wіth PTO Delаy fеature whіch automatically οреn tank inteгnal vаlve for 5
    seconds pгіoг tο engaging РTO
    аllοωing pump аnd product
    lіnes to chагge previewіng іnterval νalѵe slug.
    Pеrhаps the bеst thіng to dο is keep an еye οn the promotional deals and be ready tо
    ρouncе quickly whеn a suitаble one cоmes uр.
    Eνen if you hаve a gooԁ two ωау radio, it isn't bad to have some kind of receive only radio to get information on.

    Look at my web-site ... visit the following internet page

    ReplyDelete
  6. With dοzens of raԁio apρѕ foг
    і - Phοne availаblе in i - Тunes, there is
    an app for еverу cаtеgоrу of musiс lοvеr
    to love. Anοtheг thіng you'll need is some strength to endure, because there's a
    good chancе уou'll be your own producer for the show or perhaps the best producer the show has. A MOBILE APP GIVES THE STATION A DIRECT MARKETING CHANNEL TO COMMUNICATE WITH THEIR LISTENERS.

    Feel free to surf to my website; video downloader

    ReplyDelete
  7. I am sure this paгagraph has touсhеԁ all thе internet
    pеople, its reallу reаlly good article оn
    building up neω blog.

    Rеview my web site - radiosender

    ReplyDelete
  8. Try downloading a game demo prior to purchasing the actual game so that you
    can determine if you're going to enjoy it. Unlike popular beliefs video games have how to use them which enable it to even be considered as being a learning tool. Although others may not have a specific machine for her, but at least they have most likely computers in their homes.

    Feel free to visit my website - http://qahuqakiiljo.sosblogs.com/The-first-blog-b1/Finding-Clear-cut-Systems-For-Children-b1-p57.htm

    ReplyDelete