Wednesday, January 18, 2012

Simple Ajax GETs and JSON Parsing in Dart

‹prev | My Chain | next›

Drat! Thwarted temporarily in my efforts to get Dart to send Ajax requests with data in the request body, I set my sites a little to the side tonight. In particular, I would like to get simple listings of my comic book collection working.

The first thing I need is a REST-like listing resource for my /comics. With express.js and node-dirty, that can be written as:
var db = require('dirty')('comix.db');
// ...

app.get('/comics', function(req, res) {
  var list = [];
  db.forEach(function(id, graphic_novel) {
    if (graphic_novel) list.push(graphic_novel);
  });

  res.send(JSON.stringify(list));
});
I am going to populate the listing page almost entirely with Dart, so the initial view is breathtakingly simple:
<script src="scripts/comics.dart" type="application/dart"></script>

<h1>Dart Comics</h1>

<p>Welcome to Dart Comics</p>

<ul id="comics-list"></ul>
As for my comics.dart Dart code, I start with a small XHR to GET the /comics resource and print the results in the console:
#import('dart:html');

main() {
  var req = new XMLHttpRequest();
  req.open('get', '/comics', true);

  req.on.load.add((res) {
    print(req.responseText);
  });

  req.send();
}
I have to import the dart:html library to gain access to the XMLHttpRequest object, which is kinda important for Ajax.

Sending the request is a simple matter of calling open() with the appropriate HTTP verb and URL, and then instructing my XHR request to send() itself to the server. I pass in true as the third argument open to make this an asynchronous call so that this code will not block the browser while waiting on a response.

Since this is an asynchronous call, I need an on-load callback to be fired after the request has been successfully loaded. For this, I make use of the nice req.on.load.add syntax to add my callback that simply prints out the response.

The result, after loading the page, is:
[
  {"title":"Watchmen","author":"Alan Moore","id":"a1f9bcaa4e9939019ec9e4c36fa7a97e"},
  {"title":"Watchmen","author":"Alan Moore","id":"12e5c6c33b16399f778bad86fc6bc082"}
]
Whoops! Looks like I have duplicate entries. I will need to add validation code another day to prevent this situation. For now, I would like to list all of the returned entries along with a delete link.

For this, I iterate through each of the returned comic books, building up an HTML string along the way:
#import('dart:html');
#import('dart:json');

main() {
   var list_el = document.query('#comics-list')
    , req = new XMLHttpRequest();

  req.open('get', '/comics', true);

  req.on.load.add((res) {
    print(req.responseText);
    var list = JSON.parse(req.responseText);

    var html = '';
    list.forEach((graphic_novel) {
      html +=
        "<li id='${graphic_novel['id']}'>" +
        "${graphic_novel['title']}" +
        " " +
        "<a href='#'>[delete]</a>" +
        "</li>";
    });
  req.send();
}
Which results in:

Nice. It was fairly easy to connect my Dart application to a REST-like backend. The string interpolation with the dollar sign delimiter helps a bit with the HTML, but a template engine might still be nice. It is definitely nice to have first-level support for JSON (which I find a bit amusing considering that Javascript does not).

Satisfied with my progress so far, I will pick back up tomorrow adding event handlers to the delete links.

Day #269

1 comment:

  1. This is great work Chris. You are blazing a trail that will make it easier for the rest of us when we get there. :)

    ReplyDelete