Challenge!! The Sushi Shop
Checkpoint 1: ทำการสร้าง sushi shop
โดยในหน้าจะประกอบด้วยส่วนของเมนูและส่วนของรายการที่สั่ง
ไฟล์ index.html ตั้งต้น
1 2 3 4 5 | < div class = "container" > < div class = "row" ui-view> </ div > </ div > |
- สร้าง state ชื่อ sushi
- ทำการดึงข้อมูล sushi จาก resolve โดยมีรายละเอียดดังนี้
- Otaro ราคา 200 yen
- Maguro ราคา 300 yen
- Tamago ราคา 120 yen
- Saba ราคา 100 yen
- Tako ราคา 150 yen
- กำหนด templateUrl เป็น shop.html
shop.html
12345678910111213141516171819202122232425262728<
div
class
=
"col-md-8"
>
<
ul
class
=
"nav nav-pills navbar-default"
>
<
li
><
a
ui-sref
=
"sushi"
>Sushi</
a
></
li
>
</
ul
>
<
div
>
<
div
class
=
"list-group"
>
<
div
class
=
"list-group-item row"
ng-repeat
=
"item in menuItem"
ng-init
=
"item.quantity = 0"
>
<
h2
class
=
"col-md-4"
>\{\{item.name}}</
h2
>
<
div
class
=
"col-md-2"
><
em
>\{\{item.price | number:2}} Yen </
div
>
<
div
class
=
"col-md-2"
><
p
>X \{\{item.quantity}}</
p
> <
button
class
=
"btn btn-default"
ng-click
=
"increase(item)"
>increse</
button
>
<
button
class
=
"btn btn-default"
ng-click
=
"decrease(item)"
>decrese</
button
></
div
>
<
div
class
=
"col-md-2"
><
button
class
=
"btn btn-default pull-right"
ng-click
=
"orderCall(item)"
>+</
button
></
div
>
</
div
>
</
div
>
</
div
>
</
div
>
<
div
class
=
"col-md-4"
>
<
div
class
=
"list-group"
>
<
div
class
=
"list-group-item row"
ng-repeat
=
"item in orderItem"
>
<
h2
class
=
"col-md-4"
>\{\{item.name}}</
h2
>
<
div
class
=
"col-md-4"
><
em
>\{\{item.price | number:2}} Yen </
div
>
<
div
class
=
"col-md-2"
><
p
>X \{\{item.quantity}}</
p
></
div
>
<
div
class
=
"col-md-2"
><
button
class
=
"btn btn-default pull-right"
ng-click
=
"removeOrder(item)"
>X</
button
></
div
>
</
div
>
<
button
ng-show="orderItem.length > 0" ng-click="checkOut()" class="btn btn-danger col-md-12">Check Out</
button
>
</
div
>
</
div
>
</
div
>
- กำหนด controller ให้มีรายละเอียดดังนี้
123456789
controller:
function
($scope, sushiItem) {
$scope.orderItem = [];
$scope.menuItem = sushiItem;
$scope.increase =
function
(item) { };
$scope.decrease =
function
(item) { };
$scope.orderCall =
function
(item) { };
$scope.removeOrder =
function
(item) { };
$scope.checkOut =
function
() { };
}
Checkpoint 1: จะได้ผลลัพธ์ดังรูป

