Getting Started

Setup AngularJS

<!-- AngularJS via CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>

<!-- For development (includes debugging tools) -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.js"></script>
Note: AngularJS 1.x is different from Angular (2+). This cheatsheet covers AngularJS 1.x.

Basic Template

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body>
<div ng-controller="MyController">
<h1>Hello, {{name}}!</h1>
<input type="text" ng-model="name">
</div>

<script>
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
$scope.name = 'AngularJS';
});
</script>
</body>
</html>

Directives

Core Directives

<!-- ng-app: Defines the AngularJS application -->
<div ng-app="myApp">...</div>

<!-- ng-model: Binds form elements to model data -->
<input type="text" ng-model="username">

<!-- ng-bind: Binds innerHTML to model data -->
<p ng-bind="username"></p>

<!-- ng-controller: Defines a controller -->
<div ng-controller="MyController">...</div>

<!-- ng-repeat: Repeats HTML for each item in a collection -->
<li ng-repeat="item in items">{{item.name}}</li>

<!-- ng-show/ng-hide: Shows/hides elements -->
<div ng-show="isVisible">Visible content</div>
<div ng-hide="isHidden">Hidden content</div>

<!-- ng-if: Conditionally includes HTML -->
<div ng-if="user.loggedIn">Welcome back!</div>

<!-- ng-class: Dynamically sets CSS classes -->
<div ng-class="{active: isActive, 'text-muted': isDisabled}">...</div>

<!-- ng-style: Sets CSS styles -->
<div ng-style="{color: myColor, 'font-size': fontSize + 'px'}">...</div>

Event Directives

<!-- ng-click: Handles click events -->
<button ng-click="count = count + 1">Increment</button>
<button ng-click="submitForm()">Submit</button>

<!-- ng-dblclick: Handles double click events -->
<div ng-dblclick="editItem(item)">Double click to edit</div>

<!-- ng-change: Handles change events -->
<input type="text" ng-model="username" ng-change="checkUsername()">

<!-- ng-blur: Handles blur events -->
<input type="email" ng-model="email" ng-blur="validateEmail()">

<!-- ng-focus: Handles focus events -->
<input type="text" ng-model="search" ng-focus="showSuggestions()">

<!-- ng-keyup, ng-keydown, ng-keypress -->
<input type="text" ng-keyup="checkEnter($event)">

<!-- ng-mouseenter, ng-mouseleave -->
<div ng-mouseenter="showTooltip()" ng-mouseleave="hideTooltip()">Hover me</div>

<!-- ng-submit: Handles form submission -->
<form ng-submit="processForm()">
<input type="text" ng-model="data">
<button type="submit">Submit</button>
</form>

Expressions & Filters

Expressions

<!-- Basic expressions -->
<p>Hello, {{user.name}}!</p>
<p>Total: {{quantity * price}}</p>
<p>Status: {{isActive ? 'Active' : 'Inactive'}}</p>

<!-- Using functions in expressions -->
<p>Welcome, {{getFullName()}}</p>
<p>Next year: {{currentYear + 1}}</p>

<!-- Object access -->
<p>City: {{user.address.city}}</p>
<p>Zip: {{user['address']['zip']}}</p>

<!-- Array access -->
<p>First item: {{items[0]}}</p>
<p>Array length: {{items.length}}</p>

<!-- One-time binding (AngularJS 1.3+) -->
<p>Initial value: {{::initialValue}}</p>

<!-- ng-bind for one-time binding -->
<span ng-bind="::user.name"></span>

Filters

<!-- Built-in filters -->
<p>{{ price | currency }}</p>
<p>{{ date | date:'medium' }}</p>
<p>{{ message | uppercase }}</p>
<p>{{ text | limitTo:100 }}</p>
<p>{{ object | json }}</p>
<p>{{ items | filter:searchText }}</p>
<p>{{ items | orderBy:'name' }}</p>

