Hugoware

The product of a web developer with a little too much caffeine

Posts Tagged ‘jQuery

Waiter, There Is Some jQuery In My jLinq…

leave a comment »

jLinq occasionally gets confused as a plug-in for jQuery. Unfortunately, jLinq doesn’t do much to help performing queries in jLinq. I’ve written some extension methods before to help link the two together but they were packaged with other projects (and not really ever released)

So this weekend I put together a few helpful extension methods and released them on GitHub.

Naturally, you’ll need the core jLinq library and the jLinq.jQuery library along with jQuery. Since a lot of jQuery uses chained methods you’ll need to use the special invoke syntax for jLinq queries (just an array).

Here are some of the commands you can use.

  • jlinq.$([selector]) : Starts a new query from document.body with the starting selector (if any).
  • $(selector).query([selector]) : Starts a new query from the current jQuery object. Allows an optional selector.
  • .include(selector, [jQuery Object]) : Includes the matches of the provided selector into the current query. You can use a different jQuery object as the source (otherwise it defaults to the object that started the query).
  • .get([selector]) : Converts the current matches in the query to a jQuery object. Allows an optional selector to further filter the results.

Just as a reminder, in order to invoke methods within a query you need to use an array where the first value is the name of the method and following values are the arguments. These arguments are all where the field name would normally be. Here are a few examples in case you need them.


//Example 1: Non-method query
jlinq.from(data).contains(
    "fieldName", //the field to pull the value from
    "check for this" //the argument for contains
    );

// Example 2 : No arguments
// function test() { ... }
jlinq.from(data).contains(
    ["test"], //no arguments, but still an invoke
    "check for this" //the argument for contains
    );

// Example 3 : With arguments
// function test(arg1, arg2) { ... }
jlinq.from(data).contains(
    ["test", 33, false], //the method with arguments
    "check for this" //the argument for contains
    );

So what do these new methods look like? Well here are a few examples to get you started!


//finds all .result elements containing red or green
//and is also case-insensitive
jlinq.$("div.results")
    .contains(["text"], "red")
    .or("green")
    .get()
    .appendTo(document.body);

//finds all links pointing to MP3 files then sorts and styles them
var mp3Links = jlinq.$("a")
    .endsWith(["attr","href"], ".mp3")
    .sort(["text"])
    .get()
    .css({
        color:"#f00",
        fontWeight:"bold"
    });

//highlights all of the matching markup with 'Joe Smith'
$("div.result").query()
    .contains(["html"], "Joe Smith")
    .each(function(rec) { 
        var markup = rec.html()
            .replace(/Joe Smith/g, 
                "<span class='highlight'>Joe Smith</span>");
        rec.html(markup); 
        });

Now you can enjoy the awesomeness of jQuery along with the semi-usefulness of jLinq! You have access to ‘or’-ing, case insensitivity, sorting — It is all there!

This code is all brand new so I don’t recommend using it anywhere important just yet, but it is fun to see how jLinq can make queries a little bit easier.

Written by hugoware

September 26, 2010 at 10:18 pm

jsshell – Reputable Software??

with 2 comments

Yes, it seems impossible so I took a screenshot. My little jsshell project has made it onto a pretty ‘notable’ list of Google extensions.

If you don’t know what jsshell then you might watch the introduction screencast.

Well… yeah, it isn’t spelled correctly… but I promise it is the same one.

In any case, you can check out the list on the Google site for yourself and possibly pick up some of the other awesome plugins while you’re at it. Don’t wait too long since it is only a matter of time before they realize their mistake 🙂

So, what better way to celebrate than to go ahead and open-source the code?

As usual, you’ll find my code out on git-hub, since its, ya’know, awesome… GitHub that is…

[Source Code]
http://github.com/hugoware/jsshell

Written by hugoware

June 28, 2010 at 10:56 pm

CobaltMVC and Custom Selectors

leave a comment »

CobaltMVC is a server side templating framework that behaves just like jQuery for your Views. CobaltMVC also works in WebForms.

