请选择 进入手机版 | 继续访问电脑版

技术控

    今日:299| 主题:54008
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Create a Trello Clone using Angular, Node.js, Mongo, and Express

[复制链接]
不曾言说 发表于 2016-10-4 16:25:04
287 4

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

  Table of contents

  
       
  • I. Introduction   
  • II. Background
           
    • A. Node.js     
    • B. Express     
    • C. Mongo     
    • D. Angular     
    • E. They are all JavaScript   
       
  • III. Let’s build a Trello clone
           
    • Step 0: Getting started     
    • Step 1: Managing tickets on a board
              
      • A. Create the “board” page      
      • B. Common mistakes so far
                   
        • Problem 1: I did not define a default route         
        • Problem 2: I forgot to include a .js file        
                
      • C. Painting the tickets      
      • D. Adding color and layout      
            
    • Step 2: Adding list and ticket functionality     
    • Step 3:  Testing time
              
      • A. Lists are not aligned at the top      
      • B. Lists exceed the page content      
      • C.  Generating many lists will overflow to the next line      
            
    • Step 4: Adding some coolness—Drag & Drop
              
      • A. Let’s look at how drag-and-drop is implemented      
           
       
  • IV.  Let’s look at our final results   
  • V. Live coding a Trello Clone  
  I. Introduction

  Simple to-do lists are great for keeping track of tasks you need to accomplish. But if you’re working with a team where tasks have sub-tasks that have sub-sub-tasks and more, that’s where you especially need a project management software. Project management apps, even simple ones like Trello, can break your project down into achievable steps and give your team a more manageable workflow.
  II.Background

  This tutorial shows how to write a Trello-like ticketing system from scratch to help you build a similar project management tool on your own. At every step, we will consider the minimal viable product requirements and implement them.
  We will use Trello as an inspiration since it is very simple yet powerful. For the purpose of this tutorial, we will create a simple version of the app.
  The stack we will use is the MEAN stack ­ Mongo, Express, AngularJS, and Node.js. The MEAN stack has no particular advantage over other technologies so picking this technology is simply my personal taste. But here are some reasons why I prefer these technologies:
  A. Node.js

  
       
  • It has a great dependency mechanism. It is relative rather than global—both in file system and path. This means:
           
    • You can have multiple versions of the same code in one project, which makes dependencies much more stable.     
    • You can easily pack your code “to go”.     
    • It is very easy to publish your code to use—micro library. This, in turn, means there’s a lot of code out there you can use for Node.js. It also means you can easily separate your code to small libraries.     
    • Combines with nvm (Node Version Manager), which means you can easily have multiple node version on your computer.   
       
  • It has a great stack of utilities for the development environment.
           
    • nodemon and lite­server auto refresh your process once code changes. This, in turn, accelerates your development process—remember there’s no compilation!     
    • Bower organizes your front-end dependencies (and I still like it even though npm can replace it).     
    • npm scripts is a very powerful way to add functionality to your development environment. I find it very useful to have Nodejs in any project ­ never mind the language.   
       
  • It is light. I like the fact I can run Node.js on a micro machine in Amazon.
           
    • It is asynchronous by nature. This makes it a very suitable technology for the web as web servers.     
    • Combines with Electron we can easily publish a native client to our app.   
       
  B. Express

  Espress is a very straight forward library that helps organize your server’s code.
  C. Mongo

  Mongo plays very well with Node.js and its schema-less nature makes development very easy, especially when you start a project.
  D. Angular

  
       
  • It is a complete framework for the frontend. No need to integrate multiple libraries.   
  • I think it barely has any learning curve ­ I never understood those who said otherwise.   
  • It separates HTML from JavaScript, which I like.  
  E. They are all JavaScript!

  
       
  • JavaScript is awesome.
           
    • It is a scripting language and so you see results right after writing the code.     
    • Its runs on engines written by the biggest companies and used by everyone using a browser.   
       
  • One language for all environments.  
  II. Let’s build a Trello clone!

  Step 0: Getting started

   To get things started, let’s use a scaffold project that includes a basic Angular setup and a backend.
  Step 1: ­ Managing tickets on a board

  For the first step, let’s chose to assume
  
       
  • a single board with lists and tickets   
  • no users, no collaboration  
  A. Create the “board” page

  First, let’s set up a board view that allows users to add lists and tickets. For that, we will define a page in Angular:
  1. // file : app.js
  2. angular.module('demo', ['ngRoute']).config(function ($routeProvider) { console.log('configuring')

  3.   $routeProvider

  4.     .when('/board', {
  5.       controller: 'BoardPageCtrl', templateUrl: '/app/views/board_page.html'
  6.     });
  7.   })
