"todo lists were never this easy before!"
"omg data-binding!"
"made by Google you say?"
"desk beers?"
app
controllers
someCtrl.js
# 100 more...
directives
someDirective.js
# 100 more...
templates
app
features
home-page
index.html
index.js
account
user-widget
index.html
index.js
components
breadcrumb
index.js
index.html
common
resource
index.js
:(
"You can package code as reusable modules."
"You can package code as reusable modules."
"...as long as all your code is Angular"
exports.controllers = {
"SearchCtrl": SearchCtrl,
};
exports.directives = {};
exports.routes = {
"/": {
template: require("./search.html")
},
}
function SearchCtrl() {
this.message = "hello"
}
npm install --save browserify watchify stringify
require("angular");
require("angular-route");
var _ = require("lodash");
angular.module('events', ["ngRoute"])
.config(function($controllerProvider, $compileProvider, $routeProvider) {
exports.controller = function(controller, name) {
$controllerProvider.register(name, controller);
}
// same for filter, routes, etc
// can use these for lazy-load
var deps = [
require("../create-event"),
require("../search-events"),
];
deps.forEach(function(module) {
_.each(module.controllers || {}, exports.controller)
// same for directives, filters etc
});
});
watchify -r stringify -o dist/app.js features/core/index.js
I give people one piece of advice: make smaller things
Sandi Metz (we can learn things from Rubyists)
Better to have 100 functions for one data structure than 10 functions for 10 data structures."
Explicit is better than implicit.
Zen of Python, PEP 20, Tim Peters
## Scope vars are implicit - who owns them?
<div ng-controller="GraphCtrl"
<table >
<tr ng-repeat="row in data">
</tr>
</table>
<div class='line-graph-header'>
<h3>{{ lineGraphTitle }}</h3>
</line-graph>
</div>
<data-table controller-as="dataTable" width="800 + ctrl.padding" > </data-graph> <line-graph x-scale="ctrl.scale" y-scale="ctrl.yScale" data="dataCtrl.series" width="800 + ctrl.padding" on-inspect="dataTable.data = $series" > </line-graph>
module.exports = function() {
return {
restrict: "E",
controllerAs: "ctrl",
bindToController: true,
controller: LineGraphCtrl,
link: lineGraph,
scope: {
xScale: "=",
// ...
onInspect: "&"
}
}
}
function lineGraph(scope, el, attrs, ctrl) {
// ...
points.on("click", function(d, i) {
ctrl.onInspect({
$series: d,
});
})
}
<my-widget ng-model="something">
<form name=timeForm>
<div class='extended-clock'>
<svg width=1000 height=1000 >
<g clock-input ng-model=item.time name=time></g>
<text x=500 y=500>
{{ item.time | date:"shortTime" }}
</text>
<text x=500 y=550 ng-click="toggle()">
{{ ticking ? "Stop" : "Start" }}
</text>
</svg>
</div>
</form>
function clock() {
return {
// we require an instance of ng-model to work
require: "ngModel",
link: function(scope, el, attrs, ngModel) {
// initialize the non-angular widget, and
// pass in our model updating fn
var clock = donutClock({
onInput: view2model,
el: el[0],
});
// when angular detects a change to the model,
// we update our widget
ngModel.$render = model2view;
function model2view(time) {
clock.set(ngModel.$viewValue);
}
function view2model(fromView) {
ngModel.$setViewValue(fromView);
}
}
}
}