AngularJS – Controller and Service
In AngularJS, services are singleton objects that encapsulate reusable business logic and data retrieval, separate from the controller. Controllers should be thin — they coordinate the view and delegate work to services. This tutorial shows how to create a custom service, inject it into a controller, and display the results in a view.
Why Use a Service?
- A service is instantiated once and shared across all controllers that inject it
- Moving data logic out of controllers makes them easier to test and reuse
- Services are the right place to put
$httpcalls, data transformations, and business rules
Built-in AngularJS Services
| Service | Purpose |
|---|---|
$http |
Make HTTP requests (GET, POST, PUT, DELETE) |
$scope |
Two-way data binding between controller and view |
$rootScope |
Application-wide scope shared across controllers |
$location |
Read and change the browser URL |
$filter |
Apply filters programmatically (date, currency, etc.) |
$timeout |
Angular-aware wrapper for setTimeout |
Example: Custom ProductService + Controller
<!DOCTYPE html>
<html ng-app="productApp">
<head>
<meta charset="UTF-8">
<title>AngularJS – Controller and Service</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.3/angular.min.js"></script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.card { border: 1px solid #ddd; padding: 12px; margin: 8px 0;
border-radius: 4px; display: flex; justify-content: space-between; }
.badge { background: #0F83A0; color: #fff; padding: 2px 8px; border-radius: 10px; }
button { margin-top: 4px; padding: 4px 10px; cursor: pointer; }
</style>
</head>
<body>
<div ng-controller="ProductController">
<h2>Products (via Service)</h2>
<p>Total: <span class="badge">{{ productService.getCount() }}</span></p>
<div class="card" ng-repeat="p in products">
<div>
<strong>{{ p.name }}</strong><br>
₹{{ p.price | number }} — {{ p.category }}
</div>
<button ng-click="removeProduct(p)">Remove</button>
</div>
<h3>Add Product</h3>
<input ng-model="newProduct.name" placeholder="Name" >
<input ng-model="newProduct.price" placeholder="Price" type="number">
<input ng-model="newProduct.category" placeholder="Category" >
<button ng-click="addProduct()">Add</button>
</div>
<script>
var app = angular.module('productApp', []);
// -------------------------------------------------------
// Custom service — holds data and business methods
// -------------------------------------------------------
app.service('ProductService', function() {
var products = [
{ id: 1, name: 'Laptop', price: 75000, category: 'Electronics' },
{ id: 2, name: 'Smartphone', price: 25000, category: 'Electronics' },
{ id: 3, name: 'Keyboard', price: 2500, category: 'Accessories' },
{ id: 4, name: 'Mouse', price: 1500, category: 'Accessories' }
];
var nextId = 5;
this.getAll = function() {
return products;
};
this.getCount = function() {
return products.length;
};
this.add = function(product) {
product.id = nextId++;
products.push(product);
};
this.remove = function(product) {
var idx = products.indexOf(product);
if (idx !== -1) products.splice(idx, 1);
};
});
// -------------------------------------------------------
// Controller — injects ProductService, exposes to view
// -------------------------------------------------------
app.controller('ProductController', function($scope, ProductService) {
$scope.productService = ProductService;
$scope.products = ProductService.getAll();
$scope.newProduct = {};
$scope.addProduct = function() {
if (!$scope.newProduct.name) return;
ProductService.add(angular.copy($scope.newProduct));
$scope.newProduct = {}; // reset form
};
$scope.removeProduct = function(product) {
ProductService.remove(product);
};
});
</script>
</body>
</html>
How It Works
app.service('ProductService', function() {...})— registers a singleton.this.getAll,this.add,this.removebecome public methods.app.controller('ProductController', function($scope, ProductService) {...})— AngularJS injects the service by name. The controller gets the same singleton instance every time.$scope.products = ProductService.getAll()— the controller holds a reference to the same array the service manages. When the service mutates it (push/splice), the view updates automatically.ng-click="addProduct()"— calls the controller method, which delegates to the service.
service() vs factory() vs provider()
| Method | Returns | Use When |
|---|---|---|
app.service() |
The function instance (this) |
OOP-style class with methods on this |
app.factory() |
Whatever the function returns | Object literals, conditional logic before returning |
app.provider() |
$get method's return value |
Configurable services (config block needed) |
Loading Data from a REST API with $http
Replace the hardcoded array with a real API call by injecting $http into the service:
app.service('ProductService', function($http) {
var products = [];
this.loadAll = function() {
return $http.get('/api/products').then(function(response) {
products = response.data;
return products;
});
};
this.getAll = function() { return products; };
});
// In controller:
app.controller('ProductController', function($scope, ProductService) {
ProductService.loadAll().then(function(data) {
$scope.products = data;
});
});
Summary
AngularJS services are the right place for data management and business logic — they are singletons, injectable, and independent of any view. Controllers should be thin: inject a service, bind its data to $scope, and wire up user actions. This separation makes it easy to swap the data source (hardcoded JSON → $http → real REST API) without touching the view or rewriting controllers.
Comments