复制代码
Then we will define the controller with some mock data we can display
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })
复制代码
As you can see, I chose a very naive data model with the following traits:
  
       
  • I have an array of lists.   
  • Each list has a name and its tickets.   
  • Each ticket has a title.  
  While this model might change in the future, it is too early for me to consider anything more complex.When I think about the first functionality I would like to add ­ which is CRUD (Create, Read, Update, Delete) for lists and tickets,
  When I think about the first functionality, I would like to add something that’s known as CRUD (Create, Read, Update, Delete) for lists and tickets. I am convinced this model is sufficient, so let’s move on.
  Time to add the view to display the lists and tickets.
  For starters, we’d want to see everything is wired correctly. So I will start with a simple page:
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page
复制代码
To verify everything is fine, simply run npmstart. Thanks to the awesome simple Node.js setup, the browser should open. But alas, the text does not appear. So let’s troubleshoot it.
  B. Common mistakes so far

  Problem 1: ­ I did not define a default route

   The board route specifies a /board page, but the browser opened on /index.html file. I can manually write /index.html#/board or simply add a default route. I prefer the latter and so we can write:
  1. // file : app.js

  2.     ...
  3.     .otherwise({redirectTo: '/board'})
复制代码
Problem 2: ­ I forgot to include a .js file

   You can see the blue background color, but still no tickets. When you open the console and see an Error with the message Argument'BoardPageCtrl'is not a function, got undefined
  Verify if the controller is spelled correctly on the route. It should be correct.
   When you add a log print console.log('initializing controller') at the top of the page, you should see that the code is not invoked.
  When modifying the angular module name to one that does not exist, an Error is not thrown. This leads to the conclusion that adding the JavaScript file in index.html has been forgotten. Add it.
   Now everything works! So let’s move on…
  C. Painting the tickets

  Now that we made sure everything is wired correctly, we can move on to painting the tickets. I start the HTML by adding a div with ID matching the page’s name. This is a habit of mine as some of the CSS will be specific to this page.
  1. <div id="board­-page">
  2.     This is board page
  3. </div>
复制代码
Now I would like to display a list and enable changing its name.
  1. <div ng­-repeat="list in lists" class="list">
  2.     <input class="list­-name" ng­model="list.name"/>
  3. </div>
复制代码
I chose a simple implementation of showing the name in an input. For now, it looks bad but provides the functionality we desire. We can fix the display issue when we reach the CSS part.
  Next, we would like to paint the tickets for each list.
  1. <div ng­-repeat="list in lists" class="list">
  2.     <input class="ticket­-title" ng­model="ticket.title"/>
  3. </div>
复制代码
  Last but not least, I want to add a button with the label Add Ticket .
  1. <button class="add­-ticket"> Add Ticket </button>
复制代码
The final HTML looks like this:
  1. <!-- file : /app/views/board_page.html ­­-->

  2. <div id="board­-page">
  3.     <div ng­-repeat="list in lists" class="list">
  4.         <input class="list­-name" ng­-model="list.name"/>
  5.         <div class="list­-content">
  6.             <div ng­-repeat="ticket in list.tickets" class="ticket">
  7.                 <input class="ticket­-title" ng­-model="ticket.title"/>
  8.             </div>
  9.         </div>
  10.         <button class="add­-ticket"> Add Ticket </button>
  11.     </div>
  12. </div>
