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