CobaltMVC supports a variety of CSS selectors including pseudo and attribute matching. To keep things flexible, I’ve made it so that you can create or overwrite anything built-in. This post we discuss how to create your own for your project.

Right now, if you wanted to select all of the even rows in a table then you could use the pseudo selector…

this.Find("table > :even");

Cool, but what if we wanted to create our own? Here is an example of a selector that finds ‘numeric’ HTML elements.


//called once to add it to the project
CobaltManagement.RegisterCustomPseudoSelector(
    "numeric", //the name of the selector :numeric
    (nodes, argument) => { //the comparison to use
        decimal container = 0;
        return nodes.Where(node => decimal.TryParse(node.InnerText.Trim(), out container));
    });

//then used from our pages like...
this.Find(":numeric");

You’ll notice there are two arguments for the method you provide – First is a list of the available nodes to compare against. The second is an optional ‘argument’ string. The method should return a list of nodes that should be kept in the selection.

And the argument? That is an optional value in case you want it included in your selector. A good example of using the argument is the nth pseudo selector which returns every x number item.

//Everything within the parens is included as part of the argument
this.Find(":nth(4)");

Note: The argument is passed as a string so you’ll need to perform any parsing before you begin using the value.

Attribute selectors match against the attributes of the HTML elements. CobaltMVC checks the values and makes sure that two string are passed (even if they are empty), but any additional parsing needs to be done as part of the method.

That said, the method you use to perform the comparison is slightly different.

CobaltManagement.RegisterCustomAttributeSelector(
    "%", //the prefix to use for the selector @attr%='value'
    (argument, value) => argument.Equals(value, StringComparison.Ordinal)); //the comparison

The special character is what you want to prefix the attribute selector with (if you plan to override the default = selector then you just pass in an empty string). This needs to be a special character so not to be confused with the name of the attribute.

The comparison method itself is just a pair of strings, the first being the argument provided by the user and the second being the value found on the attribute. If the element doesn’t have the matching attribute then it is skipped entirely.

So, we could use the method we created in the example above by using…

this.Find("[@title%='Hugoware']");

Pretty neat!

If you haven’t downloaded Cobalt then head out to GitHub and download the code!

Written by hugoware

June 6, 2010 at 11:08 pm

CobaltMVC – Custom Controls and Dynamic HTML

with one comment

CobaltMVC is a server side templating frameworks that works a lot like jQuery. You can use it with both ASP.NET MVC and WebForms – (Watch the introduction video)

So far all of the CobaltMVC examples that have been posted have involved selecting existing elements on the page and making changes to them. However, there are times you’d like to generate new elements or wrap the same markup in a reusable control and attach it to the page.

Controls in CobaltMVC are just CobaltElements with properties and methods that you can use to define the behavior of an element. Because of this, a control can be selected against and modified by external selectors. This means that any control can be adjusted and tweaked for your individual needs.

Want to learn more? Check out the screen cast below that explains some of the interesting things you can do with custom controls and dynamically generated HTML elements.

[Watch The Screencast!]

Written by hugoware

June 4, 2010 at 9:52 am

Cobalt Beta – jQuery Style MVC View Templating!

leave a comment »

In a recent blog post I shared a preview of the Cobalt project I’ve been working on. Today, the source code has been uploaded to git-hub and the first beta binaries are being released!

Not sure what Cobalt is? Watch a screencast showing how you can use Cobalt in your MVC projects.
Watch the video now!

If you’ve seen any of my previous blog posts then you realize I’m not much of a fan of the current way to populate templates in ASP.NET MVC. I’ve tried a handful of different ways to improve the experience but so far nothing really felt like an improvement.

Cobalt uses CSS selectors to find and update content, much like the way that jQuery works. Cobalt works *with* ASP.NET MVC (and WebForms) so you can include it in an already existing project and use it right away!

So what does Cobalt look like? Here is an example of an MVC View…

<%@ Page Language="C#" 
    Inherits="System.Web.Mvc.ViewPage<IEnumerable<ProductDetail>>" %>
