摘要:[AngularJs]新增留言板功能及驗證機制說明
概述
本章,將介紹新的Directives,並不贅續說明直接以範例說明。
-
ng-model
- 這個Directive 提供值綁定功能。
-
validations
- 本章將說明驗證的機制。
- 驗證將觸發 classes變更並對應到css,默認匹配幾個 css 項目(名稱對應上,即可自訂義內容),以凸顯某驗證機制的顯示。
寶石商店
新任務,在每個寶石資訊中加入提供者留言版功能。
-
於js中新增回覆訊息類別。
function Review(inputStars,inputBody,inputAuthor) { this.stars=inputStars; this.body=inputBody this.author=inputAuthor }
-
修正js中gems對象,所帶的參數,給一些預設的留言訊息。
var gems=[ { name:'Dodecahedron', price:5.95, description:'Some gems have hidden qualities beyond their luster,beyond their shine...Dodeca is one of those gems.', date:1388123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/3244f630-438f-42ea-9f1f-cd8645b3f024/2014-07-10_1510.png', //新增回覆屬性 reviews:[ new Review(3,'I love this product!','I love this product!','Benson@hotmail.com') , new Review(5,'good for you!','tom@yahoo.com.tw') ] }, { name:'pentagonalGem', price:5, description:'Some gems have hidden qualities beyond their luster,beyond their shine...Dodeca is one of those gems.', date:1288123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/f6c03fe4-6d0a-421f-904e-9ad3890ed755/2014-07-10_1511.png', reviews:[ new Review(1,'good for you!','joe@yahoo.com.tw') , new Review(5,'cheap!','tom@yahoo.com.tw') ] }, { name:'redGem', price:3.85, description:'Red.', date:1299123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/ea8c267d-032d-4d54-b9a4-cb5861e2c7ca/2014-07-10_1512.png', reviews:[ new Review(4,'well done!','amber@yahoo.com.tw') , new Review(5,'pretty!','mark@yahoo.com.tw') ] } , { name:'bigGem', price:3.20, description:'big', date:132123412323, img:' http://content.screencast.com/users/BensonLan/folders/Jing/media/c8d1f866-8cc0-4475-84e5-b671176367e2/2014-07-10_1512.png', reviews:[ new Review(3,'oh my god!','san@yahoo.com.tw') , new Review(2,'i want it!','qq@yahoo.com.tw') ] }
-
新增一個controller,當作流言版的控制器。並定義當html按下Submit時的邏輯。
//留言版的controller app.controller("ReviewController", function(){ //init this.review =new Review(1,'',''); //when Submit doing this.addReview=function(product) { product.reviews.push(this.review); this.review =new Review(1,'',''); }; })
-
html前端,新增一個留言版的form 於珠寶項目中
- novalidate(不須驗證)、required(需要驗證的項目,當屬性改變時檢查及更改form.$valid狀態並通知 )
-
<!-- 留言板--> <!--新增 ReviewController--> <!--novalidate 不須被驗證--> <!--在form標籤中我們只需要取得$valid 驗證是否執行reviewCtrl.addReview(product)--> <form name="reviewForm" class="form-horizontal" ng-controller="ReviewController as reviewCtrl" ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)" novalidate > <div class="form-group"> <div class="controls"> <blockquote> <b>Stars: {{ reviewCtrl.review.stars}}</b> {{ reviewCtrl.review.body}} <cite>by: {{ reviewCtrl.review.author}}</cite> </blockquote> </div> </div> <div class="form-group"> <section> <!--<label>stars:</label>--> <label class="control-label">Stars</label> <!-- required 需要被驗證--> <div class="controls"> <select ng-model="reviewCtrl.review.stars" required> <option value="1">1 star</option> <option value="2">2 stars</option> <option value="3">3 stars</option> <option value="4">4 stars</option> <option value="5">5 stars</option> </select> </div> </section> </div> <div class="form-group"> <label class="control-label">Description</label> <div class="controls"> <!-- required 需要被驗證--> <textarea ng-model="reviewCtrl.review.body" placeholder="Typing Description…" required></textarea> </div> </div> <div class="form-group"> <label class="control-label">Author</label> <div class="controls"> <!-- required 需要被驗證--> <input ng-model="reviewCtrl.review.author" type="email" placeholder="Typing email…" required/> </div> </div> <div class="form-group"> <div class="controls"> //若 驗證失敗 則disabled <input type="submit" ng-disabled="!reviewForm.$valid" class="btn btn-primary" value="Submit"/> </div> </div> </form>
-
新增style.css 標示驗證狀態改變時,required 項目 顯示的顏色不同
-
ng-invalid.ng-dirty
- 當無效時會匹配到css的名稱
-
ng-valid.ng-dirty
- 當有效時會匹配到css的名稱
-
ng-pristine.ng-invalid
- 當項目初始的匹配到css的名稱
.ng-invalid.ng-dirty { border-color: #FA787E; } .ng-valid.ng-dirty { border-color: #78FA89; } .ng-pristine.ng-invalid { border-color: #333333; }
-
ng-invalid.ng-dirty
經以上程序後,完整代碼如下:
-
js code
//建構 AppConstructor() //將你的JavaScipt 放在一個閉包裡是一個好的習慣 function AppConstructor() { app = angular.module('store', [ ]); app.controller('StoreController', function() { this.products=gems; }); var gems=[ { name:'Dodecahedron', price:5.95, description:'Some gems have hidden qualities beyond their luster,beyond their shine...Dodeca is one of those gems.', date:1388123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/3244f630-438f-42ea-9f1f-cd8645b3f024/2014-07-10_1510.png', reviews:[ new Review(3,'I love this product!','I love this product!','Benson@hotmail.com') , new Review(5,'good for you!','tom@yahoo.com.tw') ] }, { name:'pentagonalGem', price:5, description:'Some gems have hidden qualities beyond their luster,beyond their shine...Dodeca is one of those gems.', date:1288123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/f6c03fe4-6d0a-421f-904e-9ad3890ed755/2014-07-10_1511.png', reviews:[ new Review(1,'good for you!','joe@yahoo.com.tw') , new Review(5,'cheap!','tom@yahoo.com.tw') ] }, { name:'redGem', price:3.85, description:'Red.', date:1299123412323, img:'http://content.screencast.com/users/BensonLan/folders/Jing/media/ea8c267d-032d-4d54-b9a4-cb5861e2c7ca/2014-07-10_1512.png', reviews:[ new Review(4,'well done!','amber@yahoo.com.tw') , new Review(5,'pretty!','mark@yahoo.com.tw') ] } , { name:'bigGem', price:3.20, description:'big', date:132123412323, img:' http://content.screencast.com/users/BensonLan/folders/Jing/media/c8d1f866-8cc0-4475-84e5-b671176367e2/2014-07-10_1512.png', reviews:[ new Review(3,'oh my god!','san@yahoo.com.tw') , new Review(2,'i want it!','qq@yahoo.com.tw') ] } ] //新增一個 PanelController 來控制顯示寶石資訊細節的 table app.controller('PanelController', function() { //controller內的屬性一有變動就會自動檢查html與controller有綁定方法的元素 //所以只需 將html 元素 與 controll綁定就好 不用擔心何時觸發 //這部分 是否有人可以幫忙補充? this.tabIndex = 1; this.selectTab = function(setTab) { this.tabIndex = setTab; } //判斷選擇的頁面 是否 等於 該tabIndex this.isSelected = function(checkTab){ return this.tabIndex === checkTab; }; }); //留言版的controller app.controller("ReviewController", function(){ //init this.review =new Review(1,'',''); //when Submit doing this.addReview=function(product) { product.reviews.push(this.review); this.review =new Review(1,'',''); }; }); function Review(inputStars,inputBody,inputAuthor) { this.stars=inputStars; this.body=inputBody this.author=inputAuthor } }
-
html code
<!DOCTYPE html> <html ng-app="store"> <head lang="en"> <script type="text/javascript" src="angular.min.js"></script> <script type="text/javascript" src="app.js"></script> <link rel="stylesheet" href="bootstrap.css"/> <link rel="stylesheet" href="bootstrap-theme.css"> <link rel="stylesheet" href="style.css"> <meta charset="UTF-8"> <title></title> </head> <body ng-controller="StoreController as store"> <p> <ul class="list-group"> <li class="list-group-item" ng-repeat="product in store.products | orderBy:'name' "> <h3> {{product.name | uppercase}} <em class="pull-right"> {{product.price | currency }} </em> </h3> <p>{{product.date | date:'MM/dd/yyyy'}}</p> <p><img ng-src="{{product.img}}"></p> //新增 一個 controller //新增一個 PanelController 來控制顯示寶石資訊細節的 table <section ng-controller="PanelController as panel"> <ul class="nav nav-pills"> <!--active:panel.tab===1 的意思是 若 panel.tab===1 時 激活(顯示) --> <li ng-class={active:panel.tabIndex===1}> <a href ng-click="panel.selectTab(1)">Description</a> </li> <li ng-class="{active:panel.tabIndex===2}"> <a href ng-click="panel.selectTab(2)">Price</a> </li> <li ng-class="{active:panel.tabIndex===3}"> <a href ng-click="panel.selectTab(3)">Reviews</a> </li> </div> </ul> <div class="container"> //呼叫controller的方法 判斷資訊是否 可顯示 <div class="panel" ng-show="panel.isSelected(1)"> <h4>Description</h4> <p>{{product.description}}</p> </div> <div class="panel" ng-show="panel.isSelected(2)"> <h4>Price</h4> <p>{{product.price}}</p> </div> <div class="panel" ng-show="panel.isSelected(3)"> <h4>Reviews</h4> <img ng-src="{{product.img}}"/> </div> </div> </section> <section> <blockquote ng-repeat="review in product.reviews"> <h3> <b>Stars: {{review.stars}}</b> {{review.body}} <cite>by: {{review.author}}</cite> <cite>Description:{{review.body}}</cite> </h3> </blockquote> </section> <!-- 留言板--> <!--新增 ReviewController--> <!--novalidate 不須被驗證--> <!--在form標籤中我們只需要取得$valid 驗證是否執行reviewCtrl.addReview(product)--> <form name="reviewForm" class="form-horizontal" ng-controller="ReviewController as reviewCtrl" ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)" novalidate > <div class="form-group"> <div class="controls"> <blockquote> <b>Stars: {{ reviewCtrl.review.stars}}</b> {{ reviewCtrl.review.body}} <cite>by: {{ reviewCtrl.review.author}}</cite> </blockquote> </div> </div> <div class="form-group"> <section> <!--<label>stars:</label>--> <label class="control-label">Stars</label> <!-- required 需要被驗證--> <div class="controls"> <select ng-model="reviewCtrl.review.stars" required> <option value="1">1 star</option> <option value="2">2 stars</option> <option value="3">3 stars</option> <option value="4">4 stars</option> <option value="5">5 stars</option> </select> </div> </section> </div> <div class="form-group"> <label class="control-label">Description</label> <div class="controls"> <!-- required 需要被驗證--> <textarea ng-model="reviewCtrl.review.body" placeholder="Typing Description…" required></textarea> </div> </div> <div class="form-group"> <label class="control-label">Author</label> <div class="controls"> <!-- required 需要被驗證--> <input ng-model="reviewCtrl.review.author" type="email" placeholder="Typing email…" required/> </div> </div> <div class="form-group"> <div class="controls"> //若 驗證失敗 則disabled <input type="submit" ng-disabled="!reviewForm.$valid" class="btn btn-primary" value="Submit"/> </div> </div> </form> </li> </ul> </p> </body> </html>
-
css
.ng-invalid.ng-dirty { border-color: #FA787E; } .ng-valid.ng-dirty { border-color: #78FA89; } .ng-pristine.ng-invalid { border-color: #333333; }
Result
By-藍小伙