复制代码
We have yet to finish the functionality as the Add Ticket button does nothing yet. But before we move on with the functionality, I would like things to look awesome.
  D. Adding color and layout

  So far, everything looks awful. So it’s time to add some style.
   To keep the project organized, let’s create a file named _board_page.scss (notice the naming convention I keep) and I start it with the page’s ID.
  1. #board­page{
  2. }
复制代码
Let’s start by adding the board’s background color:
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })0
复制代码
Colors have the tendency to be reused. So I prefer to keep it in a variable. I think it is more readable, too.
   Now, I want the background to not be all over the page. I could use width: 100% and height: 100% , but that has some other implications we want like to avoid. So instead, I prefer to use absolutepositioning . It will also resolve some scrolling issues down the road.
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })1
复制代码
Next, let’s make the lists horizontal—one next to the other.
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })2
复制代码
Now, let’s display the title properly and add background to the lists with some spacing:
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })3
复制代码
  Let’s also add padding on the #board­page with padding:20px;
   Note that I used margin­-left to have spacing between the lists, but when I wanted spacing from the page, I added padding on the page.
   I could have added margin­-top on the lists and margin­-left on the left­-child to achieve the same thing.
  The reason I chose to implement it this way is that if I ever added anything else on the page, I can rest assure it will be aligned with the lists properly. The alternative would force me to add the margins repeatedly to every element I will add in the future.
  Saying that, this is what the app should look like at this point
   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

  Now let’s style the button
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })4
复制代码
Let’s add some style to each ticket:
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })5
复制代码
I ignored the first child when I added the margin because I don’t like it when the distance between two elements in the page is a sum of two styles. In this case:
  
       
  • padding on the list name   
  • margin­-top on the ticket  
  I also want to avoid the possibility that the distance between the title and the first ticket, and the distance between the tickets are somehow connected. We want to be able to change one without the other.
  You might be wondering why am I being so meticulous with the style. The reason is that I find it much harder to detect style regressions than functionality regressions, mainly before the former is hard to test automatically. So paying attention to small details and acquiring good practices with CSS will save you a lot of time down the road.
   This is the final scss file
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })6
复制代码
  So far, all the style is under the #board­page and reusable components are not yet defined. This will be a refactoring we will do once we find ourselves copy­pasting… (Note: I like this approach because it keeps me very goal oriented. I am not thinking about infrastructure yet, but once I need it, a small refactoring will get me there.)
   If you are not seeing the style changes, make sure you remembered to add an @import 'board_page'; statement to main.scss
  Step 2: ­ Adding list and ticket functionality

   It’s time to enable adding tickets and lists. We already have a hook for adding a ticket on the Add Ticket button but we also need some action to add a list. For now, binding it to double­-click on the board sounds nice.
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })7
复制代码
And in the controller, we will implement these functions:
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })8
复制代码
Pretty simple, and it will do for now.
  Step 3­: Testing time

  So playing with the new shiny app, I discovered some style issues. Let’s review and see how to resolve them.
  A. Lists are not aligned at the top

   When I create a new list, it is not aligned to the top. This can be easily fixed by telling all the lists to be aligned to the top. Simply add vertical­-align:top; on .list
   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

  B. Lists exceed the page content

  When I click ‘Add Ticket’ repeatedly, I see the lists spills over the content area.
   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

  To quickly fix this, add the following css
  1. // file : BoardPageCtrl.js

  2. angular.module('demo').controller('BoardPageCtrl', function ($scope) { $scope.lists = [
  3.     {
  4.       name: 'list 1',
  5.       tickets: [
  6.         {title: 'task 1'},
  7.         {title: 'task 2'}
  8.       ]
  9.     },
  10.     {
  11.       name: 'list 2',
  12.       tickets: [
  13.         {title: 'task 3'},
  14.         {title: 'task 4'}
  15.       ]
  16.     }
  17.   ]
  18. })9
