Getting Started
Note
This documentation assumes a reasonable understanding of javascript, html, and css. If you are brand new to frontend development you might want to learn the language and basics of html to begin with...it's worth it, and will help immensely regardless of what framework you end up using.
By far, the fastest route to get Footwork running is including it via the CDN with a simple script tag:
<script src="https://unpkg.com/footwork/dist/footwork.js"></script>
Thats all you need, toss that script tag into an HTML file and get started right away. For a super quick demo/example, take a look at the Hello World jsFiddle.
Installing¶
For a more defined project you may want to install/configure it as a dependency. Footwork is served up via the two most common frontend packagers, bower and npm:
-
To install via bower:
bower install footwork --save
-
To install via npm:
npm install footwork --save
-
To download it directly:
https://unpkg.com/footwork/dist/footwork.js
https://unpkg.com/footwork/dist/footwork.css (optional, for animations)
The Basics¶
Footwork is largely declaratively-based, logic is modularized within view models bound against those declarations. Using two-way bindings and simple constructor functions you can build rich user interfaces.
Views and View Models¶
An example view:
<viewModel module="Person" params="name: 'Jill'"> My name is <span data-bind="text: name"></span> <button data-bind="click: sayHello">Say Hello</button> <span data-bind="text: response"></span> </viewModel>
In the example above we declare a single viewModel Person
with some markup inside of it. When the application is started Footwork will iterate over the view, find the viewModel declaration, match that up with the registered viewModel, and then instantiate and bind it.
An example view model which we might bind against the view above:
fw.viewModel.register('Person', function (params) { var self = fw.viewModel.boot(this, { namespace: 'Person' }); self.name = params.name; self.response = fw.observable(); self.sayHello = function () { self.$namespace.publish('hello', self); }; self.$namespace.subscribe('hello', function (from) { if (from.name !== self.name) { self.response('Hello ' + from.name); } else { self.response(undefined); } }); }); // Start the application fw.start();
Tip
There are several different types of view models and ways to create them. Some have additional features or advantages depending on your needed use, see Creating View Models
Starting The Application¶
There are two ways of kickstarting your application:
-
fw.start
Using this method you can simply tell Footwork to start processing the DOM. Instantiation of your application then depends on the declarative viewModels, dataModels, routers, components, etc that you define in the view.
fw.start();
You can optionally pass it a root-node you want it to begin processing on (by default it assumes
document.body
):fw.start(document.getElementById('my-app'));
Once
fw.start
has been called all descendant declarations to the root node will be processed. This means any nested viewModels/components/etc will be instantiated and bound per their registrations/configurations/etc. -
fw.applyBindings
This method allows you to instantiate and bind a specific view model when binding to the view.
fw.applyBindings(new MyViewModel());
You can optionally pass it a root-node you want it to begin processing on (by default it assumes
document.body
):fw.applyBindings(new MyViewModel(), document.getElementById('my-app'));
Note
Once
fw.applyBindings
has been called all descendant declarations to the root node will be processed as well. This means any nested viewModels/components/etc will be instantiated and bound per their registrations/configurations/etc.
Browser Support and Polyfills¶
Footwork is an ES5-based library and utilizes a few of the newer ES6/HTML5 features such as:
This means that it needs at least IE9 or later, and might require that you load some polyfills (if any of the aforementioned are not natively supported by a browser you need to support).
If you require polyfills, then the following ones are recommended (they are the ones run with the tests):
- https://github.com/stefanpenner/es6-promise
- https://github.com/github/fetch
- https://github.com/devote/HTML5-History-API
Depending on your preferred package manager, they are available via bower and npm:
-
Install via bower
bower install es6-promise fetch html5-history-api --save
-
Install via npm
npm install es6-promise whatwg-fetch html5-history-api --save
These polyfills need to be loaded prior to Footwork. Here is an example using normal script tags (adjust accordingly for your preferred script loader):
<html> <head> <title>My Awesome Application</title> <!-- (optional) Need this for animation support --> <link rel="stylesheet" href="bower_components/footwork/dist/footwork.css"> </head> <body> <!-- ... application markup goes here ... --> <!-- polyfills --> <script src="bower_components/es6-promise/es6-promise.auto.js"></script> <script src="bower_components/fetch/fetch.js"></script> <script src="bower_components/html5-history-api/history.js"></script> <!-- Footwork framework --> <script src="bower_components/footwork/dist/footwork.js"></script> <!-- Your code --> <script src="scripts/my-script.js"></script> </body> </html>
Dynamic Loading of Assets¶
One of Footworks nice features is the ability to load your components/viewModels/dataModels/routers at runtime when needed.
In order To use those features you will need to ensure RequireJS is installed and linked. Footwork also requires the supporting text plugin to load your template/html files dynamically as well.
You can install these dependencies via bower and npm:
-
Install via bower
bower install requirejs requirejs-text --save
-
Install via npm
npm install requirejs requirejs-text --save
And to load these you would do something like so:
<html> <head> <title>My Awesome Application</title> <!-- (optional) Need this for animation support --> <link rel="stylesheet" href="bower_components/footwork/dist/footwork.css"> </head> <body> <!-- ... application markup goes here ... --> <!-- polyfills --> <script src="bower_components/es6-promise/es6-promise.auto.js"></script> <script src="bower_components/fetch/fetch.js"></script> <script src="bower_components/html5-history-api/history.js"></script> <!-- RequireJS --> <script src="bower_components/requirejs/require.js"></script> <script src="bower_components/text/text.js"></script> <!-- Footwork framework --> <script src="bower_components/footwork/dist/footwork.js"></script> <!-- Your code --> <script src="scripts/my-script.js"></script> </body> </html>
The above example shows a lot of ugly script tags...and whats worse is that they may cause significant lag when loading these dependencies sequentially.
It is important to remember that if you are using RequireJS you will typically load everything via RequireJS itself. This allows you to get rid of most of the script tags and allows you to optimize your application into a single file when you are ready to deploy into a production environment.
A brief example of this is shown here:
-
The main HTML file:
<html> <head> <title>My Awesome Application</title> <!-- (optional) Need this for animation support --> <link rel="stylesheet" href="bower_components/footwork/dist/footwork.css"> </head> <body> <!-- ... application markup goes here ... --> <script src="bower_components/requirejs/require.js" data-main="/path/to/main/script"></script> </body> </html>
-
The main
script.js
file:require.config({ paths: { "text": "/bower_components/text/text", "footwork": "/bower_components/footwork/dist/footwork", "es6-promise": "/bower_components/es6-promise/es6-promise", "fetch": "/bower_components/fetch/fetch", "history": "/bower_components/html5-history-api/history" } }); require(['footwork', 'es6-promise', 'fetch', 'history'], function (fw, promise) { // Promise polyfill requires an explicit call (fetch and history do not) promise.polyfill(); // Your code goes here fw.start(); } );
Much better, RequireJS will take care of the heavy lifting for us now. And whats even better, with a bit more work we can utilize the RequireJS optimizer and compile our code down into a single file (including templates).
Note
For more detailed information see: How to get started with RequireJS.