I am relatively pleased, so far, with my refactoring of my Dart Ajax powered application into more of an MVC approach. If nothing else, I have cleared away considerable amounts of the callback spaghetti code previously:
#import('dart:html');
#import('dart:json');
main() { /* ... */ }
attach_create_handler() { /* ... */ }
enable_create_form(event) { /* ... */ }
_ensure_create_form(id_selector) { /* ... */ }
_show_form(form_container) { /* ... */ }
_attach_form_handlers(form_container) { /* ... */ }
_submit_create_form(form) { /* ... */ }
_disable_create_form(event) { /* ... */ }
load_comics() { /* ... */ }
attach_handler(parent, event_selector, callback) { /* ... */ }
delete(id, [callback]) { /* ... */ }
graphic_novels_template(list) { /* ... */ }
graphic_novel_template(graphic_novel) { /* ... */ }
form_template([graphic_novel]) { /* ... */ }I replaced the bulk of that code with a collection class:#library('Collection View for My Comic Book Collection');
#import('dart:html');
#import('dart:json');
class ComicsCollectionView {
var get el;
var get collection;
ComicsCollectionView([el, collection]) {/*...*/}
// Be Backbone-lik
render() {/*...*/}
template(list) {/*...*/}
// private helper methods
_singleComicBookTemplate(comic) {/*...*/}
_attachUiHandlers() {/*...*/}
// Need to move these elsewhere
delete(id, [callback]) {/*...*/}
attach_handler(parent, event_selector, callback) {/*...*/}
}And a Collection class:#library('Collection class to describe my comic book collection');
#import('dart:html');
#import('dart:htmlimpl');
#import('dart:json');
class ComicsCollection {
var list;
var get on;
ComicsCollection() {/*...*/}
// Be List-like
forEach(fn) {/*...*/}
get length() {/*...*/}
// Be Backbone-like
fetch() {/*...*/}
// private helper methods
_handleOnLoad(event) {/*...*/}
}
// Support MVC events
class CollectionEvents implements Events {/*...*/}
class CollectionEventList implements EventListenerList {/*...*/}I especially like the Collection class—it does its thing with very few extraneous methods.The view class could probably benefit from being broken into a collection view plus a sub-view for the individual items in the collection. Aside from that, I also have a bit of Model code (
delete()) lurking in there. I will get to that in a bit (probably tomorrow). First, I would like to finish extracting code out of my earlier mess.Left in the
main() entry point of my application is Collection and View instantiation along with a call to attach_create_handler():main() {
var my_comics_collection = new ComicsCollection()
, comics_view = new ComicsCollectionView(
el:'#comics-list',
collection: my_comics_collection
);
my_comics_collection.fetch();
attach_create_handler();
}That handler function is responsible for attaching a handler to the already existing #add-comics element, establishing a click handler to display a form. Say, that sounds an awful lot like View work. So I replace attach_create_handler() with a new view:#import('ComicsCollection.dart');
#import('ComicsCollectionView.dart');
#import('AddComicView.dart');
main() {
var my_comics_collection = new ComicsCollection()
, comics_view = new ComicsCollectionView(
el:'#comics-list',
collection: my_comics_collection
);
my_comics_collection.fetch();
new AddComicView(el:'#add-comic');
}That is now the entire contents of the main comics.dart file. This is the only file that is loaded via a <script> tag. All of the other code comes from those #import() statements at the top the file. That is all kinds of nice.The
AddComicView() view is solely responsible for toggling the form:#library('Simple view to toggle new comic form view');
#import('dart:html');
#import('AddComicFormView.dart');
class AddComicView {
var get el;
var get collection;
var form_view;
AddComicView([el]) {
this.el = document.query(el);
_attachUiHandlers();
}
_attachUiHandlers() {
el.on.click.add(_toggle_form);
}
_toggle_form(event) {
if (form_view == null) {
form_view = new AddComicFormView();
form_view.render();
}
else {
form_view.remove();
form_view = null;
}
}
}The AddComicFormView is pretty straight-forward (and the guts most copied from the old callback spaghetti):#library('Form view to add new comic book to my sweet collection.');
#import('dart:html');
class AddComicFormView {
var get el;
AddComicFormView() {
this.el = new Element.html('<div id="add-comic-form"/>');
this.el.style.opacity = "0";
document.body.nodes.add(this.el);
_attachUiHandlers();
}
_attachUiHandlers() {
attach_handler(el, 'submit form', (event) {
event.preventDefault();
_submit_create_form(event.target);
});
attach_handler(el, 'click a', (event) {
event.preventDefault();
_disable_create_form(event);
});
}
render() {...}
remove() {
this.el.remove();
}
template() {
return """
<form action="comics" id="new-comic-form">
....
</form>
""";
}
_disable_create_form(event) {...}
attach_handler(parent, event_selector, callback) {...}
// Thar be model code here...
_submit_create_form(event) {...}
}And, yup, it still works:My not-another-MVC-framework framework is coming along nicely. Except for the distinct lack of "M". And the presence of Model code in the Views (e.g.
_submit_create_form()). I will address that tomorrow.Day #283

Nice post Chris. I have been enjoying the blog posts you have been submitting. Thanks!
ReplyDelete