Sneaking Angular

into an Existing App

Alicia Liu

@aliciatweet

Sr Software Engineer, Lift


http://alicialiu.net/talks

  1. Decide You Want to Migrate Existing App to Angular
  2. ???
  3. Profit

Start Small


<html ng-app="myApp">
...
</html>
      

<div ng-app="myApp">
...
</div>
      

Example

Add question widget to meetup website


<div>
  <div>
    <form>
      <textarea></textarea>
      <input type="submit">
    </form>
  </div>
  <div>
    <ul>
      <li>
        <!-- list of questions -->
      </li>
    </ul>
  </div>
</div>
      

<div ng-app="meanDemoApp">
  <div ng-controller="QuestionformCtrl">
    <form ng-submit="submitQuestion();">
      <textarea ng-model="question.text"></textarea>
      <input type="submit">
    </form>
  </div>
  <div ng-controller="QuestionlistCtrl">
    <ul>
      <li ng-repeat="question in questions">
        {{question.text}}
      </li>
    </ul>
  </div>
</div>
      

Getting MEAN


angular.module('meanDemoApp')
  .factory('Question', function ($resource) {
    var rootUrl = 'http://localhost:4567';
    var apiRootUrl = rootUrl + '/api';

    return $resource(
      apiRootUrl + '/questions/:id',
      { id: '@id' },
      { vote: {
        method: 'POST',
        url: apiRootUrl + '/questions/:id/vote' }
      }
    );
  });
      

Controllers


angular.module('meanDemoApp')
  .controller('QuestionformCtrl', function ($scope, Question) {

    $scope.question = {};

    $scope.submitQuestion = function() {
      Question.save($scope.question,
        function() {
          $scope.question = {};
        });
    };
  })
  .controller('QuestionlistCtrl', function ($scope, Question) {

    Question.query(null,
      function(questions) {
        $scope.questions = questions;
      });

    $scope.upvote = function(question) {
      Question.vote({id: question._id});
    };
  })
      

Filter Example

Super Simple Client-side Sorting


<button ng-click="predicate = '-created'">Newest</button>
<button ng-click="predicate = '-voteCount'">Most Popular</button>
<ul>
  <li ng-repeat="question in questions | orderBy:predicate">
    <span>{{question.voteCount}}</span>
    {{question.text}}
  </li>
</ul>
      

Directives


<question-list></question-list>
            

Basic Directive


angular.module('meanDemoApp')
  .directive('questionList', function() {
    return {
      restrict: "EA",
      templateUrl: '/views/question-list.tpl.html'
      scope: {},
      controller: 'QuestionlistCtrl',
    };
  });
      

Wrapping Existing Code



      

angular.module('meanDemoApp')
.directive('categorySelector', function() {
  return {
    restrict: "E",
    replace: true,
    scope: {
      question: '='
    },
    template: '',
    // continued in next slide
  };
});
      

Compile & Link


compile: function(tElem) {
  var categories = ['', 'mongo', 'express', 'angular', 'node'];
  categories.forEach(function(category) {
    tElem.append(angular.element(''));
  });

  return function(scope, iElem) {
    var selectFx = new SelectFx(iElem[0], {
      onChange: function(option) {
        scope.question.category = option;
      }
    });

    scope.$watch('question.category', function(newVal) {
       selectFx.select(newVal);
    });
  }
}
      

bit.ly/mean-code

Expanding Angular

Angular in a Subdirectory


<html ng-app="myApp">
<head>
  <base href="/app/">
</head>
<body>
   <a href="/app/page">Handled by Angular</a>
   <a href="/page">Not handled by Angular</a>
</body>
</html>
          

All Angular!

What about non-Angular paths?



<a href="/url">Handled by Angular</a>
<a href="/url" target="_self">Not handled by Angular</a>
          

Thanks!

Q & A to Follow

@aliciatweet