catalyst iconperl icontemplatetoolkit iconscriptaculous iconprototype icon

HTML::Prototype - AJAX Without JavaScript

Posted in , , , , , Tue, 06 Jun 2006 01:52:00 GMT

HTML::Prototype is by far the most painless way to get started with AJAX that I've found. Simply put, you do not need to know or write any JavaScript! HTML::Prototype is a Perl module on CPAN that wraps the prototype AJAX library and Script.aculo.us effects library with Perl helper methods so you don't need to write a single line of JavaScript to get some great effects. There are also a number of modules that wrap HTML::Prototype for integration with Catalyst, CGI::Application, Template Toolkit and others.

There are a number of convenient methods such as link_to_remote() and submit_to_remote() that create a link and form button to make an AJAX call and populate the innerHTML of a specified DOM element with the response body. Syntactic sugar to be sure as the JS generated by HTML::Prototype is very simple once you look at it, but the beauty is that you never have to.

To truly appreciate HTML::Prototype you need to use some of Scriptaculous' more advanced widgets such as autocomplete. Sebastian Riedel put together a screencast using Catalyst that demonstrates how easy it is to use. Links to the screencast are available on the Catalyst wiki movies page:

http://dev.catalyst.perl.org/wiki/Movies

Another great thing about having HTML::Prototype generate the JS syntax for you is that you can learn prototype syntax just by View Source. I picked up enough of prototype's JS syntax this way that I haven't looked at the docs yet.

I've recently removed HTML::Prototype from a project in favor of using prototype.js and scriptaculous.js directly and I'm evaluating the Dojo Toolkit but HTML::Prototype let me get started with very effective, painless AJAX functionality. I used it with Catalyst::Plugin::Prototype and thought 'this is how frameworks make you productive.' Thanks to all the contributors.

del.icio.us:HTML::Prototype - AJAX Without JavaScript digg:HTML::Prototype - AJAX Without JavaScript reddit:HTML::Prototype - AJAX Without JavaScript spurl:HTML::Prototype - AJAX Without JavaScript wists:HTML::Prototype - AJAX Without JavaScript simpy:HTML::Prototype - AJAX Without JavaScript newsvine:HTML::Prototype - AJAX Without JavaScript blinklist:HTML::Prototype - AJAX Without JavaScript furl:HTML::Prototype - AJAX Without JavaScript fark:HTML::Prototype - AJAX Without JavaScript blogmarks:HTML::Prototype - AJAX Without JavaScript Y!:HTML::Prototype - AJAX Without JavaScript smarking:HTML::Prototype - AJAX Without JavaScript magnolia:HTML::Prototype - AJAX Without JavaScript segnalo:HTML::Prototype - AJAX Without JavaScript

no comments

dojo iconscriptaculous icon

Dojo's ComboBox Not Ready for Prime Time?

Posted in , , , Sun, 04 Jun 2006 06:21:00 GMT

