## Djangular ![Alt text](lib/img/tm.png)
## About Me Matt Camilli @mlcamilli matt@trackmaven.com http://mattcamilli.com
## The Product
![feed](lib/img/feed.png)
![alerts](lib/img/alerts.png)
![brand](lib/img/brand.png)
![brand2](lib/img/brand2.png)
![visualizer](lib/img/visualizer.png)
## The Problem ![corgisleep](lib/img/corgisleep.jpg) We wanted a fast and fluid UI/UX while working with a lot of variable data.
## Django Templates ![sadcorig](lib/img/sadcorgi.jpg)
## The Solution We would serve all of our data from the backend in a Rest API and have the front end asynchronously interact with it.
![django](lib/img/django.png)
## Django Rest Framework ![drf](lib/img/drf.png)
![kickstarter](lib/img/kickstarter.png) https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3
## Models ```python from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __unicode__(self): return self.question_text class Choice(models.Model): question = models.ForeignKey(Question, related_name='choices') choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) def __unicode__(self): return self.choice_text ```
## Serializers ```python from rest_framework import serializers from .models import Question, Choice class ChoiceSerializer(serializers.ModelSerializer): class Meta: model = Choice fields = ('choice_text', 'id', 'votes') class QuestionSerializer(serializers.ModelSerializer): choices = ChoiceSerializer(many=True) class Meta: model = Question fields = ('question_text', 'choices', 'id') ```
## Views ```python from rest_framework import generics, permissions from .models import Question, Choice from .serializers import QuestionSerializer, ChoiceSerializer class QuestionList(generics.ListCreateAPIView): model = Question serializer_class = QuestionSerializer permission_classes = [permissions.AllowAny] class QuestionDetail(generics.RetrieveAPIView): model = Question serializer_class = QuestionSerializer lookup_url_kwarg = 'question_pk' permission_classes = [permissions.AllowAny] ```
## Views ```python class ChoiceUpdate(generics.UpdateAPIView): model = Choice serializer_class = ChoiceSerializer lookup_url_kwarg = 'choice_pk' permission_classes = [ permissions.AllowAny ] class ChoiceList(generics.ListCreateAPIView): model = Choice serializer_class = ChoiceSerializer permission_classes = [ permissions.AllowAny ] ```
## URLS ```python from django.conf.urls import patterns, url, include from .views import QuestionList, ChoiceList, QuestionDetail, ChoiceUpdate urlpatterns = patterns('polls.views', url(r'^questions$', QuestionList.as_view(), name='questions_list'), url(r'^questions/(?P[0-9]+)/$', QuestionDetail.as_view(), name="questions_detail"), url(r'^choices$', ChoiceList.as_view(), name='choices_list'), url(r'^choices/(?P[0-9]+)/$', ChoiceUpdate.as_view(), name='choices_update'), url(r'^$', 'index', name='questions_index'), ) ```
![questions](lib/img/questions.png)
## CoffeeScript ![coffee](lib/img/coffee.jpg)
![comparison](lib/img/comparison.png)
## 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() ) ```
## DEMO THAT SHOULD WORK ![scared](lib/img/scared.jpg)