Blog

- Showing all posts in category: AngularJS

Creating a SPA  containting multiple pages/views would require the use of a router like ui-router. The only thing about ui-router is that the documentation is kinda messed up. I will explain how to pass parameters between multiple views.

When you switch between states in your Angular app, you will sometimes need to pass some parameters to the state you want to enter. Mostly you will pass some kind of a number that stands for the primary key of the entity you are trying to show.

In the code below you see an state that requires a personId as a param. The url of the state contains a placeholder where the personId param is expected.

If you would go to the URL /person/1337/  or calling ui-sref="person.detail({personId:1337})" or even calling $state.go("person.detail", {personId: 1337}), then the personId can be acquired by calling $stateParams.personId. Keep in mind that you could get a string value.

$stateProvider
   .state("person.detail", {
		url: "/person/:personId/",
		templateUrl: "templates/personDetail.html",
		controller: "PersonDetailController"
	});

 

Let's come to the next part. Sometimes you want to pass some object as param. UI-router allows that, but you need to define the param first in your state.You can't just pass randomly params until you have defined them. These parameters are optional and have their initial value.

$stateProvider
   .state("person.detail", {
		url: "/person/:personId/",
		templateUrl: "templates/personDetail.html",
		controller: "PersonDetailController",
                params: {
                    dateOfRequest: new Date(), //inital default value
                    manager: null //Null  as initial value but yet is defined
                }
	});

In the code above I have defined the params dateOfRequest and manager. These parameters must have a initial value. If you really don't need a initial value, then you can set the parameter value on null.

This is the way how we pass the params now:

$state.go("person.detail", {personId: 1337, dateOfRequest: getDate(), manager: getManager()});

Same story if you use ui-sref:

ui-sref="person.detail({personId:1337, dateOfRequest: getDate(), manager: getManager()})"

In the controller of the state you want to switch you can fetch the parameter like this:

.controller("PersonDetailController", function($scope, $stateParams) {
    $stateParams.personId;
    $stateParams.dateOfRequest;
    $stateParams.manager;
});

 

The last way to pass value between controllers, states, views is using the Angular service. A service is only instantiated once and it's reference is shared.

Angular services are:

  • Lazily instantiated – Angular only instantiates a service when an application component depends on it.
  • Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.

 

 

# Getting started with AngularJs
Published on 29-07-2015

Javascript is getting more popular now while it could be a nightmare to code it.  There is an uncontrollable growth in javascript frameworks to make your development progress easier so you can create code in less time. In this article I will explain how to start with AngularJs.

AngularJs

AngularJs is an open source javascript framework created by Google and is maintained by Google and the open community of individual developers. Check the wiki for more info about AngularJs.

The framework is user friendly to develop with and runs client side in the web browser. It also uses the MVC pattern so the presentation layer is separated with the data and logic.

 

Lets begin!