<%  
    this.Ready(() => {

        //select by tag names
        this.Find("form")
            .Attribute(new {
                action = this.Url.Action("CheckOut")
            });
        
        //find and set values for elements
        string current = this.Find("h3").Text();
        this.Find("#title").Text(current.ToUpper());
        
        //select classes and certain pseudo selectors
        this.Find(".list :even").AddClass("alt-item");
        
        //create new elements on the fly
        var link = this.Create("<a/>")
            .Text("Read About Us")
            .Attribute("href", this.Url.Action("AboutUs"));
        this.Find("p").Append(link);
       
        //create custom elements (like CustomControls)
        Stylesheet sheet = new Stylesheet("~/site.css");
        sheet.AddToPage();
        
    });
    
%>

<html>
    <head>
        <title>Sample</title>
    </head>
    <body>
        <form method="post" >
            <h3>Temp Title</h3>
            <p>The description goes here</p>
            <ul class="list" >
                <li>Item 1</li>
                <li>Item 2</li>
                <li>Item 3</li>
                <li>Item 4</li>
                <li>Item 5</li>
            </ul>
        </form>
    </body>
</html>

You can see that much like jQuery we have to queue up the work we need to execute once the document is ready.

I have a lot of documentation to write and a lot of screencasts to record, but don’t forget about the preview video which should get you started. For now, here are a list of the more important details.

The Important Stuff!

  • You must call CobaltManagement.Initialize() in your Global.asax file in the Init method (just override it and call it).
    public override void Init() {
        base.Init();
        CobaltManagement.Initialize();
    }
    
  • Cobalt uses HtmlAgilityPack to handle parsing of html content. I’m not happy with the framework so it will be one of the first things to be phased out, but for now you need to make sure to download it if you get the source code instead of the binaries.
  • You must use this.Ready from your pages and controls to wrap your commands. Otherwise your commands will run before the document is ready and fail.
  • Cobalt is aware of context, so if you use this.Find within a UserControl then you’re only going to select elements within that control. If you need to access the Page level from a UserControl then you can call this.Page.Find to change the scope of the command.
  • Cobalt supports a decent amount of selectors. Below is a list of currently available options.
    • Combinators: ‘ ‘, >, +
    • Shortcut Attributes: #elementId, .cssClass, $elementName
    • Attribute Matching (ex. [@name=’value’]): equals (=), starts with (|=), ends with ($=), contains (~=)
    • Pseudo: first, last, even, odd, nth(#), lt(#), lte(#), gt(#), gte(#), text, password, button, checkbox, radio, submit, file

Keep in mind this is very much beta code – I was literally working on changes today :). If you’re feeling brave then download the source and dig right in!

Download Beta

Cobalt (Source Code)

Written by hugoware

May 31, 2010 at 11:38 pm

Cobalt MVC Preview!

with 3 comments

Lately, I’ve been working a lot on my project Cobalt which is, more or less, jQuery for server side ASP.NET MVC views. I’ve shown some code examples before but today I have a screen cast of some of the code in action.

Watch the video now!

Hopefully, I’ll have some code released in the next week or two, but for now feel free to give thoughts and feedback!

Written by hugoware

May 27, 2010 at 9:09 am

MVC Templating – jQuery Style!

with 3 comments

I’ve messed around with a variety of ways to make MVC templating better but I’ve never really been satisfied with any of my solutions until now.

One of the things that I really like about jQuery is that it allows for better separation of markup from code since you can use CSS selectors to find and change elements on the page. ASP.NET MVC requires server side blocks of code to be mixed into the markup to display content.

The other day I started working on a new project I’ve named Cobalt – A jQuery style, context aware templating framework for ASP.NET MVC. I’m not quite ready to release the code but I wanted to share the idea in advance.

Note: When I say “jQuery Style”, I mean method chaining with css selectors – You can’t use $()… sorry 🙂

Let’s pretend we have the following markup

[Index.aspx (Markup)]

<%@ Page ... %>
<html>
    <head>
        <title>Untitled</title>
    </head>
    <body>
        <h1>Title</h1>
        <div class="content">
            <p></p>
            <ul></ul>
        </div>
        <a id="back" >Previous</a> | <a id="next" >Next</a>
    </body>
