javascript for flex devs

Post on 08-May-2015

9.054 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

JavaScript for Flex DevsPresented by Aaron Hardy (http://aaronhardy.com) at 360|Flex 2012 in Denver, CO.

TRANSCRIPT

JavaScript

Software Engineer, Adobe Digital Marketing Suite We enable management, measurement, execution, and

optimization of digital advertising and marketing.

HELLO my name is

@AARONIUS AARONHARDY.COM ·

No hidden agenda

Single-Page Apps

DataGrid

DataGroup

List

CurrencyFormatter TabBar

Slider Panel

Accordion ViewStack

ToggleButtonBar

EventDispatcher ArrayCollection

Bindable

NumericStepper

DragManager

Effects

Main (Application)

Header (Group)

AccountInfo (Group)

Music (ViewStack)

Artist (Group)

Menu (ToggleButtonBar)

Discography (DataGroup)

Discussion (DataGroup)

Biography (Group)

Similar Artists (List)

Basic Form Elements Div

Span

Links

? ?

? ?

? Image

?

Bulleted Lists

<html> <head> <script> buckets of vomit buckets of vomit buckets of vomit buckets of vomit buckets of vomit </script> </head> <body> buckets of vomit buckets of vomit buckets of vomit buckets of vomit buckets of vomit </body> </html>

• IDEs • MVC • Widgets/Components • Dependency management • DOM manipulation • Templating • Testing • Utilities • JavaScript + HTML + CSS

Quality ide

Libraries

Presenter
Presentation Notes
Is the product part of a larger suite? What is the rest of the suite using? How hard would it be for us to refactor to another library? Is it a fad or popular for good reason? What’s the community like? How open-source is it? What’s the learning curve? How easy is it to hire developers that want to work with it?

Rolling your own

jquery underscore.js

backbone.js requirejs

All MIT license (+ other options) and on GitHub

Learn Javascript

Never build large apps The secret to building large apps is NEVER build large apps. Break up your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application. – Justin Meyer

Admit what you don’t know

The key is to acknowledge from the start that you have no idea how this will grow. When you accept that you don’t know everything, you begin to design the system defensively. – Nicholas Zakas

Add "use strict"; before code or at beginning of function to help decrapify your code.

• Eliminates pitfalls by raising errors • Improves JS engine optimization • Prohibits syntax reserved for future JS versions * Won’t be used in examples to save slide space

JSLint or JSHint. • Run in IDE. • Run on command line. • Run in build scripts. • Copy-paste into web interface. • Use flags for configuration.

General community style: • Names of directories and files shall be lowercase and

hyphens shall be used to separate words. • Variable names shall be camelCase. • Classes (functions) to be instantiated shall start with a

capital letter. • Members intended to be private shall be prefixed with

an underscore.

Loose typing == more testing! • JsTestDriver • QUnit • Jasmine • Vows • …and bucket-loads more

jquery

• Not an application framework! • Abstracts the DOM

• Style • Position • Behavior • Animation • Creation/Removal

• AJAX requests • Utilities for objects, arrays, strings, etc. • “Framework” for UI widgets and utilities

Usage by Top Sites

http://trends.builtwith.com/javascript/jQuery

• Performance-tuned servers • Allows browser to have more concurrent connections • Cross-site caching

Toolbox of array, object, and function manipulation utilities.

var names = _.pluck( [{name: 'moe', age: 40}, {name: 'larry', age: 50}], 'name'); var person = _.extend({name: 'moe'}, {age: 50}); var uniques = _.union([1, 2, 3], [101, 2, 10], [2, 1]);

And bucket-loads more…

Old-school var tweetTemplate = '' + '<div>' + '<div style="float: left">' + '<img src="' + avatar + '"/>' + '</div>' + '<div style="margin-left: 60px">' + '<p>' + username + '</p>' + '<p>' + text + '</p>' + '</div>' + '<div>';

Old-school • HTML buried in logic (hard to re-skin) • Concatenation/escaping takes time and is error-prone • IDE might not code-hint or color-code properly • Boring and tedious

New-school <script type="text/template" id="tweet-template"> <div> <div style="float: left"> <img src="<%= avatar %>"/> </div> <div style="margin-left: 60px"> <p><%= username %></p> <p><%= text %></p> </div> </div> </script> <script> var tweet = {avatar: 'aaronius.jpg', alias: '@Aaronius', text: 'Honey roasted peanuts rock my sox.'}; var template = _.template($('#tweet-template').html()); var html = template(tweet); var element = $(html); </script>

Presenter
Presentation Notes
How to handle many templates.

• Mustache.js • Handlebars.js • Jade • Eco • …and bucket-loads more. Underscore.js templating is one of the best (though not as full-featured) and is a dependency of Backbone.js. You can use any templating engine.

backbone

Presenter
Presentation Notes
MV* Application Framework Non-prescriptive 1200 lines of code (with comments) Extensible

Object A passes a function to object B and tells object B to call the function when X occurs. When X occurs, object B calls the function.

backbone.events

Presenter
Presentation Notes
Like EventDispatcher

var baby = new Baby(); var changeDeuceTrap = function() { baby.deuces = 0; baby.cakeHoleShut = true; }; baby.on('turdDropped', changeDeuceTrap); Baby:

this.trigger('turdDropped');

Dad:

Mix into any object or class var baby = new Baby(); baby = _.extend(baby, Backbone.Events); baby.on(…); baby.trigger(…);

backbone.Model

Presenter
Presentation Notes
Like [Bindable] model

Plain Old JavaScript Object var book = { title: 'A Tale of Two Cities', author: 'Charles Dickens', genre: 'historical', publisher: 'Chapman & Hall' };

How can another object know when one of book’s values changes? It can’t!

Eventful Backbone.Model var book = new Backbone.Model({ title: 'A Tale of Two Cities', author: 'Charles Dickens', genre: 'historical', publisher: 'Chapman & Hall' }); book.on('change:genre', function(model, genre) { alert('genre for ' + model.get('title') + ' changed to ' + genre); }); book.set({genre: 'social criticism'});

Extending Backbone.Model var Book = Backbone.Model.extend({ …custom model logic… }); var book = new Book({ title: 'A Tale of Two Cities', author: 'Charles Dickens', publisher: 'Chapman & Hall' });

Persistence HTTP Method URL Action

GET /books Retrieve all books

GET /books/10 Retrieve book with id == 10

POST /books Add a book

PUT /books/10 Update book with id == 10

DELETE /books/10 Delete book with id == 10

Persistence (save) var Book = Backbone.Model.extend({ urlRoot: '/books' }); var book = new Book({title: 'The Tragedy of the Commons'}); book.save();

Persistence (fetch) var Book = Backbone.Model.extend({ urlRoot: '/books' }); var book = new Book({id: 2}); var fetchSuccess = function() { alert(book.get('title')); }; book.fetch({success: fetchSuccess});

MODEL layersOpen

characterOpen magicWandOpen

colorOpen infoOpen

And more… • Validation • Extracting native object • Determine which attributes have changed • And bucket-loads more…

backbone.collection

Presenter
Presentation Notes
Like ArrayCollection

Plain Old JavaScript Array: var books = [book1, book2, book3, book4];

How can another object know when an item is added or removed from this array? It can’t!

var goodEarth = new Backbone.Model(); var books = new Backbone.Collection(); books.on('add', function(book, books, options) { alert('Book ' + book.get('title') + ' added at index ' + options.at + '. ' + 'The collection now contains ' + books.length + ' models.'); }; books.on('remove', function(book, books, options) { alert('Book ' + book.get('title') + ' removed from index ' + options.index); } books.add(goodEarth); books.remove(goodEarth);

var books = new Backbone.Collection([taleOfTwoCities, goodEarth]); books.on('change:title', function(book, title) { alert('Book title changed from ' + book.previous('title') + ' to ' + title); }); goodEarth.set({title: 'Good Earth, The'});

Event Pass-through

Presenter
Presentation Notes
Similar to PropertyChangeEvent

Persistence (fetch) var Books = Backbone.Collection.extend({ model: Book, url: '/books' }); var books = new Books(); books.fetch();

Underscore mix-ins var titles = books.pluck('title');

each(), reduce(), find(), filter(), reject(), shuffle(), without() and bucket-loads more!

And more… • Sorting • Resetting • Retrieving model by id or index • Custom loading and parsing • …and bucket-loads more!

Backbone view

Presenter
Presentation Notes
Case Study: Update view when tweet is sent

Tweet Model

Tweet Collection

Tweet

Tweet

Tweet

Tweet

Tweet

Tweet

Stats Model

Presenter
Presentation Notes
Case Study: Update view when tweet is sent

var Tweet = Backbone.Model.extend({ …view logic… }); var TweetRow = Backbone.View.extend({ …view logic… }); var tweet = new Tweet({ avatar: 'aaronius.jpg', alias: '@Aaronius', text: 'Honey roasted peanuts rock my sox.' }); var row = new TweetRow({ model: tweet });

var TweetRow = Backbone.View.extend({ _template: _.template($('#tweet-row-template').html()), initialize: function() { this.render(); }, render: function() { this.$el.html(this._template(this.model.toJSON())); return this; } });

<script type="text/template" id="tweet-row-template"> <div style="float: left"><img src="<%= avatar %>"/></div> <div style="margin-left: 60px"> <p><%= username %></p> <p><%= text %></p> </div> </script>

Presenter
Presentation Notes
Significance of this.el

Backbone router

backbone extensions

requirejs

Must we be restricted to working inside a few monstrous spaghetti files? NO! Then why are they so prevalent? • “That’s the way JavaScript has been done in the past.” • “Loading many JavaScript files requires many HTTP

requests resulting in longer load times.” • “Dependency management is hard in JavaScript.” We can do better!

// What are the dependencies here!? // What if a new employee had to re-order for some reason!? <script src="script3.js"></script> <script src="script1.js"></script> <script src="script7.js"></script> <script src="script6.js"></script> <script src="script4.js"></script> <script src="script5.js"></script> <script src="script9.js"></script> <script src="script8.js"></script> <script src="script10.js"></script> <script src="script2.js"></script>

Old school

script4.js

script5.js script6.js script9.js

script10.js script7.js

script8.js script1.js

script2.js

script3.js

ServerJS CommonJS Module Async module definition (AMD) RequireJS

Presenter
Presentation Notes
Kevin Dangoor

define({ title: "My Sister's Keeper", publisher: "Atria" });

book.js

define([ 'book' ], function(book) { return { listBook: function() { alert(book.title); } }; });

bookshelf.js

<!DOCTYPE html> <html> <head> <title>RequireJS Example</title> <script data-main="js/main“ src="js/libs/require.js"></script> </head> <body/> </html>

index.html

require([ 'bookshelf' ], function(bookshelf) { bookshelf.listBook(); });

main.js

<span class="label">Title:</span> <span class="value"><%= title %></span><br/> <span class="label">Author:</span> <span class="value"><%= author %></span><br/> <span class="label">Genre:</span> <span class="value"><%= genre %></span>

templates/book.tpl.html

define([ 'backbone', 'underscore', 'text!templates/book.tpl.html' ], function(Backbone, _, template) { return Backbone.View.extend({ _template: _.template(template), initialize: function() { this.render(); }, render: function() { var nativeBook = this.model.toJSON(); var html = this._template(nativeBook); this.$el.html(html); return this; } }); });

book-view.js

define([ 'backbone', 'underscore', 'book-view' ], function(Backbone, _, BookView) { return Backbone.View.extend({ … create child book views as necessary … … new BookView() … }); });

bookshelf-view.js

requirejs optimization

Thank you!

@Aaronius aaronhardy.com

encore (stuff I fit in if time allows)

Persistence with custom url pattern: var Book = Backbone.Model.extend({ urlRoot: '/books', url: function() { return this.urlRoot + '?id=' + this.get('id'); } }) var book = new Book({id: 2}); book.fetch();

var App = Backbone.View.extend({ initialize: function() { this.render(); }, render: function() { var tweet = new Tweet({ avatar: 'avatar.jpg', username: '@Aaronius', text: 'Honey roasted peanuts rock my sox.' }); var row = new TweetRow({ model: tweet }); this.$el.append(row.$el); return this; } }); var app = new App({el: $('body')});

var DocumentView = Backbone.View.extend({ events: { "dblclick" : "open", "click .icon.doc" : "select", "mouseover .title .date" : "showTooltip" }, render: function() { ... }, open: function() { ... }, select: function() { ... }, showTooltip: function() { ... }, });

<script type="text/javascript"> $(function() { var AppRouter = Backbone.Router.extend({ routes: { "shirt/id/:id": "showShirt" }, showShirt: function(id) { alert('Show shirt with id ' + id); } }); var appRouter = new AppRouter(); Backbone.history.start(); }); </script> <a href="#shirt/id/5">Shirt with id of 5</a><br> <a href="#shirt/id/10">Shirt with id of 10</a><br> <a href="#shirt/id/15">Shirt with id of 15</a><br>

<script type="text/javascript"> $(function() { var AppRouter = Backbone.Router.extend({ routes: { ":product/:attribute/:value": "showProduct" }, showProduct: function(product, attribute, value) { alert('Show ' + product + ' where ' + attribute + ' = ' + value + '.'); } }); var appRouter = new AppRouter(); Backbone.history.start(); }); </script> <a href="#shoe/size/12">Size 12 shoes</a><br> <a href="#shirt/id/5">Shirt with id of 5</a><br> <a href="#hat/color/black">Black hats</a>

var AppRouter = Backbone.Router.extend({ routes: { ":product/:attribute/:value": "showProduct" } }); var MyView = Backbone.View.extend({ initialize: function(options) { options.router.on('route:showProduct', this._showProduct); } _showProduct: function(product, attribute, value) { alert('Update to show ' + product + ' where ' + attribute + ' = ' + value + '.'); } }); var appRouter = new AppRouter(); var view = new MyView({router: appRouter}); Backbone.history.start();

Fragment Identifier • Using URLs in unintended ways • Dependent on JavaScript • Controversial • Used by many popular sites pushState aka HTML5 History • The bee’s knees • Allows changing of core url without changing pages • Long-term solution • Browser support lacking (guess which browser)

top related