<!-- Chaining filters -->
<p>{{ date | date:'fullDate' | uppercase }}</p>
<p>{{ items | filter:searchText | orderBy:'name' }}</p>

<!-- Using filters in JavaScript -->
<script>
app.controller('MyCtrl', function($scope, $filter) {
$scope.formattedDate = $filter('date')($scope.rawDate, 'yyyy-MM-dd');
$scope.upperText = $filter('uppercase')($scope.text);
});
</script>

<!-- Creating custom filters -->
<script>
app.filter('reverse', function() {
return function(input) {
return input.split('').reverse().join('');
};
});
</script>
<p>{{ 'hello' | reverse }}</p> <!-- Displays 'olleh' -->

Controllers & Scope

Controllers

<!-- Basic controller -->
<script>
var app = angular.module('myApp', []);

app.controller('MyController', function($scope) {
$scope.message = 'Hello World!';
$scope.user = { name: 'John', age: 30 };

$scope.sayHello = function() {
alert('Hello ' + $scope.user.name);
};
});
</script>

<!-- Controller with dependencies -->
<script>
app.controller('UserController', ['$scope', '$http', '$location',
function($scope, $http, $location) {
$scope.loadUser = function() {
$http.get('/api/user').then(function(response) {
$scope.user = response.data;
});
};

$scope.redirect = function(path) {
$location.path(path);
};
}]);
</script>

<!-- Controller As syntax -->
<script>
app.controller('MyController', function() {
this.message = 'Hello World!';
this.sayHello = function() {
alert(this.message);
};
});
</script>
<div ng-controller="MyController as ctrl">
<p>{{ctrl.message}}</p>
<button ng-click="ctrl.sayHello()">Say Hello</button>
</div>

Scope

<!-- $scope properties and methods -->
<script>
app.controller('MyController', function($scope) {
// Primitive values
$scope.title = 'My App';
$scope.count = 0;

// Objects
$scope.user = {
name: 'John Doe',
email: 'john@example.com'
};

// Arrays
$scope.items = ['Item 1', 'Item 2', 'Item 3'];

// Functions
$scope.increment = function() {
$scope.count++;
};

$scope.addItem = function(item) {
$scope.items.push(item);
};

// $watch for changes
$scope.$watch('count', function(newVal, oldVal) {
console.log('Count changed from ' + oldVal + ' to ' + newVal);
});

// $watch for object changes
$scope.$watch('user', function(newVal, oldVal) {
console.log('User changed');
}, true); // deep watch
});
</script>

<!-- Scope inheritance example -->
<div ng-controller="ParentController">
Parent: {{parentValue}}
<div ng-controller="ChildController">
Child: {{parentValue}} <!-- Inherits from parent -->
Child: {{childValue}}
</div>
</div>

Services

Built-in Services

<!-- $http service for AJAX requests -->
<script>
app.controller('MyController', function($scope, $http) {
// GET request
$http.get('/api/users')
.then(function(response) {
$scope.users = response.data;
})
.catch(function(error) {
console.error('Error:', error);
});

// POST request
$http.post('/api/users', { name: 'John', age: 30 })
.then(function(response) {
console.log('User created:', response.data);
});

// With configuration
$http({
method: 'GET',
url: '/api/users',
params: { limit: 10, offset: 20 },
headers: { 'Authorization': 'Bearer token123' }
}).then(function(response) {
$scope.users = response.data;
});
});
</script>

<!-- $timeout and $interval -->
<script>
app.controller('MyController', function($scope, $timeout, $interval) {
// $timeout - single delay
$timeout(function() {
$scope.message = 'This appears after 2 seconds';
}, 2000);

// $interval - repeated execution
var counter = 0;
var stop = $interval(function() {
counter++;
$scope.counter = counter;
if (counter >= 10) {
$interval.cancel(stop);
}
}, 1000);
});
</script>