I've been happily developing with Prototype and Scriptaculous for a while now but was recently convinced to look at Dojo. To start, I was pretty happy with dojo.io.bind but disappointed that I wasn't able to get the Dojo scripts to load from a remote server. Having gotten dojo.io.bind to work, I was off to test my first widget, Dojo's ComboBox, which offers functionality similar to the Scriptaculous autocomplete widget. I've been using Dojo 0.3.0. The Dojo ComboBox Nightly Test is often mentioned as a good place to start so I went there first. Eventually I also spent some time reading and implementing the code at Java.net's AJAX with Dojo and JSON page. In the end I came away disappointed due to several bugs and strange behaviors listed below:

  1. Default value: Dojo does not let you set a default value via the HTML or any other way. To get a default value to show up, I've heard you can write it in with JavaScript but I'm not sure where or when yet due to the DOM onLoad transform issue described below.
  2. Single option bug: when the a resulting list only has one item, hitting the 'enter' key will not close the list. With autocomplete, the single entry will already be populated in the box but not selectable with 'enter'. You need to select the single option in the list with the down key and then hit the 'enter' key. To try this out, type in 'am' for American Samoa in the first input on the nightly test and click 'enter' to continue. I haven't found out whether this is being worked on or not.
  3. DOM onLoad transform: Unlike other libraries, after the page has been rendered Dojo will go back and transform the DOM, replacing dojoTypes with HTML templates. This can cause some timing problems when one wants to use DOM to modify the resulting HTML templates. Dojo provides a dojo.addOnLoad capability to specify a callback function however the new DOM elements don't seem to be available yet. Perhaps something to the effect of dojo.afterDojoOnLoad is needed? This issue can be seen when trying to remove the ComboBox downArrowNode. The ComboBox comes with a down arrow graphic by default and is assigned dojoattachpoint="downArrowNode". With some lists, the reply possibilities are enormous and a default list isn't desirable. When nothing has been typed, it may also give the impression that the list provided is a complete list like a standard select element. I haven't found a good way to disable this yet. Setting the display property on the downArrowNode isn't a good solution because it only works after the page has been rendered. It can't be set immediately rendering the ComboBox input tag because Dojo hasn't been run yet. Setting the display property in the dojo.addOnLoad callback is also too early, i.e. the widget doesn't exist yet. Here's the JS I've been working with:
    var ac = dojo.widget.byId("ac");
    ac.downArrowNode.style.display="none";
    I've also tried setting downArrow and downArrowNode attributes to 0, -1 and false. So far, the only solution I found that works is to delete or comment out the downArrowNode HTML in the following file:
    dojo/src/widget/templates/HtmlComboBox.html
    Not exactly a great solution. Is there a better way to remove the arrow?
  4. Client-side result filtering: It seems like the Dojo javascript does it's own filtering. You give it a list in the format of an Array of Arrays where each inner array has two elements. Dojo then applies it's own filtering. This is nice if you are working off a local list such as a JS file in the Nightly Test example but if you are retrieving a list from a server, the server should have filtered the list already so there's no reason to filter it a second time. This may be partially at fault for the choppy rendering. Is there any way to disable this?
  5. Aribitrary location match: Because Dojo does client-side result filtering, the user isn't guaranteed to see what your server delivers. One area this shows up is that it's not clear how to match any part of the string instead of just the beginning. On the nightly test page, the only results presented are ones where the input matches the start of the string so if someone types a last name and the strings have the format "$first_name $last_name" there would not be a match. The DocTool on dojo.org will match inside the string but the rendering seems choppy and I can't seem to locate it any more. I haven't gotten around to seeing how the DocTool does it. The SVN copy of the doctool.html file shows the following which does not result in the desired non-start match for me:
    <input
        dojoType="combobox"
        id="search"
        autoComplete="false"
        value=""
        style="width: 300px;"
    >
  6. HTML result rendering: Often it's nice to show the user which part of the string matched, especially if the match is not at the beginning of the string. This is done by bolding the matching letters a la Gmail. If HTML is included in the array, it is rendered literally instead of interpreted as HTML. Because Dojo does client-side filtering, HTML mark up will also cause matching to fail. With Scriptaculous, you can add HTML mark-up to the results and it will render properly. Perhaps with Dojo, the HTML needs to be added by client-side JavaScript?

These are my initial observations of Dojo's ComboBox. It seems very difficult to get it to DWIW and very different than the Scriptaculous Autocomplete which just works and has been working. Scriptaculous autocomplete has been working like champ for me since prototype 1.3.1 and it's now on 1.5.0 rc0. Please let me know of any ways to accomplish the above Dojo ComboBox issues. Also let me know if you're using Dojo's ComboBox in production and / or your experiences with it.

del.icio.us:Dojo's ComboBox Not Ready for Prime Time? digg:Dojo's ComboBox Not Ready for Prime Time? reddit:Dojo's ComboBox Not Ready for Prime Time? spurl:Dojo's ComboBox Not Ready for Prime Time? wists:Dojo's ComboBox Not Ready for Prime Time? simpy:Dojo's ComboBox Not Ready for Prime Time? newsvine:Dojo's ComboBox Not Ready for Prime Time? blinklist:Dojo's ComboBox Not Ready for Prime Time? furl:Dojo's ComboBox Not Ready for Prime Time? fark:Dojo's ComboBox Not Ready for Prime Time? blogmarks:Dojo's ComboBox Not Ready for Prime Time? Y!:Dojo's ComboBox Not Ready for Prime Time? smarking:Dojo's ComboBox Not Ready for Prime Time? magnolia:Dojo's ComboBox Not Ready for Prime Time? segnalo:Dojo's ComboBox Not Ready for Prime Time?