You have to run a webserver like Apache on your PC. There are easy all-in-one packages (for Windows) to setup apache like XAMPP or WAMP (I don't have to tell you that you must not use these webservers for production right? :)). Or you could use a nodejs webserver.

Create the index.html:

<!DOCTYPE html>
<html>
	<head>
		<title>Getting started with angular</title>
		<script src="/bower_components/angularjs/angular.min.js"></script>
		<script src="/js/app.js"></script>
		<script src="/js/controller.js"></script>
	</head>
	<body ng-app="angularApp" ng-controller="MainController">
	
	</body>
</html>

 

Create the js/app.js:

var angularApp = angular.module("angularApp", [
	"angularControllers"
]);

 

Create the js/controller.js:

var angularControllers = angular.module("angularControllers", []);

angularControllers.controller("MainController", function() {
	console.log("Main");
})

Well, this was quite easy huh? If you run this code, you have a single page with a controller. Let's add some pages and navigations.

There are two options for navigations: angular $route, and a commonly used third party library UI-router. If you wish to have a simple page navigation, then the build in angular $route is enough. If you want more advanced navigation with nested views and states, then use UI-router. In this example we will be using UI-router.

You will have to download the UI-router library and include it in index.html. I am using bower package management for my web libraries, even for angular.
Bower has also a dependency management system ex: if your fubar["1.2" ] library requires at least jQuery["1.10"], then fubar 1.2 will be installed with jQuery 1.10. Pretty cool huh? Take another coffee with the time you've saved!

Just take a look at it if you have time. For this example you could skip the bower part and just download UI-router library.

Include the angular-ui-router.min.js in index.html and add the <ui-view> directive inside the <body> tag.
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Getting started with angular</title>
        <script src="/bower_components/angularjs/angular.min.js"></script>
        <script src="/bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
        <script src="/js/app.js"></script>
        <script src="/js/controller.js"></script>
    </head>
    <body ng-app="angularApp" ng-controller="MainController">
        <ui-view>
        </ui-view>
    </body>
</html>

The <ui-view> directive decides that the content from the page states will be rendered here.

Inside your app.js we need to load the module "ui-router" and add the page states configuration.
js/app.js:

var angularApp = angular.module("angularApp", [
	"angularControllers",
	"ui.router"
]);

angularApp.config(function($stateProvider, $urlRouterProvider) {
	$stateProvider
	.state("homepageState", {
		url: "/home/",
		templateUrl: "templates/homePage.html",
		controller: "HomePageController"
	})
	.state("myOtherStateName", {
		url: "/secondPage/",
		templateUrl: "templates/secondPage.html",
		controller: "SecondPageController"
	});
	$urlRouterProvider.otherwise("/home/");
});

This still sounds easy right? Well, it is! We have done the following things:

  • Registered "ui-router" module to "angularApp".
  • Added a config block where the "ui-router" module is configured.
  • Added two states named "homepageState" and "myOtherStateName"
  • Added a fallback state to url: "/home/". You could define a 404 page like "templates/pagenotfound.html".

Every state has his state name(we will come back later to this), an URL to map the browser URL, and a controller. There are more advanced options. Check the ui-router wiki. You could even delay the page navigation. state loading until some requested remote data is loaded, but that's out of the scope for this article.

In this example we will be using a basic page with an controller behind it.

js/controllers.js

var angularControllers = angular.module("angularControllers", []);

angularControllers.controller("MainController", function($scope) {
	$scope.callTheMain = function() {
		console.log("What's up?!");
	}
});
angularControllers.controller("HomePageController", function($scope) {
	$scope.callTheMain();
	$scope.title = "This is the homepage";
});
angularControllers.controller("SecondPageController", function($scope) {
	$scope.title = "The secondpage";
});

Angular controllers supports inheritance. In index.html there is the <body ng-controller="MainController">. Every controller inside <body> inherits "MainController". In this case if the current state is "homepageState", we have a controller named "HomePageController" who automatically inherits"MainController". 

So basically like this:

<div ng-controller="ParentController">
        <div ng-controller="SomeChildController"></div>
</div>

"SomeChildController" can call "ParentController" but "ParentController" cannot access "SomeChildController"

 

Lets create the state templates

templates/homePage.html

<div>{{title}}</div>
<br />
<div>Go to the <a ui-sref="myOtherStateName">next</a> page.</div>

templates/secondPage.html

<div>{{title}}</div>
<br />
<div>Go back to home <a href="#/home/">page</a>.</div>
<br />
<label>Modify the title!</label>
<input type="text" ng-model="title"/>

You should have noticed the two difference in the templates. In homePage.html we use the ui-sref="myOtherStateName" to create a link to secondPage.html. This is the proper way to create links to different states. So if you want to change the URL's to these states, you only have to change the url property in app.js. 

The ui-sref also works on other html tags like <div ui-sref="myOtherStateName">link</div>. 

In secondPage.html we have used the plain <a> which is self explanatory.

 

Template compilation

Both templates contain {{title}} expression. Angular compiles the template and replaces the {{title}} expression with the value of $scope.title from the controller. This also could be a function call :{{getTitle()}}.

AngularJS provides two-way databinding support. If you write text in the input field in secondPage.html, the value in $scope.title changes synchronously.

 

So far so good, we have an AngularJS application with page navigation. Lets see what we can do with services and factories

Create js/services.js

var angularServices = angular.module("angularServices", []);

angularServices.service("MyService", function() {
	this.helloWorldMe = function(myName) {
		return "Hello world " + myName;
	}
});

angularServices.factory("PetFactory", function() {
	return {
		createPet: function(myPetName) {
			return "Oh hello " + myPetName + "!";
		}
	}
});

The main difference between a service and a factory is explained in this thread on StackOverflow.

Summarized:

  • A service is a singleton. This means that there is only one instance of this service.
  • A factory returns a new object.

 

Add the services module to your app like you did before:

js/app.js

​var angularApp = angular.module("angularApp", [
	"angularControllers",
	"angularServices",
	"ui.router"
]);

angularApp.config(function($stateProvider, $urlRouterProvider) {
	$stateProvider
	.state("homepageState", {
		url: "/home/",
		controller: "HomeController",
		templateUrl: "templates/homePage.html",
		controller: "HomePageController"
	})
	.state("myOtherStateName", {
		url: "/secondPage/",
		templateUrl: "templates/secondPage.html",
		controller: "SecondPageController"
	});
	$urlRouterProvider.otherwise("/home/");
});

 

Add the service "MyService" and factory "PetFactory" into our controllers and execute the functions.

js/controllers.js

var angularControllers = angular.module("angularControllers", []);

angularControllers.controller("MainController", function($scope) {
	$scope.callTheMain = function() {
		console.log("What's up?!");
	}
});
angularControllers.controller("HomePageController", function($scope, MyService) {
	$scope.callTheMain();
	$scope.title = "This is the homepage";
	
	console.log(MyService.helloWorldMe("Gokhan"));
});
angularControllers.controller("SecondPageController", function($scope, PetFactory) {
	$scope.title = "The secondpage";
	
	console.log(PetFactory.createPet("Bob"));
});

Now you can reuse your code by using services and factories.
I will post more articles about filters and directives.

 

Download the complete project with all files here