## AngularJS
![angular](lib/img/angularjs.jpg)
## First Steps
```coffeescript
app = angular.module('pollApp', ['ui.router','pollApp.controllers',
'pollApp.services', 'pollApp.directives'])
app.config(($interpolateProvider, $stateProvider, $urlRouterProvider) ->
$interpolateProvider.startSymbol('[[')
$interpolateProvider.endSymbol(']]')
```
## CSRF Fix
```coffeescript
app.config(($httpProvider) ->
getCookie = (name) ->
for cookie in document.cookie.split ';' when cookie and
name is (cookie.trim().split '=')[0]
return decodeURIComponent cookie.trim()[(1 + name.length)...]
null
$httpProvider.defaults.headers.common['X-CSRFToken'] = getCookie("csrftoken")
)
```
Initial Template
<body ng-app="pollApp">
<div class="container">
<div class="page-header">
<h1>Polls</h1>
</div>
<div ui-view></div>
</div>
<script src="/static/js/angular.js"> </script>
<script src="/static/js/angular-ui-router.min.js"></script>
<script src="/static/js/app.js"></script>
<script src="/static/js/controllers.js"></script>
<script src="/static/js/directives.js"></script>
<script src="/static/js/services.js"></script>
</body>
## Services
```coffeescript
services = angular.module('pollApp.services', [])
services.factory('Questions', ($log, $http, Question) ->
questions = {all : []}
fromServer: (data) ->
questions['all'].length = 0
for question in data
questions['all'].push(new Question(question))
fetch: ->
$http({method: 'GET', url: '/polls/questions'})
.success (data) =>
@fromServer(data)
$log.info("Succesfully fetched questions.")
.error (data) =>
$log.info("Failed to fetch questions.")
data : ->
return questions
)
```
## Question Class
```coffeescript
services.factory('Question', (Choice, $http, $log) ->
class Question
constructor : (data) ->
if data != null
@init(data)
init : (data) ->
@question_text = data.question_text
@id = data.id
@choices = []
@totalVotes = 0
for choice in data.choices
c = new Choice(choice)
@totalVotes += c.votes
@choices.push(new Choice(choice))
```
## Question Class
```coffeescript
get : (questionId) ->
$http({method: 'GET',
url: '/polls/questions/' + questionId + '/'})
.success (data) =>
@init(data)
$log.info("Succesfully fetched question")
.error (data) =>
$log.info("Failed to fetch question.")
return Question
)
```
## Choice Class
```coffeescript
services.factory('Choice', ($http, $log)->
class Choice
constructor: (data) ->
@choice_text = data.choice_text
@id = data.id
@votes = data.votes
update : ->
data = {'votes' : @votes, 'choice_text' : @choice_text}
$http({method: 'PUT',
url: '/polls/choices/' + @id + '/', data:data})
.success (data) =>
$log.info("Succesfully voted")
.error (data) =>
$log.info("Failed to vote.")
return Choice
)
```
## States
```coffeescript
$urlRouterProvider.otherwise('/');
$stateProvider
.state('questionList'
url: '/'
templateUrl: 'questionList'
controller: 'questionListController'
resolve:
questions : (Questions)->
Questions.fetch()
return Questions.data()
)
```
## States
```coffeescript
.state('questionDetail'
url: '/{questionId:[0-9]+}/'
templateUrl: 'questionDetail'
controller: 'questionDetailController'
resolve:
question : ($stateParams, $log, Question)->
question = new Question(null)
question.get($stateParams.questionId)
return question
)
```
## Controllers
```coffeescript
controllers = angular.module('pollApp.controllers', [])
controllers.controller('questionListController',
($scope, $state, $log, questions) ->
$scope.questions = questions.all
)
```
## Controllers
```coffeescript
controllers.controller('questionDetailController',
($scope, $state, $log, question) ->
$scope.question = question
$scope.voted = false
$scope.voteChoice = 0
$scope.vote = ->
for choice in $scope.question.choices
if choice.id == parseInt($scope.voteChoice)
choice.votes+=1
$scope.question.totalVotes+=1
choice.update()
break
$scope.voted = true
)
```
Templates
<script type="text/ng-template" id="questionList">
</script>
questionList Template
<ul>
<li ng-repeat="question in questions">
<a ui-sref="questionDetail({questionId:question.id})">
[[question.question_text]]
</a>
</li>
</ul>
questionDetail Template
<form class="form" ng-submit="vote()" ng-show="!voted">
<h2>[[question.question_text]]</h2>
<div class="radio" ng-repeat="choice in question.choices">
<label>
<input type="radio" ng-model="$parent.voteChoice"
name="voteChoice" value="[[choice.id]]">
[[choice.choice_text]]
</label>
</div>
<input type="submit" class="btn btn-info" />
</form>
questionDetail Template
<div ng-show="voted">
<h2>[[question.question_text]]</h2>
<div ng-repeat="choice in question.choices" style="width: 50%">
[[choice.choice_text]] : [[choice.votes ]]
<div class="progress progress-striped">
<div class="progress-bar progress-bar-info"
choice-percentage votes="choice.votes"
total="question.totalVotes" >
</div>
</div>
</div>
</div>
<a ui-sref="questionList"> << Back to list</a>
## Directives
```coffeescript
directives = angular.module('pollApp.directives', [])
directives.directive('choicePercentage', ->
restrict: 'A'
scope:
votes: '='
total: '='
link: (scope, element, attrs) ->
update = ->
if scope.total > 0
percentage = scope.votes / scope.total * 100
else
percentage = 0
element.css('width', percentage + '%')
scope.$watch 'total', (value) -> update()
scope.$watch 'votes', (value) -> update()
)
```