目次
本記事はknockout.jsの公式サイトにある以下のチュートリアルを実施した備忘録です。 learn.knockoutjs.com
Step1
foreachバインディングを使用して、プログラム内で保持しているデータを1個1個取り出して画面上に表形式で表示するサンプルプログラム
サンプルコード
ko.observableArray()で保持しているデータをhtml上で「foreach: [プロパティ名]」を指定することにより個々に取り出せることが分かった。
sample.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script> <script type="text/javascript" src="sample.js" defer="defer"></script> <title></title> </head> <body> <table> <thead> <tr> <th>Passenger name</th> <th>Meal</th> <th>Surcharge</th> <th></th> </tr> </thead> <tbody data-bind="foreach: seats"> <tr> <td data-bind="text: name"></td> <td data-bind="text: meal().mealName"></td> <td data-bind="text: meal().price"></td> </tr> </tbody> </table> </body> </html>
sample.js
function SeatReservation(name, initialMeal) { var self = this; self.name = name; self.meal = ko.observable(initialMeal); } function ReservationsViewModel(){ var self = this; self.availableMeals = [ { mealName: "Standard (sandwich)", price: 0 }, { mealName: "Premium (lobster)", price: 34.95 }, { mealName: "Ultimate (whole zebra)", price: 290 } ]; self.seats = ko.observableArray( [ new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0]) ] ); } ko.applyBindings(new ReservationsViewModel());
Step2
ボタンクリックで座席テーブルに対してデータを1行追加するサンプルプログラム
サンプルコード
ko.observableArray()を設定したプロパティからpush()が呼び出せ、 データを追加できることが分かった。 追加されると画面にも自動的に反映される。 画面が全体が再生成されず、テーブルの1行分のデータのみが部分的に反映されていることが分かった。
sample.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script> <script type="text/javascript" src="sample.js" defer="defer"></script> <title></title> </head> <body> <table> <thead> <tr> <th>Passenger name</th> <th>Meal</th> <th>Surcharge</th> <th></th> </tr> </thead> <tbody data-bind="foreach: seats"> <tr> <td data-bind="text: name"></td> <td data-bind="text: meal().mealName"></td> <td data-bind="text: meal().price"></td> </tr> </tbody> </table> <button data-bind="click: addSeat">座席を予約する</button> </body> </html>
sample.js
function SeatReservation(name, initialMeal) { var self = this; self.name = name; self.meal = ko.observable(initialMeal); } function ReservationsViewModel(){ var self = this; self.availableMeals = [ { mealName: "Standard (sandwich)", price: 0 }, { mealName: "Premium (lobster)", price: 34.95 }, { mealName: "Ultimate (whole zebra)", price: 290 } ]; self.seats = ko.observableArray( [ new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0]) ] ); self.addSeat = function(){ self.seats.push(new SeatReservation("", self.availableMeals[0])) } } ko.applyBindings(new ReservationsViewModel());
Step3
前回までテキスト表示していた部分をテキストボックスとセレクトボックスに変更してデータを更新できるようにしたサンプルプログラム
サンプルコード
前回までの内容を組み合わせた応用のサンプルプログラム。 そして簡単にテキスト表示から入力ボックスへの変更など行えることが分かった。
sample.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script> <script type="text/javascript" src="sample.js" defer="defer"></script> <title></title> </head> <body> <table> <thead> <tr> <th>Passenger name</th> <th>Meal</th> <th>Surcharge</th> <th></th> </tr> </thead> <tbody data-bind="foreach: seats"> <tr> <td><input data-bind="value: name"></td> <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td> <td data-bind="text: formattedPrice"></td> </tr> </tbody> </table> <button data-bind="click: addSeat">座席を予約する</button> </body> </html>
sample.js
function SeatReservation(name, initialMeal) { var self = this; self.name = name; self.meal = ko.observable(initialMeal); self.formattedPrice = ko.computed(function(){ var price = self.meal().price; return price ? "$" + price.toFixed(2) : "None"; }); } function ReservationsViewModel(){ var self = this; self.availableMeals = [ { mealName: "Standard (sandwich)", price: 0 }, { mealName: "Premium (lobster)", price: 34.95 }, { mealName: "Ultimate (whole zebra)", price: 290 } ]; self.seats = ko.observableArray([ new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0]) ]); self.addSeat = function(){ self.seats.push(new SeatReservation("", self.availableMeals[0])) } } ko.applyBindings(new ReservationsViewModel());
Step4
シートの削除と合計料金表示を実装したサンプルプログラム
サンプルコード
ViewModel内のデータ追加削除などが自由に行えることが分かった。 今回のサンプルプログラムにてforeach内のスコープはSeatReservationを指しており、 ReservationsViewModel内のプロパティを使用するには$rootを使用しなくてはいけないことが分かった。 $rootはトップレベルのViewModelであるReservationsViewModelを指している。 つまりはko.applyBindings()の引数に渡しているViewModelがトップレベルとなっていることが分かった。
sample.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script> <script type="text/javascript" src="sample.js" defer="defer"></script> <title></title> </head> <body> <table> <thead> <tr> <th>Passenger name</th> <th>Meal</th> <th>Surcharge</th> <th></th> </tr> </thead> <tbody data-bind="foreach: seats"> <tr> <td><input data-bind="value: name"></td> <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td> <td data-bind="text: formattedPrice"></td> <td><a href="#" data-bind="click: $root.removeSeat">削除</a></td> </tr> </tbody> </table> <h3 data-bind="visible: totalSurcharge() > 0"> Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span> </h3> <button data-bind="click: addSeat">座席を予約する</button> </body> </html>
sample.js
function SeatReservation(name, initialMeal) { var self = this; self.name = name; self.meal = ko.observable(initialMeal); self.formattedPrice = ko.computed(function(){ var price = self.meal().price; return price ? "$" + price.toFixed(2) : "None"; }); } function ReservationsViewModel(){ var self = this; self.availableMeals = [ { mealName: "Standard (sandwich)", price: 0 }, { mealName: "Premium (lobster)", price: 34.95 }, { mealName: "Ultimate (whole zebra)", price: 290 } ]; self.seats = ko.observableArray([ new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0]) ]); self.addSeat = function(){ self.seats.push(new SeatReservation("", self.availableMeals[0])) } self.removeSeat = function(seat){ self.seats.remove(seat) } self.totalSurcharge = ko.computed(function(){ var total = 0; for(var i = 0; i < self.seats().length; i++) total += self.seats()[i].meal().price; return total; }); } ko.applyBindings(new ReservationsViewModel());
Step5
総座席数と予約可能座席数を満たした場合にボタンを非活性にする処理を実装したサンプルプログラム
サンプルコード
一度作成した要素のdata-bind属性にプロパティを追加していけば、細かい制御を追加できることが分かった。 jQueryなどで行うとDOMを書き換える必要があるので、それに比べると細かい処理が簡潔に実装できるなと感じた。
sample.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" src="../../lib/knockout-3.2.0.js"></script> <script type="text/javascript" src="sample.js" defer="defer"></script> <title></title> </head> <body> <h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2> <table> <thead> <tr> <th>Passenger name</th> <th>Meal</th> <th>Surcharge</th> <th></th> </tr> </thead> <tbody data-bind="foreach: seats"> <tr> <td><input data-bind="value: name"></td> <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td> <td data-bind="text: formattedPrice"></td> <td><a href="#" data-bind="click: $root.removeSeat">削除</a></td> </tr> </tbody> </table> <h3 data-bind="visible: totalSurcharge() > 0"> Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span> </h3> <button data-bind="click: addSeat, enable: seats().length < 5">座席を予約する</button> </body> </html>
sample.js
function SeatReservation(name, initialMeal) { var self = this; self.name = name; self.meal = ko.observable(initialMeal); self.formattedPrice = ko.computed(function(){ var price = self.meal().price; return price ? "$" + price.toFixed(2) : "None"; }); } function ReservationsViewModel(){ var self = this; self.availableMeals = [ { mealName: "Standard (sandwich)", price: 0 }, { mealName: "Premium (lobster)", price: 34.95 }, { mealName: "Ultimate (whole zebra)", price: 290 } ]; self.seats = ko.observableArray( [ new SeatReservation("Steve", self.availableMeals[0]), new SeatReservation("Bert", self.availableMeals[0]) ] ); self.addSeat = function(){ self.seats.push(new SeatReservation("", self.availableMeals[0])) } self.removeSeat = function(seat){ self.seats.remove(seat) } self.totalSurcharge = ko.computed(function(){ var total = 0; for(var i = 0; i < self.seats().length; i++) total += self.seats()[i].meal().price; return total; }); } ko.applyBindings(new ReservationsViewModel());
記事トップは以下になります。