复制代码
  Pay attention to the ugly max­-height:80% . It is a very ugly solution. The distance between the bottom of the list to the end of the page will change according to screen height. Which means if the screen resolution is high, the list will end relatively high on the screen. If the screen is small, the bug will still reproduce. So why did I implement it this way?
  Simply because the correct solution for this problem is cumbersome and requires very good css skills to get it right.
  C. Generating many lists will overflow to the next line

  When I try to add a lot of lists, I see this horrifying image
   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

   This is easily solved by adding white­-space: nowrap on the board.
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page0
复制代码
Step 4: ­ Adding some coolness—Drag & Drop

  So far, we have some pretty fair results. But Trello is very famous for its drag & drop ease and it would be a shame not to have it.
   Luckily, there’s a pretty nifty Angular library called angular­-drag­-and­-drop­-lists , so I quickly add it by running bower install­ -S angular -­drag-­and-­drop­lists . I also add a module dependency and the relevant JavaScript file to index.html
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page1
复制代码
  Following its instructions, let’s add some dnd attributes to the ticket div
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page2
复制代码
And then I eagerly go to verify if it works—and it does! But it’s ugly… So add the following style:
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page3
复制代码
This is much better, but still, something is not smooth enough when we try to move a ticket to the bottom. The reason is that there is not enough space between the list body and the button, a quick solution is by adding:
  1. <!-- file : /app/views/board_page.html --­­>

  2. This is the board page4
复制代码
When I play with it a bit more, I find that it’s still not smooth when I have a lot of tickets when scrolling the content. The functionality works, but there is some mild discomfort—for now, let’s let it be.
   I will open an issue on angular­-drag­-and­-drop­-lists project and on mine, and add a reference between them.
  A. Let’s look at how drag­-and-­drop is implemented

  I would like to pause for a minute and investigate how this library works. It contains only 1 file of 500 lines—most of them are documentation. So it shouldn’t take long to understand how it works.
  There are several cool things in this library that I took note of:
  
       
  • The directive does not have an isolated scope. This calms me down as I know I cannot have two directives with isolated scopes on the same element. So no problem here   
  • event.dataTransfer.setData("Text", angular.toJson(scope.$eval(attr.dndDraggable))); This line shows how this library translates the string—representing the draggable model to the actual model.
    It evaluates the model from the scope using scope.$eval . In our case  attr.dndDraggable is ticket.   
  • $parse(attr.dndDragstart)(scope, {event: event}); invokes the start callback.  
  These are a couple of nice things to know you can do with angular. And if I combine this knowledge with drag and drop MDN documentation I can wrap my head around the entire implementation.
  IV. Let’s look at our final results

  All the code above gets us to some promising initial results:
   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express

  As you can see, I was not joking when I said that Trello will be my inspiration. To recap all we’ve done so far:
  
       
  • We wrote the first page for our Trello clone application   
  • We added style to the page   
  • We added the ability to add lists and tickets.   
  • We added the Drag and Drop ability.  
  V. Live coding a Trello clone

  Let’s build the app together, join us in a coding session where we will build a Trello clone live! We will be adding persistency and cross-device sync to the app and even throw in a Q&A during the session.
   Join us on October 10th, 2016 to complete your Trello clone!
   RSVP now!
  Author’s Bio

   

Create a Trello Clone using Angular, Node.js, Mongo, and Express

Create a Trello Clone using Angular, Node.js, Mongo, and Express
Guy Mograbi has been a programmer in his heart and soul since his first “hello world.” He enjoys everything related to software development projects.



上一篇:Introducing InfraKit, an open source toolkit for creating and managing declarati
下一篇:神经网络与深度学习笔记(一)
baby126 发表于 2016-10-4 23:28:21
一语道尽爱情的残忍。情到深处人孤。疾苦使人成熟,强项的人会感悟爱的真谛,而懦弱的人徒生怅恨。
回复 支持 反对

使用道具 举报

安春 发表于 2016-10-6 11:12:46
视死如归的架势啊!
回复 支持 反对

使用道具 举报

lrtjk 发表于 2016-10-7 00:49:54
我也是醉了
回复 支持 反对

使用道具 举报

rtooj 发表于 2016-10-15 17:35:08
今天不想骂人!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )

© 2001-2017 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表