On Github scato / pomwa
by Scato Eggen / @scataco
Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard).
What does that even mean?
Research shows that if your page takes ... ms to load, half of your users will abandon your site.
Product owners always want to change something after the project is done. And often even before that happens.
Lots of JavaScript!!!
Big Ball of Mud
AJAX
JavaScript MVC
Plumbing
Layers
Combination
Design Patterns
Plan
Find reviews and discover new music
Sociological study on musical taste
"music board"
Modern: popovers...
... and modals
Why JavaScript MVC harder than Web MVC?
What is MVC?
Martin Fowler, EAA Dev
2 problems → 3 problems
Combine non-MVC with MVC
Non-MVC: easier to maintain, progressive enhancement, no re-render
MVC: harder to maintain, Separated Presentation, complex behavior
What do we agree on?
What are best practices?
6 rules
Bad:
<div style="color: red;">This is not a valid email address</div>
Good:
<div class="error">This is not a valid email address</div>
Bad:
<a href="#" onclick="openModal('/contact')">Contact</a>
Good:
<a href="javascript:;" class="contact-link">Contact</a>
Bad:
<style> .error { color: red; } </style> <script> function openModal(url) { // TODO } </script>
Good:
<link href="css/register.css" rel="stylesheet" type="text/css"> <script src="js/menu.js"></script>
Bad:
<div class="red">This is not a valid email address</div>
Good:
<div class="error">This is not a valid email address</div>
The thing you style
Not the way you style it
Bad:
<div class="lead">This is not a <i>disclaimer</i>.</div>
Good:
<div class="lead">This is not a <em>disclaimer</em>.</div>
Bad:
<div class="menu"> <span class="menu-item"><a href="/">Home</a></span> <span class="menu-item"><a href="/register">Register</a></span> </div>
Good:
<ul class="menu"> <li><a href="/">Home</a></li> <li><a href="/register">Register</a></li> </ul>
(function () { var local = 0; $('.counter').click(function () { local += 1; }); }());
Douglas Crockford, JavaScript: The Good Parts
"Don't leave home without it!"
var myNamespace = (function () { var local = 0; $('.counter').click(function () { local += 1; }); return { count: function () { return local; } }; }());
var myNamespace = {}; (function (exports) { var local = 0; $('.counter').click(function () { local += 1; }); exports.count = function () { return local; }; }(myNamespace));
Used by RequireJS
define(['jquery'], function ($) { var local = 0; $('.counter').click(function () { local += 1; }); return { count: function () { return local; } }; });
Used by Browserify and Node.js
var $ = require('jquery'); var local = 0; $('.counter').click(function () { local += 1; }); exports.count = function () { return local; };
.menu li { border-radius: 4px; background-color: #753A26; } #account-register input[type="submit"] { border-radius: 4px; background-color: #753A26; }
.menu li, #account-register input[type="submit"] { border-radius: 4px; background-color: #753A26; }
@mixin primary-button() { border-radius: 4px; background-color: #753A26; } .menu li { @include primary-button(); } #account-register input[type="submit"] { @include primary-button(); }
Sass is better: conditionals and loops
Blog post on CSS Tricks by Chris Coyier
Just try it!
There's not excuse not to use a CSS Preprocessor
Modules... but what to isolate?
Alternatives to AJAX
views/account/register.template:
<div id="account-register"> <form> <!-- ... --> </form> </div>
css/account/register.css:
#account-register form { /* ... */ }
js/account/register.js:
$('#account-register').each(function () { // ... });
It's about isolation
Use common stylesheets for:
Note: good style guides can be hard to come by
Add custom behavior
css/shared/menu.css:
.shared-menu a[href] { /* ... */ }
js/shared/menu.js:
$('.shared-menu').each(function () { // ... });
$.validator.addMethod('strong-password', function (value, element) { // ... });
<input type="password" strong-password="true">
Add extra screen state without roundtrips to the server
<div class="shared-avatar"> <input type="hidden" name="avatarId" value="3"> <!-- ... --> </div>
<span class="shared-progress" data-value="1" data-max="10"></span>
<script> var genreList = [ {"id": 1, "name": "Post-Grunge"}, {"id": 2, "name": "Post-Hardcore"} ]; </script>
Trade-off: inline js and global var!
Content Security Policy header :(
Update screen state with data from the server
$('.shared-menu').each(function () { var $menu = $(this); $menu.find('.contact-link').click(function () { $.get('/shared/contact', function (data) { $('#modal .modal-dialog').html(data); $('#modal').modal('show'); }); }); });
No client-side templates
No Web APIs
$('.shared-login').each(function () { var $login = $(this); $login.find('form').submit(function () { $.post('/shared/login', $(this).serialize(), function (data) { $login.html(data); }); }); });
POST
Some "technical difficulties"
We know what to do with non-MVC
When to use JavaScript MVC?
How to prevent lasagna code?
Page Modules
JavaScript MVC
JavaScript MVC
Code that is divided in several well-defined and separable layers, but where individual layers in the system are highly unstructured or disorganized.
Joe Celko
Different from the server-side model
Hypermedia without PUT and DELETE
{ "_links": { "self": { "href": "/user/music-board" } }, ... }
Hyperlinks work best with "networky" data, like users, bands, other users
bundle.js
shared/menu.js
account/board.js
Bundled into one asset, next to Widgets and Page Modules
No way to include half a bundle
Don't mix in Widgets and Page Modules
To summarize
Complexity where you need it
Side by side without problems
EAA Dev, very interesting
EIP, if you're getting into Web Sockets
Good Parts, if you haven't already
by Scato Eggen / @scataco
Questions?
All images licensed under Creative Commons, by: Maurice Vanderfeesten, Rennette Stowe, Rajeev3065, ちいた, CEphoto, Uwe Aranas, Eric Hadley-Ives, Jason McDonald & National Guard