<!-- $location service -->
<script>
app.controller('MyController', function($scope, $location) {
// Get current path
$scope.currentPath = $location.path();

// Change location
$scope.goTo = function(path) {
$location.path(path);
};

// Get search parameters
$scope.searchParams = $location.search();
});
</script>

Custom Services

<!-- Creating a service with .service() -->
<script>
app.service('UserService', function() {
this.users = [];

this.addUser = function(user) {
this.users.push(user);
};

this.getUsers = function() {
return this.users;
};

this.clearUsers = function() {
this.users = [];
};
});
</script>

<!-- Creating a service with .factory() -->
<script>
app.factory('DataService', function() {
var data = {};

var service = {
set: function(key, value) {
data[key] = value;
},
get: function(key) {
return data[key];
},
getAll: function() {
return data;
}
};

return service;
});
</script>

<!-- Creating a value service -->
<script>
app.value('apiKey', 'abc123def456ghi789');
app.value('appConfig', {
version: '1.0.0',
environment: 'development',
apiUrl: 'https://api.example.com'
});
</script>

<!-- Creating a constant service -->
<script>
app.constant('APP_NAME', 'My AngularJS App');
app.constant('MAX_FILE_SIZE', 10485760); // 10MB
</script>

<!-- Using custom services in controllers -->
<script>
app.controller('MyController', function($scope, UserService, DataService, apiKey, appConfig) {
$scope.apiKey = apiKey;
$scope.config = appConfig;

$scope.addUser = function(user) {
UserService.addUser(user);
};

$scope.getUsers = function() {
return UserService.getUsers();
};

$scope.saveData = function(key, value) {
DataService.set(key, value);
};

$scope.loadData = function(key) {
return DataService.get(key);
};
});
</script>

Routing

Basic Routing

<!-- Include ngRoute module -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular-route.min.js"></script>

<!-- Set up the app to use ngRoute -->
<script>
var app = angular.module('myApp', ['ngRoute']);

app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutController'
})
.when('/contact', {
templateUrl: 'views/contact.html',
controller: 'ContactController'
})
.when('/user/:id', {
templateUrl: 'views/user.html',
controller: 'UserController'
})
.otherwise({
redirectTo: '/'
});
});
</script>

<!-- Add ng-view directive to your HTML -->
<div ng-view></div>

<!-- Navigation links with href -->
<a href="#/">Home</a>
<a href="#/about">About</a>
<a href="#/contact">Contact</a>
<a href="#/user/123">User Profile</a>

<!-- Navigation with ng-href -->
<a ng-href="#/user/{{userId}}">My Profile</a>

Advanced Routing

<!-- Route with resolve -->
<script>
app.config(function($routeProvider) {
$routeProvider
.when('/dashboard', {
templateUrl: 'views/dashboard.html',
controller: 'DashboardController',
resolve: {
userData: function(UserService) {
return UserService.getUser();
},
appSettings: function(ConfigService) {
return ConfigService.loadSettings();
}
}
});
});

// Controller using resolved data
app.controller('DashboardController', function($scope, userData, appSettings) {
$scope.user = userData;
$scope.settings = appSettings;
});
</script>

<!-- Using $routeParams -->
<script>
app.controller('UserController', function($scope, $routeParams) {
$scope.userId = $routeParams.id;

// Load user based on ID
$scope.loadUser = function() {
UserService.getUser($scope.userId).then(function(user) {
$scope.user = user;
});
};
});
</script>

<!-- Using $route service -->
<script>
app.controller('NavController', function($scope, $route) {
// Watch for route changes
$scope.$on('$routeChangeSuccess', function(event, current, previous) {
$scope.currentRoute = current.originalPath;
});

// Check if a route is active
$scope.isActive = function(route) {
return $route.current && $route.current.originalPath === route;
};
});
</script>

