Charlotte - 6 years of software dev experience, past 9 months focused on SPAs - So glad to be in Portland - Co-organizer of CLTFED for over a year - Local speaker at UX/dev groups
- Broad definition: All HTML, CSS, and JS is loaded onto one page (either all at once or dynamically). New content is most commonly loaded via AJAX without a page refresh. Could also be websockets, flash, silverlight, etc Example: GitHub is a collection of single page apps
13, 13 Scientific documents linked together in a way understandable by non-technical people: Hypertext, Hyperlinks Basic personal homepages linking to other pages
and PHP. Dynamically generated pages, ugly dynamic URLs based on query strings = obviously not scientific documents Only way of determining a user interaction was through server. AKA, forms! CGI = interface between form and server No structure enforced, HTML and logic interspersed willy nilly PHP: faster, but had a lot of the same problems Flash/proprietary technologies: slow loading, adverse to the open web Introduction of XHR by MS in ’99, started seeing AJAX bolted on to “classical” websites First single page apps “broke the web” = no bookmarkable URLs, can’t refresh the page, etc
the lines between designer, back-end developer, and front-end developer: show app demo Your mission, should you choose to accept it, is to learn application development principles - Loosely coupled front & back end = flexibility - Possible to add other front-ends - Caveats: if SEO is a priority, no go. - Lower overhead for server - Easy to host (static HTML, CSS, JS)
•Mobile (pair with cache manifest and local storage = offline use) •Highly interactive web apps •They can even be accessible: go to Katie Cunningham’s talk at 3:30 for more information on making JS accessible, ARIA roles, and all that good stuff.
product sites, or blogs because of search indexing • Generally, SPAs are not public and have marketing pages that can be indexed by search engines •If high interactivity is not needed
is also an option, or BYO with Grunt (show new project with brunch) •It pre-wraps your modules for you •It compiles template langs (jade, haml, stylus, sass, mustache, handlebars, etc) •It can run a test suite •JSHint plugin (which breaks the build when there is a jshint error) •Can build in development mode or production mode (compressed) •Builds to static files, so really easy to deploy • Preview server that automatically rebuilds files - Can minify and concat your CSS/JS files for you
on load/reload .active.page display block stylus: jade: // ko if: current.page().name === 'search-results' .page(data-bind='attr: { class: "active" }') //- Page code here // /ko Thursday, June 13, 13 - Hide everything by default and toggle display with the data binding
It impacts performance •Occurs when little bits of your application overstay their welcome in the heap •JS is a garbage-collected language, but there are still delays in collection that impact performance •Can affect not only your app, but other tabs that are open •Special consideration for old browsers
= $(".title"); function repaint() { causeRepaintsOn.css({ 'z-index': 1 }) } $(window).off('resize.repaint'); $(window).on('resize.repaint', _.debounce(repaint, 100)); } Thursday, June 13, 13 - Resize event - lots of events fired in Webkit/IE. Firefox only fires one event when resize completes. - Also applicable to scrolling - you probably don’t need every x/y value as it updates. - Namespacing - Calling “off” before “on” so multiple listeners aren’t out there
to: function() { searchResults = new pages.searchResults(this.params, appVM.current) }, exit: function() { searchResults.destroy(); } }); Thursday, June 13, 13 Include a destroy function that cleans up anything that you’ve set that you won’t need later: event listeners, observable values, etc.
totalBeers: ko.observable(), searchQuery: ko.observable(), errorMessages: ko.observableArray([]), page: ko.observable({}), } ko.applyBindings(current); //on dom ready Thursday, June 13, 13 - Define a viewmodel with observables. Biggest misconception = everything needs to be an observable. No! only things that you need to know about when they change. - You can store anything (objects, arrays, etc) - Call applyBindings - Create templates that bind with your observables & other JS objects - Keep track of data without relying on specific DOM elements
with: current.beer .page(data-bind='attr: { "class": "active"}') h2(data-bind='text: name + " by " + brewery.name') p(data-bind='text: abv + "% ABV"') p(data-bind='text: description') a.btn(href='#/') Search Again // /ko // /ko Thursday, June 13, 13 Default: uses HTML comments. Can also use jQuery tmpl, underscore, etc. Much easier to work with in Jade. Can use any JS expression in the data binding, not just observables
beerDetails(this.params, appVM.current) }, exit: function() { beerDetails.destroy(); } }); Thursday, June 13, 13 Don’t be one of those silly people who builds a single-page app that no one can bookmark or use their back button on! You might as well be using Flash I like PathJS because it’s library agnostic. Sammy is another popular one.
radio('progressIndicator').subscribe( function(data) { if (data === 'loading:data') return $(".loader").css({ "display": "block" }); if (data === 'loading:complete') return $(".loader").css({ "display": "none" }); }); Thursday, June 13, 13 Event emitter because observable would be too much overhead Really awesome for quick and easy inter-module communication Any time you set up a subscriber, remove it when you don’t need it anymore! UX rec: explain why progress indicators are important
appVM.current.page.subscribe(function(newPage) { if (newPage) { appVM.current.errorMessages.removeAll(); } }); // Computed Observable self.current.beerTotalDelayed = ko.computed(function() { return self.current.totalBeers() + “ on the wall”; }, 500); Thursday, June 13, 13 Useful if the value you’re monitoring is an observable!
of concerns •Flexible API backend •Can build a SPA that falls back to purely server-side code •Or you can decide that you don’t care, based on your audience
module. Set some initial properties. Call methods to kick things off like fetching data from the server and binding event handlers Define unbind/destroy functions Tell the rest of the app your module can be used Thursday, June 13, 13 Modules = JS objects Look at the BeerDetails module & config module to see in practice.
have to decide how HTML will be served •Client-side templates •Static from the server, compiled into one page (my preference) •Depends on backend. Can keep them as separated as you’d like
data drive the interface •Example: event listener in KO template; able to find the target/source of the element so the node name/id/whatever doesn’t have to be known
Charlotte - 7 years of software dev experience, past 9 months focused on SPAs - So glad to be in Portland = my cryptonite, as a vegan and huge Elliott Smith fan. <3 jQuery. May not come home. - Co-organizer of CLTFED for over a year - Local speaker at UX/dev groups - Working locally on new initiatives to educate women about development
the refresh button to refresh the DOM so you can inspect dynamically added elements You will also want to get comfy with Chrome developer tools so you can get a sense of performance