4 comments

json icondojo icon

Dojo - Using dojo.io.bind

Posted in , , Sun, 04 Jun 2006 04:15:00 GMT

I recently looked into Dojo Toolkit 0.3.0's dojo.io.bind to perform AJAX requests because of it's good handling of memory leaks. I checked out the dojotoolkit.org intro page which was okay but didn't cover how to pass parameters or how to process a JSON response so I thought I'd put some info together here. Here are a few things worth knowing:

  1. A dojo response has a type that is typically set to load or error, though sometimes it may be neither. With dojo, type=="load" means success.
  2. Dojo.io.bind has a few handlers to process the response. The load handler is executed when the response type=="load" and the error handler is executed when the response type=="error". There is also a catch-all handle handler that can accept all response types so you can process a response that has a type that's neither load nor error.
  3. If request parameters are set as a hashref using content, dojo.io.bind will automatically turn them into form post parameters
  4. The response mimetype (or content-type) is set in the client JavaScript. Dojo uses this to determine how to process the response. Dojo ignores content-types set by the server

Here are two examples to help put the above together. The examples cover a plain HTML fragment response as well as a JSON response. Both examples submit a hashref. Dojo can also submit an entire form automatically. This is covered on the Dojo.IO Intro link above and isn't covered here, for now. Thanks to Toby Corkindale who posted his saveHandler function to the catalyst mailing list.

Example 1: HTML processed by load
This first example retrieves a single fragment of HTML in the response body and processes it using the load handler.

dojo.io.bind({
    url: "/binduri",
    method: "post",
    /* optional content. If the content is in the
     * form of a hashref they are converted to
     * post paramters */
    content: {
        username: "George",
        password: "curious"
    },
    load: function(type,data,evt) {
        if (data) alert('Response Data: '+data);
    },
    mimetype:'text/html'
});

Example 2: JSON processed by handle
This second example processes a JSON response using the all-in-one handle handler. The handle is typically used in special situations where load and error are not appropriate such as a progress bar. It is shown here just to provide the syntax. To process a JSON response, set the dojo.io.bind mimetype to text/json and return the JSON object in the response body.

dojo.io.bind({
    url: "/binduri",
    method: "post",
    /* optional content. If the content is in the
     * form of a hashref they are converted to
     * post paramters */
    content: {
        username: "George",
        password: "curious"
    },
    handle: function(type,data,evt) {
        if (type=='load') {
            alert( 'Successful response' );
            if (data.myItem)
                alert('Response JSON Item: '
                +data.myItem);
        } else if (type=='error') {
            alert('A error has occurred');
        } else {
            alert('Some other event has occurred');
        }
    },
    mimetype:'text/json'
});

Conclusion
Dojo.io has a nice interface that has a few conveniences including auto-conversion of a hashref to request form parameters and auto-eval of JSON set in the response body. Along with the good memory leak handling for IE, a very nice implementation.

del.icio.us:Dojo - Using dojo.io.bind digg:Dojo - Using dojo.io.bind reddit:Dojo - Using dojo.io.bind spurl:Dojo - Using dojo.io.bind wists:Dojo - Using dojo.io.bind simpy:Dojo - Using dojo.io.bind newsvine:Dojo - Using dojo.io.bind blinklist:Dojo - Using dojo.io.bind furl:Dojo - Using dojo.io.bind fark:Dojo - Using dojo.io.bind blogmarks:Dojo - Using dojo.io.bind Y!:Dojo - Using dojo.io.bind smarking:Dojo - Using dojo.io.bind magnolia:Dojo - Using dojo.io.bind segnalo:Dojo - Using dojo.io.bind

7 comments

dojo icon

Dojo - Remote Script Problem

Posted in , Sun, 04 Jun 2006 04:11:00 GMT

Dojo Toolkit 0.3.0 seems to have a problem loading it's javascript libraries remotely, i.e. when the Dojo scripts are hosted on a server different than where the HTML is. For example, if the page http://www.mysite.com/index.html includes http://www.mystatic.com/dojo/dojo.js. The main Dojo file, dojo.js, runs fine when loaded remotely, however the following fatal errors occur when it attempts to load its external libraries:

FATAL: Could not load 'dojo.io';
   last tried '__package__.js'
FATAL: Could not load 'dojo.widget.ComboBox';
   last tried '__package__.js'

