tags:

views:

63

answers:

1

I'd like to write a small JavaScript (framework) that can chain functions with all following functions being aware of the data of its predecessor.

Basically, I'm not interested in the bloat (I realize it's small, for my even smaller project though it's bloat) that jQuery provides but would like to mimic some of its behavior -- primarily for learning purposes and having data available to all chained functions.

I'd love, for example being able to do something like:

myJsLib.processForm("user", "pass").url("http://domain.dev/form.php").queryString({ secure: true, errorPage: "login_failure.htm" });

In the above example all functions must be aware to some extent what the other is doing.

Or, more specifically:

myJsLib.getDataIntoArray(jsonObjectOrWhatever).each(function(item) { alert(item); });

Where "item" would be the array that getDataIntoArray() created (and returned?).

I hope that I have worded this suitably. I tried to go a bit overboard with the example. Making sense of jQuery's prototype extending proved useless, but I'm not that versed in JavaScript at all. I would very much appreciate a detailed (yet dumbed down) explanation and code examples, please.

Many thanks.

EDIT: Thanks to Andrew I was able to come up with something that seems satisfactory. Please correct any misunderstandings I may seem to have, thanks.

function myLib()
{
this.properties = ['status', 'window', 'ui'],
this.inputArrayParms = function(parms)
{
 for (var i = 0, len = parms.length; i < len; i++)
 {
  this.properties[this.properties.length] = parms[i];
 }
 return this;
},
this.each = function(callback)
{
 for (var i = 0, len = this.properties.length; i < len; i++)
 {
  callback(this.properties[i]);
 }
 return this;
}
}

var f = new myLib;
f.inputArrayParms(["one", "two", "three"]).each(function(theMsg){ alert(theMsg); });

This appears to work as expected. Any caveats?

+4  A: 

This is called a fluent interface and the best way to create this is to have a single master object (like the jQuery object) that is returned from every function allowing additional function calls to be chained together.

Here is a small example:

function foo() {
 this.first = function(first) {
  alert(first);
  return this;
 }
 this.second = function(second) {
  alert(second);
  return this;
 }
}

This notice that the foo class has two methods, first and second. Since both of these methods return this they can be chained in any order you wish:

new foo().first("hello").second("world");
new foo().second("hello").first("world");
new foo().first("hello").first("world");

You get the idea :)

A good way to think about fluent interfaces is that they flow easier and are arguably easier to read. The example above is simply a replacement for this more conventional usage:

f = new foo();
f.first("hello");
f.second("world");

This means that a fluent interface does not dictate any of the implementation of the class beyond mandating that you return this so that method calls can be chained. This means that you can add fields to this class that can be used in any function, just like any other class.

Andrew Hare
Thanks, Andrew. I will try this approach but would very much appreciate a small example in code.
Brainsick
This is fantastic and easily understood. Thank you. How though, would I, for example, have second() use "first" or an array that was declared or processed in first()?
Brainsick
If I have understood correctly we are basically mimicking real classes in that each "method" would refer simply to a "property" of the original object. Thanks for your assistance and feel free to correct any glaring omissions on my part.
Brainsick