</html>

Using Cobalt, we can use jQuery style code to select the correct elements and update content in server side code at the top of the view.

[Index.aspx (Server Code)]


//select tags by their names
this.Find("h1")
    .Text("My Page");

//select tags by name
this.Find("a")
    .Attr("href", this.Url.Action(link.Text())
    .Css(new { color = "#f00" });

//find by ID
this.Find("#back")
    .Remove();

//use other selectors
this.Find(".content > p")
    .Html(this.Model.PostContent);

//select classses and children
this.Find(".content > ul")
    .Remove();

//or perform sub queries
this.Find(".content", content =>
    content.Find("strong")
        .Text(bold.Text().ToUpper())
            .AppendTo(content)
            );

Keep in mind, this code is part of the view and not in a code behind file.

Of course, this view could probably be just as easily updated using a Model and assigning values using server side blocks of code, but consider some of the advantages of keeping our code separated.

  1. Markup stays free of server side code blocks so it is easier to pull the content from external resources (for example a database)
  2. If the markup is constantly being changed by another team member (for example a designer) we can avoid tinkering with the new HTML and instead make changes to our selectors (if even needed).
  3. Many web developers are familiar with CSS selectors – The template could be understood by other team members and developers regardless of programming language choice.

Being Context Aware

The context of a selector is another important part of Cobalt. If you’re working in a UserControl you might changes to stay within the context of the control. At the same time, you might want some of your commands to change other parts of the page.

[SomeControl.ascx]

<@ Control ... %>

<h3>Latest Tweets</h3>
<ul class="tweet-list" ></ul>
<a href="http://www.twitter.com/hugoware" >Follow Me!</a>
<% =this.Html.ActionLink("Rendered Link", "Index") %>

When you use the this.Find(...) command, the actions are queued up and executed only for the calling control. That said, you can use the this.Page or the this.Parent properties to change the context (and scope) of a command.

[SomeControl.ascx (Server Code)]


//context stays inside of the UserControl
this.Find("ul.tweet-list")
    .Html(this.Model.Tweets);

//context stays inside of the UserControl
this.Find("h3")
    .Text("Follow Me!");

//finds both links (static and rendered)
this.Find("a")
    .Attr("href", this.Url.Action("Home"))
    .Text("changed!");

//context changes to the page level
this.Page.Find("head")
    .Append(this.Model.Stylesheet);

//updates the title in the page
this.Page.Find("title")
    .Text("Changed the title!!");

//never finds the title (context is in the control)
this.Find("title")
    .Text("Title not changed!");

Again, this might be a little extra code in some cases, but we are also able to access elements all over the page without needing to apply special WebControls or wire up to the Page life cycle.

It is worth pointing out that both links will be discovered by the a selector since the actions aren’t actually invoked until after the page is rendered. This means you can use MVC like you normally would and still use Cobalt to find and change elements. In fact, as far as I can tell this should work with WebForms as well as MVC, but I’d have to test it before I could say how well it works.

Work In Progress

This project is only a few days old right now but is already coming along very well. I’ll be posting some code soon but till then feel free to share any ideas you have.

Written by hugoware

May 17, 2010 at 11:56 pm

Simple External jQuery Templates (Update)

with 5 comments

In my previous post I made some code available that would allow you to access external templates all in the same jQuery chain. Unfortunately, I discovered a few bone-head mistakes in the code the next day while I was using it.

The new code has been uploaded and the bugs (the ones I found) have been fixed. If you have anymore feedback, please let me know.

Written by hugoware

January 26, 2010 at 11:09 pm

Simple External jQuery Templates – Part 2

with 4 comments

In my last blog post I wrote about an interesting way to work with server side templates and avoid using callbacks to work with the elements you created. I worked on the concept some more and added some simple templating capabilities along with the ability to apply inline or external data. I’m posting this plugin to the jQuery website for downloading (along with parts of this blog post)

If you remember in the last post, the main problem was having to define callback methods to handle making changes to your jQuery object after it had been created. Instead, we used method forwarding and method queueing to allow direct access to the final object even before it had been created.

So instead of using callbacks your jQuery would look something like…

//loads an external resource but returns a placeholder to
//capture additional jQuery commands
$.template("/resource.html")
    .css({ color: "#f00" })
    .animate({ height: 400 })
    .click(function() { alert('clicked'); });

Interesting concept but requires some more work…

Important: This plugin simply helps avoid using callbacks to keep track of external templates.

What Is New?

Activation and Replacement Commands
The previous method worked pretty well if you’re adding to a page but if you needed to replace something then you were back to using callbacks to handle removing content from the page. This version adds a couple extra new functions to work with the document after the template has finished loading

  • fill(selector): Empties the target and then fills the container with the current jQuery object. (accepts a string or a jQuery object as a selector)
  • replace(selector): Removes the target and then puts the current jQuery object in its place. (accepts a string or a jQuery object as a selector)
  • ready(delegate(element) { ... }): Simple way to perform any action that you want immediately following the external resources being loaded and processed.

All of these commands can be used along with the rest of the existing jQuery commands (like styles, animations, events, etc) because they follow the same queueing rules that the rest of the methods use. So for example, you could write the following command…

$.template("/resource.html")
    .ready(function() { $(document.body).css({ background: "#00f" }); })
    .fill("#placeholder")
    .fadeIn();

Templating Engine

Another thing that was missing from before was a quick, automated way to populate the template after it was loaded. This version introduces a simple engine that allows you to pass in an object or a URL to the source to JSON data you want to use and then populate the template automatically.

Here is a simple example of using a template with a data source…

[template.html]

<div class="customer-list">
	<a href="javascript:void(0);" class="refresh" >Refresh</a>
	<h2>%%title%%</h2>
	<p>%%description%%</p>
	<ul>
	    <li each="%%customers%%" class="%%odd:'alt-row'%%" >
	        <h4 class="%%first:'top-customer'%%" >%%name%%</h4>
	        <ul>
	            <li each="contacts" class="%%first:'preferred'%% %%odd:'alt'%% contact-%%type%%">%%value%%</li>
	        </ul>
	        <hr if="%%!last%%" />
	    </li>
	</ul>
</div>

[data.json]

{"title":"Customer List",
"description":"Customers and their contact methods.",
"customers":[
    { "name":"Mark", "contacts":[
        { "type":"email", "value":"mark@example.com" },
        { "type":"email", "value":"supermark@example.com" },
        { "type":"phone", "value":"555-1254" }
    ]},
    { "name":"Susan", "contacts":[
        { "type":"email", "value":"susan@example.com" },
        { "type":"phone", "value":"555-9811" }
    ]},
    { "name":"Jamie", "contacts":[
        { "type":"email", "value":"jamie@example.com" },
        { "type":"phone", "value":"555-4322" },
        { "type":"phone", "value":"555-1077" }
    ]}
]}

[script.js]

var list = $.template({
	template: "template.html",
	externalData: "data.json"
})
.ready(function() {
	$(document.body).css({ background: "#ffc" })
})
.appendTo("#target")
.find(".preferred")
	.css({ color: "#f00" })
	.end()
.find("h4")
	.css({ color: "#00f" });

The final rendered result would look like the following sample…

I suspect that a templating engine written in the duration it takes me to finish a Starbucks coffee isn’t going to be high enough quality for everyone so you can easily replace it with a custom one by using the following command.

$.template(function(params) {
    /* perform formatting in this block (or send it to another templating engine)
     * params.html: The text provided by the template from the server
     * params.data: The JSON data provided for rendering (if any)
     */

    //must return a jQuery object
    return $(params.html);
});

This will replace the template formatting method for the duration of the page, however you can replace the formatting on a per request basis (but I’ll explain that later)

How To Use

There are a few ways you can use the template command.

$.template(function(params) { ... });
Replaces the template formatting method with a custom method. The argument passed in contains a html property that contains the string of HTML to use for the template. The argument also contains a data property that contains the JSON data to populate the template with (if any). This should return a jQuery object when finished.

$.template("/path/to/template.html")
Simply downloads the HTML from an external path and then returns the jQuery object after it has finished loading. This option does not support templating.

$.template({ options })
Allows a lot more control over the request. The argument accepts the following properties.

  • template: The URL that points to the template file. You can optionally pass in an object that contains the same parameters as the $.ajax command so you can have full control over the request.
  • externalData [optional]: The URL that points to the JSON content for the template. You can optionally pass in an object that contains the same parameters as the $.ajax command so you can have full control over the request.
  • data [optional]: A JSON object with data to populate the template with.
  • complain [optional]: Determines if an exception should be thrown if the template and the data do not cooperate with each other (such as missing information).
  • error [optional]: A delegate that handles any connection errors. The first argument will tell where the error took place (external data or the template).
  • format [optional]: A delegate that performs formatting for a template. This won’t replace the default formatting. Requires the same delegate type as the example for replacing the default version.

Source Code

For now I’m simply uploading the code for downloading but I’m going to post it to the jQuery website shortly. I’d like to get some feedback and check for bugs before I save anything to the site.

Also — If anyone can come up with a clever, buzz-wordy sort of name of the plugin, please clue me in! I’m terrible at naming applications or plugins.

Download

Download template.js (full source code)

.

Written by hugoware

January 24, 2010 at 10:38 pm

Simple External Templates With jQuery

with 4 comments

New code available: I’ve written a follow up post about this topic with new code and new features.

If you’ve ever tried building a jQuery object from scratch then you’ve probably found that it is a little time consuming and probably a little ugly by the time you’re finished. You could put additional HTML templates as hidden elements on the page but maybe you’d rather keep that extra mark up out of your page.

One option would be load a template from a website address and then make your changes once it arrives. The code would probably look something like this.

//create the container
var element = null;

//make the request for the HTML
$.ajax({
    url:"template.html",
    success:function(html) {
        element = $(html);
        //make changes here
    }
});

There isn’t anything wrong with this code but it does put a bit of separation of your declaration of an element and the actual usage of the element. The problem is that you can’t do the whole process at once since the AJAX call takes a little time and you have to rely on a call back before you have access to the object.

It would be nice if we could have immediate access to our jQuery object on an AJAX call, but not block anything else on the page.

Time For Some Javascript Magic ™

I’m not really sure what you would call the example below, but the general idea is to capture (and queue up) any actions that would be invoked on our jQuery object and then release them once the AJAX call has been finished.

Let’s look at some code and see what it would look like (extra comments to try and explain the process)

/*
 * Arguments
 * $.template(url) - Pass in a string to a url to load 
 * $.template(params) - An object with parameters found below
 *   url: Path to the template resource (required)
 *   data: Same as the 'data' argument in the $.ajax call
 *   error: Same as the 'error' argument in the $.ajax call
 *   complete: Same as the 'complete' argument in the $.ajax call
 *   beforeUpdate: delegate(html) called just before the actual object is created
 *   afterUpdate: delegate(html, actual) called just after the actual object is created
 */

//creates a function to access a web template
jQuery.template = function(params) {
	
	//format the passed in parameters
	//check if this was only the resource url
	if (typeof(params) === "string") {
		params = { url:params };
	}
	
	//prepare the arguments passed into the class
	if (!$.isFunction(params.beforeUpdate)) { params.beforeUpdate = function() {}; }
	if (!$.isFunction(params.afterUpdate)) { params.afterUpdate = function() {}; }
	

	//create the object that handles the work
	var self = {
	
	//Properties
	//---------------------------------------------------------
	
		//handles forwarding methods onto the actual object
		container:null,
		
		//the actual jQuery object being created
		actual:null,
		
		//method calls that are waiting to be called
		queue:[],
		
	//Methods
	//---------------------------------------------------------
		
		//prepares the container for use
		setup:function() {
			
			//apply each of the methods
			self.container = $("<div/>");
			for(var item in self.container) {
				if (!$.isFunction(self.container[item])) { continue; }
				self.register(item);
			}
			
		},
		
		//handles creating method forwarding on the returned object
		register:function(method) {
		
			//create a method that handles routing the original method calls
			self.container[method] = 
				function(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) {
				
				//if the actual object has been called, just invoke
				if (self.container.actual) {
					return self.container.actual[method](
						p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14
						);
				}
				//otherwise, queue the request
				else {
					self.queue.push({
						action:method,
						params:[p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14]
					});
					
					//then return the temporary object
					return self.container;
				}
			
			};
		
		},
		
		//executes any queued commands and updates the jQuery object
		update:function(html) {
			
			//create the jQuery object
			self.container.actual = $(html);
			
			//then execute all of the waiting commands
			$.each(self.queue, function(i, arg) {
				self.container.actual[arg.action](
					arg.params[0], arg.params[1], arg.params[2], arg.params[3], arg.params[4],
					arg.params[5], arg.params[6], arg.params[7], arg.params[8], arg.params[9],
					arg.params[10], arg.params[11], arg.params[12], arg.params[13], arg.params[14]
					);
			});
		
		},
		
		//starts the ajax request to download the template HTML
		download:function() {
			
			//starts downloading content
			$.ajax({
			
				//parameters for the template request
				url:params.url,
				data:params.data,
				dataType:"html",
				
				//performs the catch up work for the ajax
				success:function(html) {
					//** Optional: Uncomment 'setTimeout' to simulate a delay 
					//setTimeout(function() {
					params.beforeUpdate(html);
					self.update(html);
					params.afterUpdate(html, self.container.actual);
					//}, 2000);
				},
				
				//additional handling of the request
				error:params.error,
				complete:params.complete
			});
		
		},
		
	//Initalization
	//---------------------------------------------------------
		
		//setup the object to work
		init:function() {
		
			//prepare the temporary container
			self.setup();
		
			//start downloading the content
			self.download();
		}
	
	};
	
	//prepare the the template code
	self.init();
	
	//return the custom container to forward method calls
	return self.container;
	
};

This code allows you to have direct access to a jQuery object even before it has finished loading the content from the server. So, instead of using a callback we can write our jQuery like we normally would.

//note: the first command is all one long chain with a comments
//between functions to explain a bit more

//create the object and immediately apply changes
var template = $.template("template.txt")
	.css({"color":"#f00", "width":"200", "background":"#333"})
	.animate({width:800, height:900}, 3000)

	//you can even append and appendTo the object in advance
	.appendTo($("#container"))

	//or search for and update child elements
	.find(".title").text("howdy")

	//and parent elements
	.parent().css({"background":"#00f"});
	
//you can also still access the template from the 
//assigned variable
template.find("div").click(function() {
	alert('clicked');
});

//even if if you call it much later, it still works
setTimeout(function() {
	template.css({"color":"#0f0"});
}, 10000);

What Is Going On Here?

As I mentioned before the real problem is that the jQuery object we create isn’t ready as soon as we want to assign to it. Because of that we have to use a callback to resume the work. However, the cool thing about dynamic languages is that we can override anything we want.

In this example we start by creating a container that has all the same functions as a typical jQuery object but has one slight modification — all the methods are overridden and placed into a queue (man, I love enclosures). Once our AJAX call has completed we run an update command that executes everything we have saved against our new jQuery object instead of the one that received the calls to begin with — madness!

After we’ve caught up and our actual object is created we can stop saving actions to the queue and instead just invoke them immediately. I nicknamed this method forwarding for the sake of having a cool, buzzword sounding sort of name but if anyone knows what this is really called, please tell me 🙂

It is worth noting that this is only going to work with functions that return the jQuery object (at least until the ‘real’ object is created). The reason is that since we’re just capturing methods and saving them for later then we don’t know what the actual return type is. Needless to say, using a property probably won’t be accurate either (since we can’t intercept the request for the property like we would with a method)

In any case, this might simplify the next time you need to download content in jQuery but you don’t want to break up your functionality.

Written by hugoware

January 14, 2010 at 10:59 pm