It was suggested this could be due to XSS protections. Scriptaculous' scriptaculous.js, however, has a way around this since it can be loaded remotely and access it's external files (builder.js, controls.js, etc.). Often it's nice to have static files hosted on a separate server. Is there a way to fix this issue for Dojo?

UPDATE 1: For now, I'm going to stick with dojo.io.bind and Scriptaculous autocomplete. A nice thing about this set up is I can load a remote dojo.js browserio build w/o issues since it doesn't need call any external libraries for just bind.

UPDATE 2: Alex Russell provided a uri for cross domain package loading. You can turn on cross domain support by using a custom build and setting the dojoLoader option to xdomain option:

ant -Dprofile=ajax -DdojoLoader=xdomain
  -Ddocless=true clean release intern-strings

If you don't want to build it yourself, James Burke has done it and made it available as dojo-0.3.1-ajax-xd.tar.gz. This page has some more info.

del.icio.us:Dojo - Remote Script Problem digg:Dojo - Remote Script Problem reddit:Dojo - Remote Script Problem spurl:Dojo - Remote Script Problem wists:Dojo - Remote Script Problem simpy:Dojo - Remote Script Problem newsvine:Dojo - Remote Script Problem blinklist:Dojo - Remote Script Problem furl:Dojo - Remote Script Problem fark:Dojo - Remote Script Problem blogmarks:Dojo - Remote Script Problem Y!:Dojo - Remote Script Problem smarking:Dojo - Remote Script Problem magnolia:Dojo - Remote Script Problem segnalo:Dojo - Remote Script Problem

4 comments

json iconie iconprototype icon

Prototype - X-JSON fails on long value in IE

Posted in , , , Thu, 01 Jun 2006 20:14:00 GMT

Unlike Dojo Toolkit and other client-side AJAX libraries that read a JSON object from the response body, prototype.js reads it from the custom X-JSON header. I didn't run into any problems with prototype's approach developing on Firefox but I soon discovered IE 6 has a max header size that will cause prototype 1.5.0 rc0's evalJSON method to silently fail with an unreported [object Error] error. In my case, IE 6 would handle an X-JSON string with length of 138 bytes but would fail with a length of 1659 bytes. Firefox 1.5.0.3 and 1.0.7 worked fine with both strings. I'm not sure what IE 6's exact limit is but the fact there's a limit at all is discouraging IMO.

The argument I've seen for putting the JSON object in X-JSON is that you can put a separate large quanity of HTML in the response body. This design works well when you only have one or zero large quantities of HTML. As soon as you have two, you need to either put them both in the response body using another serialized data notation or put them both in the JSON object and put the JSON object in the response body instead of the X-JSON header. It seems better to simply expect the JSON object in the response body in all cases than in cases when there's only one or zero large return values.

Let's take a look at an example. In the following the one Ajax JSON response can return meta data about the overall response ("Result":"ok") as well as a list of "Posts", say when updating a post list on something like Digg's homepage. Further more a list of "Hot Stories" can simultaneously updated in the same request. Each one of the stories may have a description or overall information that exceeds IE 6's max header length.

{
  "Result":"ok",
  "Posts":[
    {
      "time":1149349580,
      "id":100001,
      "title":"Article 11 title",
      "desc":"Article 11 desc
         (longer than IE header length)",
      "votes":120,
      "comments":5,
      "submitter":"garfield"
    },
    {
      "time":1149349583,
      "id":100002,
      "title":"Article 12 title",
      "desc":"Article 12 desc
         (longer than IE header length)",
      "votes":125,
      "comments":15,
      "submitter":"garfield"
    }
  ],
  "Hot Stories":[
    {
      "time":1149348000,
      "id":1001,
      "title":"Hot Article 1 title",
      "desc":"Hot Article 1 desc
         (longer than IE header length)",
      "votes":1120,
      "comments":115,
      "submitter":"garfield"
    },
    {
      "time":1149349000,
      "id":1002,
      "title":"Hot Article 2 title",
      "desc":"Hot Article 1 desc
         (longer than IE header length)",
      "votes":1120,
      "comments":115,
      "submitter":"garfield"
    }
  ]
}

I understand where having a proprietary X-JSON header and a separate response body is useful however I view those situations as a subset of a more generic, and powerful, use. With more complex return values, putting the JSON object in the response body is ultimately a more flexible and extensible design.