<!-- HTML with active route highlighting -->
<nav>
<a href="#/" ng-class="{active: isActive('/')}">Home</a>
<a href="#/about" ng-class="{active: isActive('/about')}">About</a>
<a href="#/contact" ng-class="{active: isActive('/contact')}">Contact</a>
</nav>

Form Validation

Form Basics

<!-- Basic form with validation -->
<form name="userForm" ng-submit="submitForm()" novalidate>

<div class="form-group">
<label>Name:</label>
<input type="text" name="userName" ng-model="user.name" required class="form-control">
<span ng-show="userForm.userName.$error.required && userForm.userName.$touched" class="text-danger">
Name is required.
</span>
</div>

<div class="form-group">
<label>Email:</label>
<input type="email" name="userEmail" ng-model="user.email" required class="form-control">
<span ng-show="userForm.userEmail.$error.required && userForm.userEmail.$touched" class="text-danger">
Email is required.
</span>
<span ng-show="userForm.userEmail.$error.email && userForm.userEmail.$touched" class="text-danger">
Please enter a valid email.
</span>
</div>

<button type="submit" ng-disabled="userForm.$invalid" class="btn btn-primary">
Submit
</button>

</form>

<!-- Display form validation states -->
<div>
Form valid: {{userForm.$valid}}<br>
Form invalid: {{userForm.$invalid}}<br>
Form submitted: {{userForm.$submitted}}<br>
Form pristine: {{userForm.$pristine}}<br>
Form dirty: {{userForm.$dirty}}<br>
</div>

Advanced Validation

<!-- Custom validation with ng-pattern -->
<div class="form-group">
<label>Username:</label>
<input type="text" name="username" ng-model="user.username" ng-pattern="/^[a-zA-Z0-9_]{3,20}$/" required class="form-control">
<span ng-show="userForm.username.$error.pattern" class="text-danger">
Username must be 3-20 characters and can only contain letters, numbers, and underscores.
</span>
</div>

<!-- Custom validation with directive -->
<script>
app.directive('validatePassword', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$validators.password = function(modelValue, viewValue) {
var value = modelValue || viewValue;
// At least 8 chars, one uppercase, one lowercase, one number
return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(value);
};
}
};
});
</script>

<div class="form-group">
<label>Password:</label>
<input type="password" name="password" ng-model="user.password" validate-password required class="form-control">
<span ng-show="userForm.password.$error.password" class="text-danger">
Password must be at least 8 characters and contain at least one uppercase letter, one lowercase letter, and one number.
</span>
</div>

<!-- Matching password confirmation -->
<div class="form-group">
<label>Confirm Password:</label>
<input type="password" name="confirmPassword" ng-model="user.confirmPassword" compare-to="user.password" required class="form-control">
<span ng-show="userForm.confirmPassword.$error.compareTo" class="text-danger">
Passwords do not match.
</span>
</div>

<!-- Custom compare-to directive -->
<script>
app.directive('compareTo', function() {
return {
require: 'ngModel',
scope: {
otherModelValue: '=compareTo'
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
return modelValue == scope.otherModelValue;
};

scope.$watch('otherModelValue', function() {
ngModel.$validate();
});
}
};
});
</script>

Best Practices

Performance

// 1. Limit watchers
// Use one-time binding (::) where possible
<h1>{{::pageTitle}}</h1>
<span ng-bind="::user.name"></span>

// 2. Use track by in ng-repeat
<li ng-repeat="item in items track by item.id">
{{item.name}}
</li>

// 3. Debounce ng-model updates
<input type="text" ng-model="searchQuery" ng-model-options="{ debounce: 300 }">

// 4. Avoid expensive operations in templates
// Instead of:
<div>{{ calculateTotal() }}</div>

// Prefer:
<script>
$scope.$watch('items', function(newItems) {
$scope.total = calculateTotal(newItems);
}, true);
</script>
<div>{{total}}</div>

