Monday 24 February 2014

Angular Full Stack / Bootstrap / Express setup and dev

Requirements:

  • http://yeoman.io/
    • sudo npm install -g yo
    • sudo npm install -g grunt
    • sudo npm install -g grunt-cli
    • sudo npm install -g bower
    • sudo npm install -g grunt-contrib-imagemin
  • https://github.com/yeoman/generator-karma (wasn't included with yo)
    • sudo npm install -g generator-karma
  • https://github.com/DaftMonk/generator-angular-fullstack
    • npm install -g generator-angular-fullstack
Creation process:
  1. Create a folder, then add scaffolding
    1. mkdir my-new-project && cd $_
    2. yo angular-fullstack [app-name]
      1. Select bootstrap
      2. Select standard angular modules
  2. run 'bower install'
  3. run 'grunt serve'
    1. This should open up in a browser window to see service running.
Build
  1. Run 'grunt serve:dist' to dynamically serve production code
  2. Run 'grunt build' to build app
Adding features
Run yo --help to see a full list. Most common:
  • yo angular-fullstack:controller <controller name> (excluding Ctrl, this is added for you)
  • yo angular-fullstack:view <view name> (excluding .html, i.e. list, creates partials/list.html)

Example
Adding API listing to the app
  1. yo angular-fullstack:controller ApiList
    1. Edit it to call the GET /api/apis endpoint
    2. set $scope.apis to the result
  2. yo angular-fullstack:view apilist
    1. Update the view to control the navbar and the result from the api call
      <div ng-include="'partials/navbar'"></div>
      <div class="row marketing">
          <div ng-repeat="api in apis">
              <h4>{{api.name}}</h4>
              <p>{{api.info}}</p>
          </div>
      </div>
  3. Edit app/scripts/controllers/navbar and add a new navbar item
    {
         'title': 'Apis',
          'link': '/apiList'
    }
  4. Update app/scripts/controllers/apilist.js to call the /api/apis endpoint
  5. Add another route to the /app/scripts/app.js route provider
  6. Add API call into lib/routes.js
Adding angular-ui bootstrap
  1. Add "angular-bootstrap": "0.10.0" to your bower.json file
  2. bower install
  3. Update index.html file and add dependency there
  4. Add the dependency to your module, i.e.
    1. angular.module('myApp', [...,  'ui.bootstrap'])

Friday 22 November 2013

angularjs dev setup

NOTE: Assumes nodejs / npm installed

Use http://yeoman.io/ for app scaffolding (yo), build/preview/test (grunt) and manage dependencies (bower)

sudo npm install -g yo            # grunt / bower are dependencies of yo
npm install -g generator-angular  # install generator
yo angular                        # scaffold out a AngularJS project
bower install angular-ui          # install a dependency for your project from Bower
grunt test                        # test your app
grunt serve                       # preview your app
grunt                             # build the application for deployment

For testing, karma is recommended: https://github.com/vojtajina/karma/
sudo npm install -g karma

Adding items to your project
yo angular:controller myController
yo angular:directive myDirective
yo angular:filter myFilter
yo angular:service myService

NOTE: The controller will be named whatever you specify + 'Ctrl', so running 'yo angular:controller About' will create the AboutCtrl controller.

A quick overview of yo/grunt/bower and usage: https://github.com/yeoman/yeoman/wiki/Getting-Started

Main things to edit are:
  • app/scripts/
  • app/scripts/controllers/
  • app/scripts/directives/
  • app/scripts/filters/
  • app/scripts/services/
  • app/styles
  • app/views

Routing

One gotcha is defining routes using $routeProvider. Url's in the document are defined as
<a href='#/path/to/route'>Clicky</a>
Where as the url is defined in the $routeProvider config as
function routeConfig($routeProvider) { $routeProvider. when('/path/to/route', { controller: MyController, templateUrl: 'template.html' })
...

notice this mismatch between the link (pre-ceeding '#') and the url (no '#')

https://github.com/angular-ui/ui-router Provides a way to nest views which seems a lot more powerful then the native routing.

TLS / Http CONNECT handling for proxies

Some brief notes on behaviour.

General Theory
RFC for upgrading HTTP to TLS (Specifically section 5.2)
  http://www.ietf.org/rfc/rfc2817.txt
IEFT draft spec
  http://tools.ietf.org/html/draft-luotonen-web-proxy-tunneling-01

Basic steps (Using sockets / threads):
1) received 'CONNECT host:port HTTP/1.1
2) Open socket to host:port
3) If successful send back a 'HTTP/1.1 Connection Established\n\n" response
4) connect streams of client / and terminal host:port (pass bytes freely between client / server)

Todo:

  • Using SocketChannels / Selectors for non-blocking I/O
  • Testing
    • Performance
    • Unit-testing


Application / Domain specific
nodejs impl and discussion:
  https://groups.google.com/forum/#!topic/nodejs/KDAW_xEwTEg
nodejs and connect:
  https://groups.google.com/forum/#!search/http$20connect/nodejs/MGeOheQQF28/T2VmEjjbn-0J


