Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Angular JS blog tutorial

3,780 views

Published on

Tutorial to create a blog using AngularJS.
The slides were originally used for a study
meetup at our office.

Published in: Technology

Angular JS blog tutorial

  1. 1. ANGULARJS INTRODUCTIONby @DanielPerez ClaudeTech
  2. 2. LEAVES STATIC WEBSITE BUILD TOOL Dependsonly onNodeJS. Uses: Yeoman Grunt Bower Jade(or EJS) Stylus(or lessor plainCSS) Coffee(or plainJS) Installwith: $npminstall-gleaves $leavessetup Checkout for moreinfo.thedocs
  3. 3. PROJECT CREATION $leavesnewangular-blog $cdangular-blog $leavesinstalljqueryangularangular-resourcebootstrapangular-ui-routermarkdown Renameassets/js/app.coffeetoassets/js/app.js, eraseassets/css/main.stylcontent andedit views/layout.jade. //views/layout.jade html head .... link(rel="stylesheet"href="components/bootstrap/dist/css/bootstrap.min.css") link(rel="stylesheet"href="components/bootstrap/dist/css/bootstrap-theme.min.css") script(src="components/jquery/dist/jquery.min.js") script(src="components/angular/angular.min.js") script(src="components/angular-resource/angular-resource.min.js") script(src="components/angular-ui-router/release/angular-ui-router.min.js") script(src="components/bootstrap/dist/js/bootstrap.min.js") script(src="js/app.js") body blockcontent
  4. 4. START HACKING Whenyouaredonewithbasic setup,run $leaves andstart hacking. FOR SCEPTICAL PEOPLE If youdonot want touseleaves,check about basic Angular setup.my blog post
  5. 5. TRY ANGULARJS Initializeapplication //views/layout.jade html head ... body(ng-app="") blockcontent Try two-way databinding: Output variablevaluewith: {{variable}}. Changevariablevaluewith: ng-model="variable" //views/index.jade extends./layout.jade blockcontent input(ng-model="variable") span{{variable}}
  6. 6. TRY ANGULARJS Initializevariable: //views/index.jade extends./layout.jade blockcontent div(ng-init="variable='plaintext'") span{{variable}} Youcanuseany element,not just divandspan.
  7. 7. TRY ANGULARJS Usecontroller toinitializevariable. //views/index.jade div(ng-controller="TestCtrl") span{{variable}} Definecontroller inJS file. $scopeisinjectedby Angular oninstanciation. //assets/js/app.js functionTestCtrl($scope){ $scope.variable="myvariabletext"; } Angular uses toinstanciatecontrollers,services,etc.DI
  8. 8. TRY ANGULARJS React toevents: //views/index.jade div(ng-controller="TestCtrl") span{{variable}} button(ng-click="action()") //assets/js/app.js functionTestCtrl($scope){ $scope.variable="myvariabletext"; $scope.action=function(){ $scope.variable="Ijustclicked!"; }; }
  9. 9. CREATE BLOG Createblog withfollowing functionalities: List posts List postsby category Showpost Createnewpost WewillusepreparedAPI toworkwith. Authentication/authorizationwillbefor next time. Sampleisavailableat .angular-blog-sample.herokuapp.com Fullsourcecodeisavailableat . github.com/claudetech-meetups/angular-blog- sample
  10. 10. AVAILABLE API TheavailableAPI callsare GET /posts GET /posts/:id POST /posts GET /categories POST /categories API isavailableat: http://angular-tutorial-api.herokuapp.com/
  11. 11. CREATE BASIC LAYOUT Addheader toviews/layout.jade html head .... body(ng-app="") .container nav.navbar.navbar-default .container-fluid .navbar-header a.navbar-brand(href="#")Blog .row .col-xs-8 blockcontent .col-xs-4 .block.categories h3Categories ul.list-unstyled li:a.small(href="#")Plentyofcategories .block.admin h3Admin ul.list-unstyled li:a.small(href="#")Addpost
  12. 12. CREATE BASIC LAYOUT Createempty views/posts/index.jadeandedit views/index.jade. //views/index.jade extends./layout.jade blockcontent include./posts/index
  13. 13. BUILD POST LIST Createcontroller inJS file: functionPostIndexCtrl($scope){ $scope.post={ id:1, title:"Posttitle", content:"Postcontent", createdAt:newDate() }; } Wrappost list inacontroller andusedummy data .posts(ng-controller="PostIndexCtrl") .post.row .row .col-xs-12 h2{{post.title}} small.date{{post.createdAt}} .row.content .col-xs-12{{post.content}} .row .col-xs-12 a.small(href="#")Seemore andcreatethecontroller.
  14. 14. SOME ISSUES {{variable}}appearsonpageload Dateformat isstrange Nolinebreakincontent Content may bevery long
  15. 15. SOME SOLUTIONS Useng-bindinsteadof {{}} Usedatefilter Wewillseehowtorender markdownincontent later on UselimitTofilter .posts(ng-controller="PostIndexCtrl") .post.row .row .col-xs-12 h2(ng-bind="post.title") small.date(ng-bind="post.createAt|date:'y/M/d'") .row.content .col-xs-12(ng-bind="post.content|limitTo:100") .row .col-xs-12 a.small(href="#")Seemore
  16. 16. MAKE IT A LIST Adddummy datainthecontroller. functionPostIndexCtrl($scope){ $scope.posts=[{ id:1, title:"Posttitle", content:"Postcontent", createdAt:newDate() },{ id:2, title:"Posttitle2", content:"Postcontent2", createdAt:newDate() }]; } Useng-repeat .posts(ng-controller="PostIndexCtrl") .post.row(ng-repeat="postinposts") ...
  17. 17. SHOW SINGLE POST Createviews/posts_show.jade,wewillextendlayout.jadefor now. extends./layout.jade blockcontent .post.row(ng-controller="PostShowCtrl") .row .col-xs-12 h2{{post.title}} small.date{{post.createdAt|date:'y/M/d'}} .row.content .col-xs-12{{post.content}} createPostShowCtrlfunction. //assets/js/app.js .... functionPostShowCtrl($scope){ $scope.post={ id:1, title:"Posttitle", content:"Postcontent", createdAt:newDate() }; } Youcantry toaccessyour page: localhost:9000/posts_show.html
  18. 18. SOME ISSUES Better modularizecontrollers Wedon't want another page Wewant content inmarkdown
  19. 19. MODULARIZATION Let'sstart by splitting files. //assets/js/controllers/posts/index.js functionPostIndexCtrl($scope){ ..... } //assets/js/controllers/posts/show.js functionPostShowCtrl($scope){ ..... } //views/layout.jade html head .... script(src="js/app.js") script(src="js/controllers/posts/index.js") script(src="js/controllers/posts/show.js") body(ng-app="") ...
  20. 20. ANGULAR MODULES Angular hasnativemodules.DeclareBlogAppmodulewithnodepencies. //assets/js/app.js angular.module('BlogApp',[]); Declarecontrollersaspart of themodule. //assets/js/controllers/posts/index.js angular.module('BlogApp').controller('PostIndexCtrl',[ '$scope',function($scope){ ... } ]); Samegoesfor PostShowCtrl.
  21. 21. ROUTING Routeinorder tobeabletohave /#/->allposts /#/posts/:id->post withid=:id /#/posts/new->newpost First,add depency tothemodule.ui.router //assets/js/app.js angular.module('BlogApp',[ 'ui.router' ]);
  22. 22. SETUP VIEW First,addtheviewwheretodisplay thecontent of theroute. //views/index.jade extends./layout.jade blockcontent div(ui-view)
  23. 23. SETUP ROUTER Configuretoredirect to/whennoroutefound,andconfiguretheroutes. //assets/js/app.js ... angular.module('BlogApp').config([ '$stateProvider','$urlRouterProvider',function($stateProvider,$urlRouterProvider){ $urlRouterProvider.otherwise('/'); $stateProvider .state('index',{ url:'/', templateUrl:'posts/index.html' }) .state('show',{ url:'/posts/:id', templateUrl:'posts/show.html' }); } ]); Then,removetheextendsandblockcontentfrom views/posts_show.jade: wedon't needthewholelayout.For consistency, moveviews/post_show.jadetoviews/posts/show.jade. Youcannowaccessyour route: localhost:9000/#/posts/1
  24. 24. SETUP ROUTER Controllersshouldbedefinedinroutes. //assets/js/app.js .state('index',{ url:'/', templateUrl:'posts/index.html', controller:'PostIndexCtrl' }) .state('show',{ url:'/posts/:id', templateUrl:'posts/show.html', controller:'PostShowCtrl' }); andremovedfromviews/posts/index.jadeand views/posts/show.jade. //views/posts/show.jade .post.row//nong-controlleranymore ...
  25. 25. ADD LINKS usesui-sreftomakelinkinsteadof normalhrefor ng-href attributes. ui-router //views/posts/index.jade ... a.small(ui-sref="show({id:post.id})")Seemore
  26. 26. USE API AddngResourcemoduleasadependency. //assets/js/app.js angular.module('BlogApp',[ 'ui.router', 'ngResource' ]); ... Try it //assets/js/controllers/posts/index.js angular.module('BlogApp').controller('PostIndexCtrl',[ '$scope','$resource',function($scope,$resource){ //noneedfordummydataanymore varPost=$resource('http://angular-tutorial-api.herokuapp.com/posts/:id'); Post.query(function(posts){ console.log(posts[0]); $scope.posts=posts; }); } ]);
  27. 27. RESOURCE FACTORY Wewant tobeabletousePostresourceanywhere. Let'smakeit afactory. //assets/js/resources/post.js angular.module('BlogApp').factory('Post',[ '$resource',function($resource){ return$resource('http://angular-tutorial-api.herokuapp.com/posts/:id'); } ]); andincludeit inviews/layout.jade html head ... script(src="js/resources/post.js")
  28. 28. USE RESOURCE FACTORY //assets/js/controllers/index.js angular.module('BlogApp').controller('PostIndexCtrl',[ '$scope','Post',function($scope,Post){ Post.query(function(posts){ $scope.posts=posts; }); } ]);
  29. 29. FETCH SINGLE POST Use$stateParamstoget id,andget post fromserver. //assets/js/controllers/posts/show.js angular.module('BlogApp').controller('PostShowCtrl',[ '$scope','$stateParams','Post',function($scope,$stateParams,Post){ Post.get({id:$stateParams.id},function(post){ $scope.post=post; }); } ]);
  30. 30. CREATE CATEGORY FACTORY //assets/js/resources/category.js angular.module('BlogApp').factory('Category',[ '$resource',function($resource){ return$resource('http://angular-tutorial-api.herokuapp.com/categories/:id'); } ]); andaddit tolayout.jade
  31. 31. NEW POST CONTROLLER CreatenewJS file,andafreshpost tobind. //assets/js/controllers/posts/new.js angular.module('BlogApp').controller('PostNewCtrl',[ '$scope','Post',function($scope,Post){ $scope.post=newPost(); } ]); andincludeit inviews/layout.jade script(src="js/controllers/posts/new.js")
  32. 32. CREATE NEW POST TEMPLATE Bindthemodelcreatedinthecontroller. //views/posts/new.jade h2Createnewpost form .form-group label(for="title")Title input#title.form-control(type="text"placeholder="Title"ng-model="post.title") .form-group label(for="content")Content textarea#content.form-control(rows="10"ng-model="post.content") .form-group select.form-control(ng-model="post.category_id") input.btn.btn-default(type="submit"value="Create")
  33. 33. ADD A NEW ROUTE Careful,order matters! $stateProvider .state('index',{ ..... }) .state('new',{ url:'/posts/new', templateUrl:'posts/new.html', controller:'PostNewCtrl' }) .state('show',{ ..... }); Andset link //views/layout.jade ... .block.admin h3Admin ul.list-unstyled li:a.small(ui-sref="new")Addpost
  34. 34. RESOLVE CATEGORIES Better havecategoriesbeforeloading template.Usecustommadepromiseand resolveAPI result. //assets/js/app.js ... .state('new',{ url:'/posts/new', templateUrl:'posts/new.html', controller:'PostNewCtrl', resolve:{ categories:['$q','Category',function($q,Category){ vardeferred=$q.defer(); Category.query(function(categories){ deferred.resolve(categories); }); returndeferred.promise; }] } }) .state('show',{ ....
  35. 35. RESOLVE CATEGORIES Usethecategoriesresolvedinthecontroller. //assets/js/controllers/posts/new.js angular.module('BlogApp').controller('PostNewCtrl',[ '$scope','Post','categories',function($scope,Post,categories){ $scope.post=newPost(); $scope.categories=categories; } ]);
  36. 36. USE NG-OPTIONS Dynamically showcategoriesinselectusing ng-options. form ... select.form-control( ng-model="post.category_id" ng-options="c.idasc.nameforcincategories" )
  37. 37. CREATE POST React tosubmit event //views/posts/new.jade form(ng-submit="createPost()") Addhandler for submit event. //js/controllers/posts/new.js angular.module('BlogApp').controller('PostNewCtrl',[ '$scope','Post','$state','categories',function($scope,Post,$state,categories){ ... $scope.createPost=function(){ $scope.post.$save(function(post){ $state.go('index',{id:post.id}); }); }; ...
  38. 38. FORMAT MARKDOWN Wearegoing tocreateafilter toformat markdown. //assets/js/filters/markdown.js angular.module('BlogApp').filter('markdown',[ '$sce',function($sce){ returnfunction(input){ if(!input){ return''; } return$sce.trustAsHtml(markdown.toHTML(input)); }; } ]); inputisthevaluetoconvert tomarkdown.Wereturnempty string if undefined. ThemarkdownisformattedinHTML,weneedtotrust theinput totellAngular it issafe.
  39. 39. DISPLAY FORMATTED MARKDOWN Weuseng-bind-htmltodisplay HTML andnot escapedvalues. //views/posts/show.jade .post.row .... .row.content .col-xs-12(ng-bind-html="post.content|markdown")
  40. 40. CREATE CATEGORIES CONTROLLER Asfor posts,query toget allthecategories. //assets/js/controllers/categories/index.js angular.module('BlogApp').controller('CategoryIndexCtrl',[ '$scope','Category',function($scope,Category){ Category.query(function(categories){ $scope.categories=categories; }); } ]);
  41. 41. SHOW CATEGORIES Createpartial //views/categories/index.jade .block.categories(ng-controller="CategoryIndexCtrl") h3Categories ul.list-unstyled li(ng-repeat="categoryincategories") a.small(ui-sref="index({category:category.id})"ng-bind="category.name") Changelayout tousepartial. //views/layout.jade .... .col-xs-4 include./categories/index .block.admin h3Admin ul.list-unstyled li:a.small(ui-sref="new")Addpost
  42. 42. UPDATE ROUTES Updateindex routestotakecategoryquery parameter. //assets/js/app.js ... $stateProvider .state('index',{ url:'/?category', templateUrl:'posts/index.html', controller:'PostIndexCtrl' }) Thisisneededtopasscategorytoui-srefandtoreadit from $stateParams.
  43. 43. FILTER QUERY Checkif thereisacategory definedandadapt query. //assets/js/controllers/posts/index.js angular.module('BlogApp').controller('PostIndexCtrl',[ '$scope','$stateParams','Post',function($scope,$stateParams,Post){ varsearch=$stateParams.category?{category_id:$stateParams.category}:{}; Post.query(search,function(posts){ $scope.posts=posts; }); } ]);

×