fat models (services) and skinny controllers
Abstraction captures only those details about an object that are relevant to the current perspective.
AngularJS live demo-example:
html:
<section ng-app="app">
<div ng-controller="appController">
<h1>Shopping Cart</h1>
<div ng-repeat="item in items">
<span>{{item.title}}</span>
<input type="number" ng-model="item.quantity">
<span>{{ item.quantity }} * {{item.price | currency}}</span> =
<span>{{item.price * item.quantity | currency}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
</div>
</section> |
<section ng-app="app">
<div ng-controller="appController">
<h1>Shopping Cart</h1>
<div ng-repeat="item in items">
<span>{{item.title}}</span>
<input type="number" ng-model="item.quantity">
<span>{{ item.quantity }} * {{item.price | currency}}</span> =
<span>{{item.price * item.quantity | currency}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
</div>
</section>
js:
var app = angular.module('app', []);
app.controller('appController', function ($scope) {
$scope.items = [{
title: 'Paint pots',
quantity: 7,
price: 12.50
}, {
title: 'Polka dots',
quantity: 2,
price: 10.00
}, {
title: 'Pebbles',
quantity: 5,
price: 25.50
}];
$scope.remove = function (index) {
$scope.items.splice(index, 1);
}
}); |
var app = angular.module('app', []);
app.controller('appController', function ($scope) {
$scope.items = [{
title: 'Paint pots',
quantity: 7,
price: 12.50
}, {
title: 'Polka dots',
quantity: 2,
price: 10.00
}, {
title: 'Pebbles',
quantity: 5,
price: 25.50
}];
$scope.remove = function (index) {
$scope.items.splice(index, 1);
}
});
AngularJS live demo-example 2:
html:
<section ng-app="myApp">
<section ng-controller="FilterCtrl">
<form>
<div>
<label>Search:</label>
<input type="text" ng-model="filterService.searchText">
</div>
<div>
<label>Sport:</label>
<select ng-model="filterService.activeFilters.sport">
<option ng-repeat="sport in ['Basketball', 'Hockey', 'Football']">{{sport}}</option>
</select>
</div>
<div>
<label>City:</label>
<select ng-model="filterService.activeFilters.city">
<option ng-repeat="city in ['Dallas', 'Los Angeles', 'Boston', 'New York']">{{city}}</option>
</select>
</div>
<div>
<label>Featured:</label>
<input type="checkbox" ng-model="filterService.activeFilters.featured" ng-false-value="" />
</div>
</form>
</section>
<section ng-controller="ListCtrl">
<table>
<thead>
<tr>
<th>Name</th>
<th>Sport</th>
<th>City</th>
<th>Featured</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="team in teamsList | filter:filterService.activeFilters | filter:filterService.searchText">
<td>{{team.name}}</td>
<td>{{team.sport}}</td>
<td>{{team.city}}</td>
<td>{{team.featured}}</td>
</tr>
</tbody>
</table>
</section>
</section> |
<section ng-app="myApp">
<section ng-controller="FilterCtrl">
<form>
<div>
<label>Search:</label>
<input type="text" ng-model="filterService.searchText">
</div>
<div>
<label>Sport:</label>
<select ng-model="filterService.activeFilters.sport">
<option ng-repeat="sport in ['Basketball', 'Hockey', 'Football']">{{sport}}</option>
</select>
</div>
<div>
<label>City:</label>
<select ng-model="filterService.activeFilters.city">
<option ng-repeat="city in ['Dallas', 'Los Angeles', 'Boston', 'New York']">{{city}}</option>
</select>
</div>
<div>
<label>Featured:</label>
<input type="checkbox" ng-model="filterService.activeFilters.featured" ng-false-value="" />
</div>
</form>
</section>
<section ng-controller="ListCtrl">
<table>
<thead>
<tr>
<th>Name</th>
<th>Sport</th>
<th>City</th>
<th>Featured</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="team in teamsList | filter:filterService.activeFilters | filter:filterService.searchText">
<td>{{team.name}}</td>
<td>{{team.sport}}</td>
<td>{{team.city}}</td>
<td>{{team.featured}}</td>
</tr>
</tbody>
</table>
</section>
</section>
js:
var app = angular.module('myApp', []);
app.factory('filterService', function () {
return {
activeFilters: {},
searchText: ''
};
});
app.controller('ListCtrl', function ($scope, filterService) {
$scope.filterService = filterService;
$scope.teamsList = [{
id: 1,
name: 'Dallas Mavericks',
sport: 'Basketball',
city: 'Dallas',
featured: true
}, {
id: 2,
name: 'Dallas Cowboys',
sport: 'Football',
city: 'Dallas',
featured: false
}, {
id: 3,
name: 'New York Knicks',
sport: 'Basketball',
city: 'New York',
featured: false
}, {
id: 4,
name: 'Brooklyn Nets',
sport: 'Basketball',
city: 'New York',
featured: false
}, {
id: 5,
name: 'New York Jets',
sport: 'Football',
city: 'New York',
featured: false
}, {
id: 6,
name: 'New York Giants',
sport: 'Football',
city: 'New York',
featured: true
}, {
id: 7,
name: 'Los Angeles Lakers',
sport: 'Basketball',
city: 'Los Angeles',
featured: true
}, {
id: 8,
name: 'Los Angeles Clippers',
sport: 'Basketball',
city: 'Los Angeles',
featured: false
}, {
id: 9,
name: 'Dallas Stars',
sport: 'Hockey',
city: 'Dallas',
featured: false
}, {
id: 10,
name: 'Boston Bruins',
sport: 'Hockey',
city: 'Boston',
featured: true
}];
});
app.controller('FilterCtrl', function ($scope, filterService) {
$scope.filterService = filterService;
}); |
var app = angular.module('myApp', []);
app.factory('filterService', function () {
return {
activeFilters: {},
searchText: ''
};
});
app.controller('ListCtrl', function ($scope, filterService) {
$scope.filterService = filterService;
$scope.teamsList = [{
id: 1,
name: 'Dallas Mavericks',
sport: 'Basketball',
city: 'Dallas',
featured: true
}, {
id: 2,
name: 'Dallas Cowboys',
sport: 'Football',
city: 'Dallas',
featured: false
}, {
id: 3,
name: 'New York Knicks',
sport: 'Basketball',
city: 'New York',
featured: false
}, {
id: 4,
name: 'Brooklyn Nets',
sport: 'Basketball',
city: 'New York',
featured: false
}, {
id: 5,
name: 'New York Jets',
sport: 'Football',
city: 'New York',
featured: false
}, {
id: 6,
name: 'New York Giants',
sport: 'Football',
city: 'New York',
featured: true
}, {
id: 7,
name: 'Los Angeles Lakers',
sport: 'Basketball',
city: 'Los Angeles',
featured: true
}, {
id: 8,
name: 'Los Angeles Clippers',
sport: 'Basketball',
city: 'Los Angeles',
featured: false
}, {
id: 9,
name: 'Dallas Stars',
sport: 'Hockey',
city: 'Dallas',
featured: false
}, {
id: 10,
name: 'Boston Bruins',
sport: 'Hockey',
city: 'Boston',
featured: true
}];
});
app.controller('FilterCtrl', function ($scope, filterService) {
$scope.filterService = filterService;
});
AngularJS core features:
- Data binding
- MVC
- Routing
- Testing
- jqLite
- Templates
- History
- Factories
- ViewModel
- Controllers
- Views
- Directives
- Services
- Dependency Injection
- Validation
AngularJS Controller purpose:
- setup the scope
- view interaction
- coordinate view and model
- application logic
AngularJS Service purpose:
- includes business logic
- handle non-view logic
- communicate with the server
- hold data and state
AngularJS Directive purpose:
- manipulate DOM (widgets, DOM events, functionality)
- receive view events
AngularJS View purpose:
- display the application
- declare bindings and directives
AngularJS recomendations:
- folder structure should reflect module structure
- treat scope as read-only in templates. Treat scope as write-only in controllers
- group your app by view (functionality/feature) and not by type
- develop with non-minified libraries
- always think about how easy to indicate what your application is doing without looking at any actual code
AngularJS performance is dictated by 2 factors:
- how many binding you have on the page
- how expensive the getter functions are
Links:
AngularJS interactive example:
html:
<section ng-app="app" class="well">
<div ng-controller="appController">
<input type="search" ng-model="search" placeholder="type to filter..." />
<app-directive></app-directive>
<h4>{{ detailedInfo }}</h4>
</div>
</section> |
<section ng-app="app" class="well">
<div ng-controller="appController">
<input type="search" ng-model="search" placeholder="type to filter..." />
<app-directive></app-directive>
<h4>{{ detailedInfo }}</h4>
</div>
</section>
js:
var app = angular.module('app', []);
app.directive('appDirective', function(){
return {
restrict: 'E',
replace: true,
template: '<ul>' +
'<li ng-repeat="country in countriesList | filter:search">' +
'<a href="#" ng-click="viewCountryDetails(country);">{{country.name}}</a>' +
'</li></ul>',
link: function($scope) {
$scope.viewCountryDetails = function(country){
$scope.detailedInfo = 'Country: ' + country.name +
'; capital: ' + country.capital +
'; population: ' + country.population;
}
}
}
});
app.controller('appController', function($scope){
$scope.countriesList = [
{name: 'Germany', capital: 'Berlin', population: '81,305,856'},
{name: 'France', capital: 'Paris', population: '65,630,692'},
{name: 'Italy', capital: 'Rome', population: '61,261,254'},
{name: 'Spain', capital: 'Madrid', population: '47,042,984'},
{name: 'United Kingdom', capital: 'London', population: '63,047,162'}
];
}); |
var app = angular.module('app', []);
app.directive('appDirective', function(){
return {
restrict: 'E',
replace: true,
template: '<ul>' +
'<li ng-repeat="country in countriesList | filter:search">' +
'<a href="#" ng-click="viewCountryDetails(country);">{{country.name}}</a>' +
'</li></ul>',
link: function($scope) {
$scope.viewCountryDetails = function(country){
$scope.detailedInfo = 'Country: ' + country.name +
'; capital: ' + country.capital +
'; population: ' + country.population;
}
}
}
});
app.controller('appController', function($scope){
$scope.countriesList = [
{name: 'Germany', capital: 'Berlin', population: '81,305,856'},
{name: 'France', capital: 'Paris', population: '65,630,692'},
{name: 'Italy', capital: 'Rome', population: '61,261,254'},
{name: 'Spain', capital: 'Madrid', population: '47,042,984'},
{name: 'United Kingdom', capital: 'London', population: '63,047,162'}
];
});
AngularJS interactive example:
html:
<div ng-app>
<div ng-controller="formController">
<input type="search" ng-model="search" placeholder="type to filter persons in dropdown list...">
<hr>
<select ng-model="selected_person" ng-options="person.name for person in people | filter:search">
<option value="">Choose a person:</option>
</select>
<hr>{{selected_person.name || 'choose a person in dropdown list...'}}
#{{selected_person.number}}
<hr>
<div>
<label>Editable Name:</label>
<input ng-model="selected_person.name">
<hr>
<label>Editable Number:</label>
<input ng-model="selected_person.number">
</div>
</div>
</div> |
<div ng-app>
<div ng-controller="formController">
<input type="search" ng-model="search" placeholder="type to filter persons in dropdown list...">
<hr>
<select ng-model="selected_person" ng-options="person.name for person in people | filter:search">
<option value="">Choose a person:</option>
</select>
<hr>{{selected_person.name || 'choose a person in dropdown list...'}}
#{{selected_person.number}}
<hr>
<div>
<label>Editable Name:</label>
<input ng-model="selected_person.name">
<hr>
<label>Editable Number:</label>
<input ng-model="selected_person.number">
</div>
</div>
</div>
js:
var formController = function ($scope) {
$scope.people = [{
name: 'Mike',
number: '1'
}, {
name: 'Donni',
number: '2'
}, {
name: 'Raph',
number: '3'
}, {
name: 'Leo',
number: '4'
}]
} |
var formController = function ($scope) {
$scope.people = [{
name: 'Mike',
number: '1'
}, {
name: 'Donni',
number: '2'
}, {
name: 'Raph',
number: '3'
}, {
name: 'Leo',
number: '4'
}]
}
AngularJS watch after changing the value of variable in the controller:
$scope.$watch('statusSelected', function(){ // watch after changes of the 'statusSelected' variable
alert('alert');
}); |
$scope.$watch('statusSelected', function(){ // watch after changes of the 'statusSelected' variable
alert('alert');
});
ng-show example:
template:
<div ng-show="uiState === 'loaded'">show if loaded</div> |
<div ng-show="uiState === 'loaded'">show if loaded</div>
controller:
$scope.uiState = 'loading';
if(/*some logic*/) {
$scope.uiState = 'loaded';
} |
$scope.uiState = 'loading';
if(/*some logic*/) {
$scope.uiState = 'loaded';
}