레벨 3에서는 form과 model에 대해서 공부한다.
app.js
(function() {
var app = angular.module('gemStore', []);
app.controller('StoreController', function(){
this.products = gems;
});
app.controller('TabController', function(){
this.tab = 1;
this.setTab = function(newValue){
this.tab = newValue;
};
this.isSet = function(tabName){
return this.tab === tabName;
};
});
app.controller('GalleryController', function(){
this.current = 0;
this.setCurrent = function(newGallery){
this.current = newGallery || 0;
};
});
var gems = [{
name: 'Azurite',
description: "Some gems have hidden qualities beyond their luster, beyond their shine... Azurite is one of those gems.",
shine: 8,
price: 110.50,
rarity: 7,
color: '#CCC',
faces: 14,
images: [
"images/gem-02.gif",
"images/gem-05.gif",
"images/gem-09.gif"
],
reviews: [{
stars: 5,
body: "I love this gem!",
author: "joe@example.org",
createdOn: 1397490980837
}, {
stars: 1,
body: "This gem sucks.",
author: "tim@example.org",
createdOn: 1397490980837
}]
}, {
name: 'Bloodstone',
description: "Origin of the Bloodstone is unknown, hence its low value. It has a very high shine and 12 sides, however.",
shine: 9,
price: 22.90,
rarity: 6,
color: '#EEE',
faces: 12,
images: [
"images/gem-01.gif",
"images/gem-03.gif",
"images/gem-04.gif",
],
reviews: [{
stars: 3,
body: "I think this gem was just OK, could honestly use more shine, IMO.",
author: "JimmyDean@example.org",
createdOn: 1397490980837
}, {
stars: 4,
body: "Any gem with 12 faces is for me!",
author: "gemsRock@example.org",
createdOn: 1397490980837
}]
}, {
name: 'Zircon',
description: "Zircon is our most coveted and sought after gem. You will pay much to be the proud owner of this gorgeous and high shine gem.",
shine: 70,
price: 1100,
rarity: 2,
color: '#000',
faces: 6,
images: [
"images/gem-06.gif",
"images/gem-07.gif",
"images/gem-08.gif"
],
reviews: [{
stars: 1,
body: "This gem is WAY too expensive for its rarity value.",
author: "turtleguyy@example.org",
createdOn: 1397490980837
}, {
stars: 1,
body: "BBW: High Shine != High Quality.",
author: "LouisW407@example.org",
createdOn: 1397490980837
}, {
stars: 1,
body: "Don't waste your rubles!",
author: "nat@example.org",
createdOn: 1397490980837
}]
}];
})();
reviews 배열이 추가되었다.
index.html
<!-- Review Form -->
<form name="reviewForm">
<!-- Live Preview -->
<blockquote>
<strong>{{review.stars}} Stars</strong>
{{review.body}}
<cite class="clearfix">-{{review.author}}</cite>
</blockquote>
<!-- Review Form -->
<h4>Submit a Review</h4>
<fieldset class="form-group">
<select ng-model="review.stars" class="form-control" ng-options="stars for stars in [5,4,3,2,1]" title="Stars">
<option value="">Rate the Product</option>
</select>
</fieldset>
<fieldset class="form-group">
<textarea ng-model="review.body" class="form-control" placeholder="Write a short review of the product..." title="Review"></textarea>
</fieldset>
<fieldset class="form-group">
<input ng-model="review.author" type="email" class="form-control" placeholder="jimmyDean@example.org" title="Email" />
</fieldset>
<fieldset class="form-group">
<input type="submit" class="btn btn-primary pull-right" value="Submit Review" />
</fieldset>
</form>
form은 그냥 평범한 form 태그를 써주면 된다. 그리고 select 태그나 input 태그에 ng-model 속성을 주고 여기에 입력을 하면, Live Preview에서 해당 변수명이 실시간으로 변하는 것을 볼 수 있다.
이제, form에 입력한 리뷰를 등록해보자.
컨트롤러를 사용할 때이다.
app.js에 ReviewController를 만든다.
app.controller('ReviewController', function(){
this.review = {};
this.addReview = function(product){
product.reviews.push(this.review);
this.review = {};
};
});
addReview 펑션에서 push 후 review 오브젝트를 다시 비워주는 이유는, 리뷰 입력후 submit 날린 후 다시 form을 클리어해서 보여주기 위해서다. review 오브젝트를 비워주지 않으면 submit 후에도 여전히 내가 남긴 코멘트가 남아있을 것이다. angular.js의 2way binding이 이런 건가보다.. 신기하네.
html
<form name="reviewForm" ng-controller="ReviewController as reviewCtrl"
ng-submit="reviewCtrl.addReview(product)">
<!-- Live Preview -->
<blockquote>
<strong>{{reviewCtrl.review.stars}} Stars</strong>
{{reviewCtrl.review.body}}
<cite class="clearfix">—{{reviewCtrl.review.author}}</cite>
</blockquote>
<!-- Review Form -->
<h4>Submit a Review</h4>
<fieldset class="form-group">
<select ng-model="reviewCtrl.review.stars" class="form-control" ng-options="stars for stars in [5,4,3,2,1]" title="Stars">
<option value="">Rate the Product</option>
</select>
</fieldset>
<fieldset class="form-group">
<textarea ng-model="reviewCtrl.review.body" class="form-control" placeholder="Write a short review of the product..." title="Review"></textarea>
</fieldset>
<fieldset class="form-group">
<input ng-model="reviewCtrl.review.author" type="email" class="form-control" placeholder="jimmyDean@example.org" title="Email" />
</fieldset>
<fieldset class="form-group">
<input type="submit" class="btn btn-primary pull-right" value="Submit Review" />
</fieldset>
</form>
form에 리뷰 컨트롤러를 씌워(?)주고, ng-submit으로 form이 submit됐을때 해야할 액션을 지정해준다. 그리고 Live Preview에도 reviewCtrl의 review를 가져오도록 해야 제대로 동작한다. ng-model도 마찬가지로 reviewCtrl을 참조하도록 수정해준다. 이렇게 하면 submit 날리는 경우 reviews 배열에 차곡차곡 쌓인다.
이제 validation 체크를 해보자.
<!-- Review Form -->
<form name="reviewForm" ng-controller="ReviewController as reviewCtrl"
ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)" novalidate>
<!-- Live Preview -->
<blockquote >
<strong>{{reviewCtrl.review.stars}} Stars</strong>
{{reviewCtrl.review.body}}
<cite class="clearfix">—{{reviewCtrl.review.author}}</cite>
</blockquote>
<!-- Review Form -->
<h4>Submit a Review</h4>
<fieldset class="form-group">
<select ng-model="reviewCtrl.review.stars" class="form-control" ng-options="stars for stars in [5,4,3,2,1]" title="Stars" required>
<option value="">Rate the Product</option>
</select>
</fieldset>
<fieldset class="form-group">
<textarea ng-model="reviewCtrl.review.body" class="form-control" placeholder="Write a short review of the product..." title="Review"></textarea>
</fieldset>
<fieldset class="form-group">
<input ng-model="reviewCtrl.review.author" type="email" class="form-control" placeholder="jimmyDean@example.org" title="Email" required/>
</fieldset>
<fieldset class="form-group">
<input type="submit" class="btn btn-primary pull-right" value="Submit Review" />
</fieldset>
</form>
일단 form에 novalidate 속성을 추가해준다. 이는 html에서 기본으로 제공하는 validation 검사를 쓰지 않겠다는 의미이다. 그리고 required는 필수값이고, type='email', 'number' 등으로 지정해주면 angular에서 알아서 validation 검사를 해준다. validation 결과가 false라도 submit은 실행된다. 이를 막기 위해 ng-submit에 reviewForm.$valid 를 추가해준다. $valide는 angular가 내장하고 있는 변수이다. validation 통과 유무를 true/false 값으로 가지고 있다.
angular에서는 input 태그에 validation 과 관련된 class를 자동으로 추가해준다.
예를 들면, 타이핑 전에는 ng-pristine ng-invalid 클래스가 아래와 같이 자동으로 들어가 있는 것이다.
<input ng-model="reviewCtrl.review.author" type="email" class="form-control ng-pristine ng-invalid " placeholder="jimmyDean@example.org" title="Email" required/>
타이핑 후에는 ng-pristine이 ng-dirty 클래스로 변경되며, validation 통과한 경우 ng-invalid 가 ng-valid로 바뀌게 된다.
이를 이용해서 css로 valid 여부를 보여줄 수 있다.
css
.ng-invalid.ng-dirty {
border-color : red;
}
.ng-valid.ng-dirty {
border-color : green;
}
마지막으로, review를 추가할때 등록시간을 넣어주자.
this.addReview = function(product){
this.review.createdOn = Date.now();
product.reviews.push(this.review);
this.review = {};
};
보여줄때는 date filter를 쓰면 간단하게 변환할 수 있다.
<cite class="clearfix">—{{review.author}} on {{review.createdOn | date}}</cite>
* 소스는 모두 http://campus.codeschool.com 에서 가져온 겁니다.
'Javascript > Angular.js' 카테고리의 다른 글
CodeSchool Angular.js Level5 (0) | 2017.03.10 |
---|---|
CodeSchool Angular.js Level4 (0) | 2017.03.09 |
CodeSchool Angular.js Level2 (0) | 2017.03.06 |
CodeSchool Angular.js Level1 (0) | 2017.02.27 |