Saturday 20 July 2013

backbone / node / restify

Models

Use Backbone.Model.extend to define a model. Specify properties to define behaviour. (http://backbonetutorials.com/what-is-a-model/)

  • initialize: - constructor. What to call when this model is instantiated
  • defaults: an object containing default values for properties associated with the model
  • validate: a function that accepts the array of attributes to update. If this function returns a string validation will fail.
  • xxx : function(...) - where xxx is a function. Any arbitrary function can be added to model (public)
  • set / get attributes, using method on instantiated model (can be set through construction)
  • 'id' attribute - used to reference key on object. makes choice between a POST (if missing) and a PUT if present
  • urlRoot attribute (the api root of the server)
  • .save() - a method that will commit data to db, response handle by object passed to 2nd arg ({success:fn(), })
  • .fetch() - a method that will retrieve data from server using GET
  • .destroy() - a method to delete data from server using DELETE
  • .toJSON() - a method to return all attributes of model
Bind events to attributes, by using the implicit 'on' member:
this.on("change:name", function(model){ 
  var name = model.get("name"); 
}); 
'change' by itself listens to all events of the model.

Watch for generic problems
this.bind("error", function (model, error) {
  alert(error);
});

Collections

An ordered set of Backbone models, defined using Backbone.Collection.extend

Assuming there is a Model defined [i.e. var Foo = Backbone.Model.extend({...}) ]
var coll = Backbone.Collection.extend({ model: Foo }); 
Then add instances of the model to the collection (can be done in the constructor, or using add method etc)
coll.add( new Foo() );

Views

Use Backbone.View.extend to define a view.
  • initialize: View constructor. Called on instantation of View.
  • 'el' property. The HTML element the view is bound to. Any events fired must be in this div. Can set with jQuery dom element selector {el: $('#foo') } etc.
  • events: a property that defines backbone events. The can only be attached to children of the specified 'el'.
Load templates using underscore and update the view:
initialize function(){
  var template = _.template( $("#search_template").html(), {} ); 
  this.$el.html( template ); 

// bind events using the 'events' property of the view, reference 
events: { "click input[type=button]": "doSearch" }, 
doSearch: function( event ){ event.currentTarget alert( "Search for " + $("#search_input").val() ); }

Routers

Use Backbone.Router.extend to define a router. They are used to handle url routing / history. Routes interpret anything after the '#' in the URL e.g. (http://host.com/foo/#/my/location
  • routes: a property define any of the routes. These are matched in order
    • '*actions' matches anything after the # - these are called splats
    • '/foo/:id' will match this path, and pass variable 'id' to the function registered in .on('route:foo') - these are called params
    • '/foo/:param/*splat' can combine params and splats, though splats always go last as they match all
  • bookmarkable URLs, use Backbone.history.start();

Register route handlers with 'on' method
router.on('route:defaultRoute', function(actions) {});

Underscore.js

Supports basic HTML templates, with variable replacement
e.g. <div id="foo"><label><%= label_text %></label></div>
can be rendered by _.template( $("#foo").html(), {label_text : "My Label"});

Friday 19 July 2013

backbone.js and node.js (using express/jade) notes

run express to generate default express project, then run 'npm install' to download dependencies.

Download following libraries and put in public/javscripts dir
Add these references to your public/views/layout.jade file

    script(src='/javascripts/json2.js', type='text/javascript')
    script(src='/javascripts/jquery-1.10.2.js', type='text/javascript')
    script(src='/javascripts/underscore.js', type='text/javascript')
    script(src='/javascripts/backbone.js', type='text/javascript')

At this point, I should remember that it's probably better to use Restify as the backend service or express without jade as backbone provides templating via underscore, however I will probably figure out how to add that in.

Useful: http://addyosmani.github.io/backbone-fundamentals

Basic todo / localstorage tutorial: https://github.com/jeromegn/backbone.localstorage

Thursday 13 June 2013

Dropwizard / JDBI String Templating

At first glance the documentation seems straight forward, but with some updates to dropwizard framework and some undocumented additions to JDBI

Based on Brian McCallisters' original blog post: http://skife.org/jdbi/java/2011/12/21/jdbi_in_clauses.html


@UseStringTemplate3StatementLocator("/sql/templates/TestDao.sql.stg")
public interface TestDao {

 @SqlQuery
 Iterator getDevicesWithInClause(
   @BindIn("guids") List guids,
   @Bind("limit") Integer limit);
}


The main pieces of information that I had to hunt around for are:

  • @UseStringTemplate3StatementLocator replaces the now deprecated @ExternalizedSqlViaStringTemplate3
  • you can pass a value to the @UseStringTemplate3StatementLocator which is the location (on the classpath) of the string template file.
  • In your string template file, for normal @Bind parameters you still use the standard colonprefix
sql/templates/TestDao.sql.stg

group TestDao;

getDevicesWithInClause(guids, limit) ::= <<
 select distinct(guid) from table where guid in () limit :limit
>>