I have made good progress in swapping a node.js for a Dart backend. But yesterday, when I tried some associated front-end code in the latest Dartium, I found a number of new things broken. Unfortunately, this seems fairly typical of the language nowadays. To be fair, this is a very new language nowhere near a 1.0 release. Still, it makes life hard when maintaining libraries. It makes life even harder when trying to maintain a book. But we must persevere.
So first, I work through both the code in both my Dart Comics sample app and my Hipster MVC library making changes. The bulk of the changes are preparing for the new import/library syntax. So the following:
#import('Collections.Comics.dart', prefix: 'Collections');
#import('Views.Comics.dart', prefix: 'Views');
#import('Views.AddComic.dart', prefix: 'Views');
#import('dart:html');
#import('dart:json');
#import('package:hipster_mvc/hipster_sync.dart');
main() {
// ...
}Is now written as:import 'Collections.Comics.dart' as Collections;
import 'Views.Comics.dart' as Views;
import 'Views.AddComic.dart' as Views;
import 'dart:html';
import 'dart:json';
import 'package:hipster_mvc/hipster_sync.dart';
main() {
// ...
}Unfortunately the changes do not end there. It seems that retrieving browser dimensions has changed yet again. Instead of a Future, I now need to request a layout frame: window.requestLayoutFrame(() {
var doc = window.document.documentElement;
// ...
bg.style.width = "${doc.offsetWidth}px";
bg.style.height = "${doc.clientHeight}px";
// ...
});I have changed that code more than once so that I can keep up with the language. Speaking of changes that I have made more than once, it seems that useCapture is again a regular optional parameter instead of a named optional parameter:class ModelEventList implements EventListenerList {
// ...
add(fn, [bool useCapture]) {
listeners.add(fn);
}
// ...
}With that out of the way, I again have my front-end code all in order. Best of all I can even create new records in the datastore using a combination of the Hipster MVC client library and the dart-dirty backend datastore. All that remains is a DELETE responder in my HTTP server and I will have complete functionality in place. As with all Dart HTTP responders, I first need a function that determines if the responder will handle the request. In this case, the HTTP method needs to be DELETE and the route must match
/comics/<number>:import 'dart:io';
import 'dart:json';
import 'package:dart_dirty/dirty.dart';
main() {
Dirty db = new Dirty('dart_comics.db');
HttpServer app = new HttpServer();
// ...
app.addRequestHandler(
(req) => req.method == 'DELETE' &&
new RegExp(r"^/comics/\d").hasMatch(req.path),
(req, res) { /* ... * / }
);
app.listen('127.0.0.1', 8000);
}The r before the RegExp string appears to be Dart's new way of signalling a non-interpolating string (borrowed from Python, I think). Since I do not have a dollar sign in this regular expression, I do not strictly need it, but it seems like a good habit to start here.As for the response, I need to extract the ID from the route (e.g.
/comics/42) and delete the record with that ID from dart-dirty: app.addRequestHandler(
(req) => req.method == 'DELETE' &&
new RegExp(r"^/comics/\d").hasMatch(req.path),
(req, res) {
var r = new RegExp(r"^/comics/(\d+)");
var id = r.firstMatch(req.path)[1];
db.remove(int.parse(id));
res.outputStream.writeString('{}');
res.outputStream.close();
}
);I then send back an empty record to signal that it has been successfully deleted.With that, I can add a new record from my Dart client-side application:
Then I can click the delete link:
And the record is deleted from the UI and from the persistent datastore:
Yay! So that should do it. I have replaced the node.js backend and datastore with a pure Dart equivalent. There is still a bit of cleanup that I would like to perform, but I am pretty excited about my progress.
Day #580



No comments:
Post a Comment