I'll continue to use prototype for now but I'm going to set all my JSON objects in the response body and eval it myself given IE 6's short comings. A bigger concern for me is that I feel Prototype's use of putting the JSON object in X-JSON will encourage inefficient AJAX implementations that end up using more HTTP request/response cycles than necessary. I really hope prototype.js will move their auto-eval feature to operate on the response body due to this problem and to make it more compatible with other JS AJAX libraries at the same time.

del.icio.us:Prototype - X-JSON fails on long value in IE digg:Prototype - X-JSON fails on long value in IE reddit:Prototype - X-JSON fails on long value in IE spurl:Prototype - X-JSON fails on long value in IE wists:Prototype - X-JSON fails on long value in IE simpy:Prototype - X-JSON fails on long value in IE newsvine:Prototype - X-JSON fails on long value in IE blinklist:Prototype - X-JSON fails on long value in IE furl:Prototype - X-JSON fails on long value in IE fark:Prototype - X-JSON fails on long value in IE blogmarks:Prototype - X-JSON fails on long value in IE Y!:Prototype - X-JSON fails on long value in IE smarking:Prototype - X-JSON fails on long value in IE magnolia:Prototype - X-JSON fails on long value in IE segnalo:Prototype - X-JSON fails on long value in IE

8 comments

json iconcatalyst iconperl iconprototype icon

Prototype, JSON and Catalyst

Posted in , , , , Thu, 01 Jun 2006 00:42:00 GMT

I use the prototype.js library (aka prototype) for AJAX and recently moved to using JSON to return multiple elements instead of a single one. I had to rearchitect my client request code and my server code to handle JSON but it's worth it to minimize the number of HTTP requests. I use Catalyst and JSON::Syck which make generating the JSON response on the server-side very easy.

Prototype.js is interesting in that it auto-evals a JSON object that's placed in the X-JSON header instead of the response body like other libaries such as Dojo Toolkit. This allows you to send HTML in the response body but I'm not convinced this is a good implementation since it supports only one HTML fragment in the response body. I think it would be better to simply put the JSON object in the response body and have all the HTML fragments in the JSON object. I just seems cleaner to put all the HTML fragments in JSON instead of fragment 1 in the response body and fragments 2-n in JSON. Although I have the X-JSON header working, I may just move to the more standard JSON in response body approach and eval the JSON string myself. To read the auto-evaled JSON response, the following example expects a JSON associative array and displays the value of the myItem key (more code is available in the wiki link below):

onComplete: function( request, json ) {
    alert( json.myItem );
}

On the server-side, I use the Catalyst framework to set the header and JSON::Syck to transform Perl data structures to JSON. JSON::Syck is a wrapper around the C libsyck library and very fast. There is a view, Catalyst::View::JSON, however it puts the JSON string in the response body because that is what Dojo and other libraries expect. Since AJAX libraries don't idnetify themselves in anyway to the server (e.g. user agent), the Catalyst View would probably need a patch to with a configuration switch to populate X-JSON instead of the response body. For now, I'm using JSON::Syck directly. The following are the minimal calls to use. If you have UTF-8 output, see C::V::JSON for UTF-8 encoding.

$c->res->header(
    'X-JSON' => JSON::Syck::Dump( \%args );
);

I've put together some example code that I thought would be better placed on the wiki. It can be found at: Prototype.js, JSON and Catalyst.

UPDATE: After running into the IE max header length issue, I've decided to put the JSON object in the response body and manually eval request.responseText on the client.

del.icio.us:Prototype, JSON and Catalyst digg:Prototype, JSON and Catalyst reddit:Prototype, JSON and Catalyst spurl:Prototype, JSON and Catalyst wists:Prototype, JSON and Catalyst simpy:Prototype, JSON and Catalyst newsvine:Prototype, JSON and Catalyst blinklist:Prototype, JSON and Catalyst furl:Prototype, JSON and Catalyst fark:Prototype, JSON and Catalyst blogmarks:Prototype, JSON and Catalyst Y!:Prototype, JSON and Catalyst smarking:Prototype, JSON and Catalyst magnolia:Prototype, JSON and Catalyst segnalo:Prototype, JSON and Catalyst

6 comments

Older posts: 1 2