Answer of Checkpoint 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | angular.module( 'application' , [ 'ui.router' ]) .config( function ($stateProvider, $urlRouterProvider) { $stateProvider .state( 'sushi' , { url: '/sushi' , resolve: { sushiItem: function () { var item = [ {name: "Otaro" , price: 200}, {name: "Maguro" , price: 300}, {name: "Tamago" , price: 120}, {name: "Saba" , price: 100}, {name: "Tako" , price: 150} ]; return item; } }, templateUrl: 'shop.html' , controller: function ($scope, sushiItem) { $scope.orderItem = []; $scope.menuItem = sushiItem; $scope.increase = function (item) { }; $scope.decrease = function (item) { }; $scope.orderCall = function (item) { }; $scope.removeOrder = function (item) { }; $scope.checkOut = function () { }; } }); |
Checkpoint 2: เราต้องการที่จะเพิ่มประเภทของเมนูเพิ่มเติม คือ appetizer และ drink

จากรูปสังเกตได้ว่าในหน้านี้มีส่วนที่เหมือนกัน คือ [ส่วนของประเภทอาหาร]และ[ส่วนรายการที่สั่ง]
และส่วนที่ต่างกันคือ ข้อมูลใน [ส่วนของเมนูอาหาร]
เราจึงทำการสร้าง abstract state ชื่อว่า shop เป็น template ให้สามารถ reuse ส่วนต่างๆของ template ได้
โดยจะแบ่ง view ของเป็น 3 หน้าดังนี้
- shop.html
123456789
<
div
class
=
"col-md-8"
>
<
ul
class
=
"nav nav-pills navbar-default"
>
<
li
><
a
ui-sref
=
"sushi"
>Sushi</
a
></
li
>
<
li
><
a
ui-sref
=
"appetizer"
>Appetizer</
a
></
li
>
<
li
><
a
ui-sref
=
"drink"
>Drink</
a
></
li
>
</
ul
><
div
ui-view
=
"menulist"
></
div
></
div
>
<
div
class
=
"col-md-4"
ui-view
=
"order"
>
</
div
>
</
div
>
- menu.html
123456789
<
div
class
=
"list-group"
>
<
div
class
=
"list-group-item row"
ng-repeat
=
"item in menuItem"
ng-init
=
"item.quantity = 0"
>
<
h2
class
=
"col-md-4"
>\{\{item.name}}</
h2
>
<
div
class
=
"col-md-2"
><
em
>\{\{item.price | number:2}} Yen </
div
>
<
div
class
=
"col-md-2"
><
p
>X \{\{item.quantity}}</
p
> <
button
class
=
"btn btn-default"
ng-click
=
"increase(item)"
>increse</
button
>
<
button
class
=
"btn btn-default"
ng-click
=
"decrease(item)"
>decrese</
button
></
div
>
<
div
class
=
"col-md-2"
><
button
class
=
"btn btn-default pull-right"
ng-click
=
"orderCall(item)"
>+</
button
></
div
>
</
div
>
</
div
>
- order.html
123456789
<
div
class
=
"list-group"
>
<
div
class
=
"list-group-item row"
ng-repeat
=
"item in orderItem"
>
<
h2
class
=
"col-md-4"
>\{\{item.name}}</
h2
>
<
div
class
=
"col-md-4"
><
em
>\{\{item.price | number:2}} Yen </
div
>
<
div
class
=
"col-md-2"
><
p
>X \{\{item.quantity}}</
p
></
div
>
<
div
class
=
"col-md-2"
><
button
class
=
"btn btn-default pull-right"
ng-click
=
"removeOrder(item)"
>X</
button
></
div
>
</
div
>
<
button
ng-show="orderItem.length > 0" ng-click="checkOut()" class="btn btn-danger col-md-12">Check Out</
button
>
</
div
>
จากนั้นทำการสร้าง shop state ขึ้นมา โดย
- กำหนดให้เป็น abstrct state
- กำหนด templateUrl ไปที่ shop.html
- ย้ายข้อมูลใน controller ของ sushi แยกออกมาดังนี้
12345678
function
($scope, $state) {
$scope.orderItem = [];
$scope.increase =
function
(item) { };
$scope.decrease =
function
(item) { };
$scope.orderCall =
function
(item) { };
$scope.removeOrder =
function
(item) { };
$scope.checkOut =
function
() { };
}
เมื่อเราต้องการใช้ส่วนต่างๆของ shop state ก็ทำการกำหนดให้เป็น child state

กำหนด sushi state เป็น child state ของ shop
- กำหนดให้ sushi เป็น child state ของ shop
- กำหนด views แทนการใช้ templateUrl โดยมี 2 views ดังนี้
- menulist
- กำหนด templateUrl ไปที่ menu.html
- กำหนด resolve ให้ดึงข้อมูล sushi มาแสดง
- ใน controller ทำการกำหนดค่าให้กับ menuItem
- order
- กำหนดให้ templateUrl ไปที่ order.html
- menulist
เพิ่ม appetizer state และ drink state โดยจะมีลักษณะ interface เหมือนกับ sushi
- appetizer state จะมีข้อมูลที่ต้อง resolve ดังนี้
- Takoyaki ราคา 500 yen
- Okonomiyaki ราคา 500 yen
- Yakisoba ราคา 650 yen
- Soba ราคา 400 yen
- drink state จะมีข้อมูลที่ต้อง resolve ดังนี้
- Coke ราคา 100 yen
- Water ราคา 100 yen
- Lemon Soda ราคา 250 yen
- Matcha ราคา 200 yen
Checkpoint 2: จะได้ผลลัพธ์ดังรูป

Answer of Checkpoint 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | angular.module( 'application' , [ 'ui.router' ]) .config( function ($stateProvider, $urlRouterProvider) { $stateProvider .state( 'shop' , { abstract: true templateUrl: 'shop.html' , controller: function ($scope, sushiItem) { $scope.orderItem = []; $scope.menuItem = sushiItem; $scope.increase = function (item) { }; $scope.decrease = function (item) { }; $scope.orderCall = function (item) { }; $scope.removeOrder = function (item) { }; $scope.checkOut = function () { }; } }) .state( 'shop.sushi' , { url: '/sushi' , resolve: { sushiItem: function () { var item = [ {name: "Otaro" , price: 200}, {name: "Maguro" , price: 300}, {name: "Tamago" , price: 120}, {name: "Saba" , price: 100}, {name: "Tako" , price: 150} ]; return item; } }, views: { "menulist" : { templateUrl: 'menu.html' , controller: function ($scope, sushiItem) { $scope.menuItem = sushiItem; } }, "order" : { templateUrl: 'order.html' } } }) .state( 'shop.appetizer' , { url: '/appetizer' , resolve: { sushiItem: function () { var item = [ {name: "Takoyaki" , price: 500}, {name: "Okonomiyaki" , price: 500}, {name: "Yakisoba" , price: 650}, {name: "Soba" , price: 400} ]; return item; } }, views: { "menulist" : { templateUrl: 'menu.html' , controller: function ($scope, sushiItem) { $scope.menuItem = sushiItem; } }, "order" : { templateUrl: 'order.html' } } }) .state( 'shop.drink' , { url: '/drink' , resolve: { sushiItem: function () { var item = [ {name: "Coke" , price: 100}, {name: "Water" , price: 100}, {name: "Lemon Soda" , price: 250}, {name: "Matcha" , price: 200} ]; return item; } }, views: { "menulist" : { templateUrl: 'menu.html' , controller: function ($scope, sushiItem) { $scope.menuItem = sushiItem; } }, "order" : { templateUrl: 'order.html' } } }); |
Checkpoint 3: กำหนดการทำงานให้กับฟังก์ชั่นต่างๆ ดังนี้
- increase(item) - เพิ่มจำนวนซูชิที่ต้องการ
- decrease(item) - ลดจำนวนซูชิที่ต้องการ [hint: จำนวนไม่น้อยกว่า 0]
- orderCall(item) - เพิ่มรายการที่สั่งลง orderItem [hint: push()]
- removeOrder(item) - ลบรายการที่สั่งออกจาก orderItem [hint: splice()]
Checkpoint 3: จะได้ผลลัพธ์ดังรูป

Answer of Checkpoint 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | angular.module( 'application' , [ 'ui.router' ]) .config( function ($stateProvider, $urlRouterProvider) { $stateProvider .state( 'shop' , { abstract: true templateUrl: 'shop.html' , controller: function ($scope, sushiItem) { $scope.orderItem = []; $scope.menuItem = sushiItem; $scope.increase = function (item) { if (item.quantity !== null ) { item.quantity += 1; } }; $scope.decrease = function (item) { if (item.quantity !== null && item.quantity > 0) { item.quantity -= 1; } }; $scope.orderCall = function (item) { if (item.quantity !== null && item.quantity > 0) { var addItem = angular.copy(item); $scope.orderItem.push(addItem); item.quantity = 0; } }; $scope.removeOrder = function (item) { var index = $scope.orderItem.indexOf(item); $scope.orderItem.splice(index, 1); } $scope.checkOut = function () { }; } }) .state( 'shop.sushi' , { ... }) .state( 'shop.appetizer' , { ... }) .state( 'shop.drink' , { ... }); |
Checkpoint 4: กำหนด checkout state สำหรับการสรุปค่าใช้จ่าย
สร้าง checkout state ขึ้นมา
- กำหนด templateUrl เป็น checkout.html
checkout.html
123456789101112131415161718<
div
>
<
ul
class
=
"nav nav-pills navbar-default"
>
<
li
><
a
ui-sref
=
"sushi"
>Back</
a
></
li
>
</
ul
>
</
div
>
<
div
class
=
"list-group"
>
<
div
class
=
"list-group-item row"
ng-repeat
=
"item in orderItem"
>
<
h2
class
=
"col-md-4"
>\{\{item.name}}</
h2
>
<
div
class
=
"col-md-4"
>
<
em
>\{\{item.price | number:2}} Yen X \{\{item.quantity}} = \{\{item.quantity * item.price}} Yen
</
div
>
</
div
>
<
div
class
=
"list-group-item row"
>
<
h2
class
=
"col-md-4"
>Total</
h2
>
<
h2
class
=
"col-md-4"
>\{\{sum}} Yen</
h2
>
</
div
>
<
button
ng-click
=
"payMoney()"
class
=
"btn btn-danger col-md-12"
>Pay</
button
>
</
div
>
- กำหนด params ให้รับค่า orderItem
1
params: {
'orderItem'
:
''
}
- กำหนดรายละเอียดของ controller ดังนี้
1234567891011
function
($scope, $stateParams, $state) {
$scope.orderItem = $stateParams.orderItem;
$scope.sum = 0;
angular.forEach($scope.orderItem,
function
(item) {
$scope.sum += (item.price * item.quantity);
});
$scope.payMoney =
function
() {
alert(
"Thank you."
);
$state.go(
'menu.sushi'
);
}
}
แต่เรายังหาทางไปยัง checkout ไม่ได้ ฉะนั้นให้ทำการกำหนดฟังก์ชั่น checkOut() ใน shop state
- กำหนดให้ map "orderItem" เข้ากับค่าของ orderItem ใส่ลงในตัวแปร params
- ส่งค่า params ไปยัง checkout state
Checkpoint 4: จะได้ผลลัพธ์ดังรูป

Answer of Checkpoint 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | angular.module( 'application' , [ 'ui.router' ]) .config( function ($stateProvider, $urlRouterProvider) { $stateProvider .state( 'shop' , { abstract: true templateUrl: 'shop.html' , controller: function ($scope, sushiItem) { $scope.orderItem = []; $scope.menuItem = sushiItem; ... $scope.checkOut = function () { var params = { "orderItem" :$scope.orderItem}; $state.go( "checkout" , params); }; } }) .state( 'shop.sushi' , { ... }) .state( 'shop.appetizer' , { ... }) .state( 'shop.drink' , { ... }) .state( 'checkout' , { url: '/checkout' , params: { 'orderItem' : '' }, templateUrl: 'checkout.html' , controller: function ($scope, $stateParams, $state) { $scope.orderItem = $stateParams.orderItem; $scope.sum = 0; angular.forEach($scope.orderItem, function (item) { $scope.sum += (item.price * item.quantity); }); $scope.payMoney = function () { alert( "Thank you." ); $state.go( 'shop.sushi' ); } } }); |