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