// 5. Use $applyAsync and $digest
<script>
// Instead of $apply, use $applyAsync when possible
$scope.$applyAsync(function() {
$scope.data = newData;
});

// Or use $timeout for safe apply
$timeout(function() {
// Code that might need a digest cycle
});
</script>

Code Organization

// 1. Use Controller As syntax
<div ng-controller="UserController as userCtrl">
<h1>{{userCtrl.title}}</h1>
<button ng-click="userCtrl.save()">Save</button>
</div>

app.controller('UserController', function() {
this.title = 'User Profile';
this.save = function() {
// Save logic
};
});

// 2. Use modules to organize code
// app.js
angular.module('myApp', ['myApp.controllers', 'myApp.services', 'myApp.directives']);

// controllers.js
angular.module('myApp.controllers', [])
.controller('MainController', function() {})
.controller('UserController', function() {});

// services.js
angular.module('myApp.services', [])
.service('UserService', function() {})
.factory('DataService', function() {});

// 3. Use dependency injection array syntax
app.controller('MyController', ['$scope', '$http', 'UserService',
function($scope, $http, UserService) {
// Controller logic
}]);

// 4. Use constants for configuration
app.constant('APP_CONFIG', {
apiUrl: 'https://api.example.com',
version: '1.0.0',
debug: true
});

// 5. Use services for business logic
app.service('UserService', function() {
this.getUser = function(id) {
// API call logic
};

this.saveUser = function(user) {
// Save logic
};
});

Quick Reference

Common Patterns

// 1. Toggle functionality
<button ng-click="isVisible = !isVisible">Toggle</button>
<div ng-show="isVisible">Content</div>

// 2. Load data on controller initialization
app.controller('MyController', function($scope, DataService) {
$scope.items = [];

$scope.loadData = function() {
DataService.getItems().then(function(response) {
$scope.items = response.data;
});
};

// Load data immediately
$scope.loadData();
});

// 3. Form reset
$scope.resetForm = function() {
$scope.user = {};
$scope.userForm.$setPristine();
$scope.userForm.$setUntouched();
};

// 4. Filter and search
<input type="text" ng-model="searchText" placeholder="Search...">
<div ng-repeat="item in items | filter:searchText">
{{item.name}}
</div>

// 5. Pagination
$scope.currentPage = 1;
$scope.itemsPerPage = 10;

$scope.paginatedItems = function() {
var start = ($scope.currentPage - 1) * $scope.itemsPerPage;
var end = start + $scope.itemsPerPage;
return $scope.items.slice(start, end);
};

$scope.totalPages = Math.ceil($scope.items.length / $scope.itemsPerPage);

Common Pitfalls

// 1. Dot rule in ng-model
// Avoid:
<input type="text" ng-model="username">
// This creates a child scope property, not on the parent scope

// Prefer:
<input type="text" ng-model="user.username">
// This ensures proper scope inheritance

// 2. ng-if creates a child scope
<div ng-if="condition">
<input type="text" ng-model="value">
<!-- This creates a child scope property -->
</div>

// 3. Using $index in ng-repeat with dynamic lists
// Avoid using $index as a unique identifier
<div ng-repeat="item in items">
<input type="text" ng-model="item.name">
<button ng-click="removeItem($index)">Remove</button>
<!-- $index changes when items are filtered or sorted -->
</div>

// Prefer using track by with a unique identifier
<div ng-repeat="item in items track by item.id">
<input type="text" ng-model="item.name">
<button ng-click="removeItem(item.id)">Remove</button>
</div>

// 4. Memory leaks with $watch and $on
// Always deregister watchers and listeners
var deregister = $scope.$watch('value', function(newVal) {
// Watch logic
});

// Deregister when no longer needed
$scope.$on('$destroy', function() {
deregister();
});

// 5. Digest already in progress errors
// Use $timeout instead of $apply when unsure
$http.get('/api/data').then(function(response) {
$timeout(function() {
$scope.data = response.data;
});
});