みこむらめもむらむらむら

なんかHTML5とかJS勉強とかやりながらめもを綴るブログ

【KnouckoutJS】リストの操作

はいはいKnouckoutJSお勉強なうです

はじめに

Working with Lists and Collections
Building a dynamic UI where elements are added and removed

ということでリストの操作です、利用頻度高そう
要素の追加、削除の動的なUI構築とあるくらいなので
変更が即時反映のリストが作れるんだろうなという期待をしつつ
実際にチュートリアルをやってみるよ


今回は座席や食事を予約ツールが例題でございまする

// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
    var self = this;
    self.name = name;
    self.meal = ko.observable(initialMeal);
}

// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
    var self = this;

    // Non-editable catalog data - would come from the server
    self.availableMeals = [
        { mealName: "Standard (sandwich)", price: 0 },
        { mealName: "Premium (lobster)", price: 34.95 },
        { mealName: "Ultimate (whole zebra)", price: 290 }
    ];    

    // Editable data
    self.seats = ko.observableArray([ //★1
        new SeatReservation("Steve", self.availableMeals[0]),
        new SeatReservation("Bert", self.availableMeals[0])
    ]);
}

ko.applyBindings(new ReservationsViewModel());

まずはViewModel(javascript)の方のあれそれ
とくにReservationsViewModelのseatsに注目(★1)
SeatReservationの初期値を保持する配列であると同時に
ko.observableArrayであることが大事

KnouckoutJSではおなじみのko.observableなわけで
項目が追加、削除されるたびに自動的にUIの更新が可能になる
うむーなんともこのko.observableにまだ慣れないのだが
これめっちゃ使うみたいなのよな‥慣れるまで時間かかりそう‥

お次はView(html)‥こっちもdata-bindに慣れねばな‥

<h1>Your seat reservations</h1>
<table>
    <thead><tr>
        <th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
    </tr></thead>
    <tbody data-bind="foreach: seats"><!--★2-->
        <tr>
            <td data-bind="text: name"></td>
            <td data-bind="text: meal().mealName"></td>
            <td data-bind="text: meal().price"></td><!--★3-->

        </tr>    
    </tbody>
</table>

こちらで注意すべきはmealプロパティの値を参照する際(★3)
関数のように

meal()

と記述する必要があるということ
故に食事の値段は

meal().price

となるわけです
なんで関数呼び出しなんだ?ってところが曖昧なんだよな‥代入処理じゃないからってどういうこと?
理解できてなすぎて死にたい、聞いてみよう‥

ちなみにforeachバインディングはおなじみの繰り返し処理で(★2)
tbody内のコンテンツを繰り返して表示するみたい
他にもifとかifnotとかもつかえるとかつかえないとかごにょごにょ

席を追加する

お次は先ほどのソースにそれぞれ下記を追加、実行!

<!--ソースの一番最後に追加-->
<button data-bind="click: addSeat">Reserve another seat</button>
function ReservationsViewModel() {
    // ※他はそのままで下記だけ追加

    // Operations
    self.addSeat = function() {
        self.seats.push(new SeatReservation("", self.availableMeals[0]));
    }
}

ボタンクリックで配列が追加できるようになりました!わー!

ReservationsViewModelのseats(★3)が
ko.observableArrayがゆえに常に値を監視されていて
先ほども述べたように追加、削除の処理が行われると
自動的にUIが更新されまする

ちなみに私は、あれ.push()ってなんだっけってなりました
Arrayオブジェクトの.push()は配列末尾に要素を追加でごわす

そうだね追加処理だね!←

ここでとくに注目すべきは
行を追加しても再生にUI全体リロードされるわけではないこと!
効率化のためKnouckoutJSは更新のあった最小限の処理を反映するように
できているそうな‥利口!

編集可能なデータを作成する

お次は既存のデータや追加したデータを編集できすようになるそうな
まずはView(html)の下記部分を

<td data-bind="text: name"></td>
<td data-bind="text: meal().mealName"></td>

↓こんな感じに書き換えてみまする

<td><input data-bind="value: name" /></td>
<td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td><!--★4-->

ドロップダウンのリスト新たに2つのバインディングを使用しているとな、ふむふむ
使用しているバイディングは下記の2つ

利用可能な項目の設定にoptionsバインディング
optionsバインディングはselect要素のみに使用するもので
割り当てる値は配列(または観察配列)
配列内の各項目ごとにoption要素が表示されるらしい

利用可能な項目のプロパティを表示するためにoptionsTextバインディング
リストのテキストとして表示されるべき
プロパティを設定するためのバインディング
ふむふむ、ここではmealNameだけどこれをpriceにすれば値段が表示されるのかー
にゃるほど!

ここでは何も触れてないのだけれど$rootのとこがなんで必要なのかわかりますん
わ、わかるのがあたりまえなの‥(((;゚Д゚)))ガクブル

価格の書式設定(データフォーマット機能を追加する)

なにやらお次は価格表示をデータの中身によって整形し直して
表示する機能を追加するようです

なんか翻訳が上手いこといってなくてわかりにくいんだけれど
KnouckoutJSはデータをきれいにオブジェクト指向で書いているから
オブジェクトグラフ内の任意の場所に簡単に機能を追加できるそうな
オブジェクトグラフってなんだよと思ったのは内緒
ぐぐってもベストアンサーがなかった‥

さて、ソース見てみましょう

今回はViewModel(javascript)から

function SeatReservation(name, initialMeal) {
    var self = this;
    self.name = name;
    self.meal = ko.observable(initialMeal);

    self.formattedPrice = ko.computed(function() { //★5
        var price = self.meal().price;
        return price ? "$" + price.toFixed(2) : "None";        
    });
}

formattedPriceを追加します(★5)
価格が0だったらNone、1以上だったら$マークをつけるフォーマット機能を追加

とくに注目すべきはko.computedの部分
監視している値をもとに処理を実行し
結果のデータを自動で返している、みたい←

ちなみにこのフォーマットされたデータをView(html)に表示する場合は

<td data-bind="text: meal().price"></td>

↓こんな感じに書き換えまする

<td data-bind="text: formattedPrice"></td>

うむうむ、自動更新される、すごい

項目を削除する

追加もできれば削除もできるよね!ということで★6の行をView(html)に追加
削除リンクですです

<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">Remove</a></td><!--★6-->
</tr> 

さてここでも出てきました$root
翻訳ツールで翻訳すると

$rootの接頭辞は、トップレベルのViewModelの代わりにSeatReservationインスタンスがバインドされている上にremoveSeatハンドラを探すためにノックアウトを引き起こすことに注意してください

はて、どういうことですかね‥?w
どうしよう全然わからない
そもそも$rootが全然わかってないのよね‥これは質問します‥

function ReservationsViewModel() {
    // ※そのまま

    // Operations
    self.addSeat = function() {
        // ※そのままで下記を追加
    }
    self.removeSeat = function(seat) {
        self.seats.remove(seat);
    }
} 

ViewModel(javascript)の方にはView(html)でdata-bindしたremoveSeatを追加

するとリンククリックで予約データ削除!おおーできました

合計金額を表示する

お次は食事の合計金額の計算処理を追加です
ko.computedですな

function ReservationsViewModel() {
   // ※他はそのままで下記だけ追加

   // Computed data
   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;
   });
} 

互いに監視関係にあるので
更新があるたびに自動でUIにも更新がされまする、うむ

さて今度は計算処理した合計値をView(html)に表示するためにこちらも追記

<p data-bind="visible: totalSurcharge() > 0"><!--★7-->
    Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</p>

ここではvisibleバインディングを使用してますな(★7)
これは感覚でわかるー
CSSのdisplayプロパティをごにょごにょしているわけですな

あとここでもう一つ、バインディングの内側に
任意のJavaScript式を使用しているところも注目
簡単な構文はdata-bind内に書けますよ、と
うーんこれはいいのか悪いのか‥
処理は極力ViewModel(javascript)に寄せたいと思ったり思わなかったり‥どうなんだろな

最後に

View(html)にちょっと記述を追加するだけで
座席数の合計を表示したり
座席の上限をしてしたりすることが可能だそうな

まずは合計

<h1>Your seat reservations</h1>

↓こんな感じに追記

<h1>Your seat reservations(<span data-bind="text: seats().length"></span>)</h1>

これだけで増減も自動で反映されまする
おおすごい

上限指定は一定数座席が埋まったらボタンを無効にすることで実現できるとか

<button data-bind="click: addSeat">Reserve another seat</button>

↓こんな感じに追記

<button data-bind="click: addSeat, enable: seats().length < 5">Reserve another seat</button>

enableバインディングは指定されたパラメーター値がtrueの場合のみ
関連付けられたDOM要素を有効にするもの
この場合 seats().length < 5 がtrueの場合はボタンが有効だけど
falseになるとその時点で無効化されるようになっていまする
inputとかselectとかtextareaとかのform要素に有用とのこと、ふむー

ということでまとめ

最終的にこんな感じになりました

<h1>Your seat reservations(<span data-bind="text: seats().length"></span>)</h1>

<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">Remove</a></td>
        </tr>    
    </tbody>
</table>

<button data-bind="click: addSeat, enable: seats().length < 5">Reserve another seat</button>

<p data-bind="visible: totalSurcharge() > 0">
    Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</p>
// Class to represent a row in the seat reservations grid
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";        
    });    
}

// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
    var self = this;

    // Non-editable catalog data - would come from the server
    self.availableMeals = [
        { mealName: "Standard (sandwich)", price: 0 },
        { mealName: "Premium (lobster)", price: 34.95 },
        { mealName: "Ultimate (whole zebra)", price: 290 }
    ];    

    // Editable data
    self.seats = ko.observableArray([
        new SeatReservation("Steve", self.availableMeals[0]),
        new SeatReservation("Bert", self.availableMeals[0])
    ]);

    // Computed data
    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;
    });    

    // Operations
    self.addSeat = function() {
        self.seats.push(new SeatReservation("", self.availableMeals[0]));
    }
    self.removeSeat = function(seat) { self.seats.remove(seat) }
}

ko.applyBindings(new ReservationsViewModel());

まとめてみたらなんかちょっとわかってきた気がする
気がするだけかもしれないけれど

互いに監視し合う関係とかその辺はなんとなくつかめてきました
ふむふむ

【KnouckoutJS】js初心者の私がKnouckoutJSをさわってみる、まとめ(になる予定)

なんかとりあえずKnouckoutJSを触らなければならないことになったので
ここにまとめながらごにょごにょしてみるよ

あ、ものすごくお久しぶりですw

KnouckoutJSとは

http://knockoutjs.com/

KnouckoutJSはMVVM(Model-View-ViewModel)パターンのフレームワークです
KnockoutJSを利用すると、ウェブページ上のインタラクションを簡単に記述できます
私みたいなのはMVVMパターンってなに?ってなるけど一旦無視することにしたのは内緒

KnouckoutJSができること

公式(http://knockoutjs.com/)からキーワードをとってきました

  • Declarative Bindings(宣言的バインディング)
  • Automatic UI Refresh(UIの自動更新)
  • Dependency Tracking(依存関係のトラッキング)
  • Templating(テンプレート)

なんかこんなこと云われてもよくわからんうえ英語全然読めないので
公式のチュートリアルを翻訳サイトとにらめっこしながらお勉強していくです
http://learn.knockoutjs.com/

ちょっとずつ、がんばるのである

KnouckoutJS奮闘記(リンク集になる予定)

  • Introduction(Getting started with MVVM and knockout.js)
  • リストの操作
    • Working with Lists and Collections(Building a dynamic UI where elements are added and removed)
  • Single page applications(Enabling navigation within the page, with back/forward support)
  • Creating custom bindings(Gaining more control over the UI, and integrating with third-party components)
  • Loading and saving data(Ways to integrate your client-side code with your server-side code)

【JavaScript】論理演算子のLL的利用法

【JavaScript】演算子②でも論理演算子やってるんだけれど
先生からさらに説明があったのでまとめる

JavaScriptっていうかプログラミング全般だと思うけれど
一旦JavaScriptカテゴリで

なにそれ今更じゃね?って感じの方がほとんどだと思うけど
はじめて知ったんだ恥ずかしい‥

論理積演算子&&、論理和演算子||をLL的に利用する

【JavaScript】演算子②では&&と||って‥

複数の条件式または論理値を
論理的に結合し、その結果を真偽で返す

  • &&(AND)
    • 左右の式がともにtrueの場合はtrue
    • 例>>100 == 100 && 1000 == 1000 //true
  • ||(OR)
    • 左右の式のどちらかがtrueの場合はtrue
    • 例>>100 == 100 || 1000 == 500 //true
  • !(NOT)
    • 式がfalseの場合はtrue
    • 例>>!(1000 == 500) //true

てな感じだったわけで
結合したものが真偽かってところに関しては
すごく利用したことがあったわけです私は

まあこんなの

var x = 1;
var y = 2;
console.log(x == 1 && y == 1);  //false
console.log(x == 1 || y == 1);  //true

それに対して今回作業中に出てきたのが

var a = 0;
var b = 1;
var c = 2;

x = a && b;
y = b && c; 

x;//  0
y;//  2

こんな感じのでした

なにそれどういうこと?ってなりました

で、先生の登場

今回説明していただいたのは
&&と||は最終的に真偽を判別した値を代入する
という特徴がある!!ということ

この例xの場合

  • a && bの左式であるaは0、要はfalseになる
  • 論理積演算子なので右式は評価されず、最終的にこのa && bはfalse
  • falseだと判別したのが左式だから左式の値である0がxに代入される

この例yの場合

  • b && cの左式であるbは1、要はtrueになる
  • 論理積演算子なので右式も評価される
  • 右式cは2、trueなので最終的にこのb && cはtrue
  • trueだと判別したのが右式だから右式の値である2がyに代入される

なるほどー
論理和演算子も同じく‥

var a = 0;
var b = 1;
var c = 2;

x = a || b;
y = b || c; 

x;  //1
y;  //1

この例xの場合

  • a || bの左式であるaは0、要はfalseになる
  • 論理和演算子なので右式も評価される
  • 右式bは1、tureなので最終的にこのa || bはture
  • tureだと判別したのが右式だから右式の値である1がxに代入される

この例yの場合

  • b || cの左式であるbは1、要はtureになる
  • 論理和演算子なので、この時点でb || cはtureになる
  • tureだと判別したのが左式だから左式の値である1がyに代入される

ふむふむ!
ifとか三項演算子のかわりに
つかったりできると‥勉強になります!

【ぼやき】最近参考にした記事まとめ

ちょっと自分用にめもめも

jsやったりSassやったりなんかいろいろやりました、ここ最近
5月中に技術書読破はできなかったけど
いろいろやらせていただけてよかったなー

いつかちゃんとまとめブログ書きたいな、と

【JavaScript】字句構造

やばいな、ひさびさすぎてはてな記法忘れているぞw

ということで再びお勉強→ここにまとめの流れでやっていくよ

JavaScript 第5版

サイ本、やります!

この一ヶ月で読破‥
逆算してみると結構既に焦らないとまずい状態なので
精いっぱい勉強していくことにするよ

ここにまとめるのは2章からにするある
1章は概要だったので

さて、がんばるぞー

字句構造とは

(・∀・)<そもそもじくこうぞうなんてはじめてききました!

プログラムの記述方法を規定する基礎的ルールの集まりのことを
プログラム言語の字句構造というそうな、ふむ‥

たとえば

  • 変数名の表記法
  • コメントに使用する文字
  • 複数のプログラム文の区切り方

などを規定するもの、なるほど文法とかそういう類の言葉ねはあく!

文字コード

JavaScriptプログラムはUnicode文字を使って記述する

大文字と小文字

JavaScriptでは大文字と小文字を区別する
これはもうおなじみです(・∀・)

キーワード、変数、関数名、識別子で大文字と小文字が厳密に区別される


【JavaScript】基本的な記法
「文(Statement)のルール」のとこでもやってますね

HTMLではタグや属性で小文字大文字が区別されないが
JavaScriptで記述するときは
イベントハンドラも含め、全て小文字表記で記述するべし(・∀・)べし!

セミコロン

JavaScriptの文は最後にセミコロン(;)を入れる
これももうおなじみです(・∀・)

同じく【JavaScript】基本的な記法
「文(Statement)のルール」のとこでもやってますね

コメント

これも本当におなじみです(・∀・)

【JavaScript】基本的な記法
「コメントを入れる」のとこでもやってますね

リテラル

JavaScriptでプログラムに直接記述するデータ値のことをリテラルと呼ぶ

もう一個の技術書では
>>データ型に格納できる値そのものをリテラルという<<
ってなってたなー

これは【JavaScript】データ型の記事
リテラル」ってとこで振りかえれまする

この技術書ではまたあとで細かい解説があるみたいなので
また後程













ていうかここまで来て思うけど想像以上に復習なため
ただのリンク集になる件‥うーんしばらくまとめ書かなくていいかも
ちょっと読む方に集中してみる

【ぼやき】どうやっても高度な関数のテーマ②がうまいことまとめられない件

たぶん理解しきってないから
消化不良のままでうまいこと書けないのだと思う

ということでサボっているわけではないのですよ
いやサボってるといえばサボっているけれども‥小声

ここだけの話、業務時間の8割を
ゲームして過ごしていたここ一ヶ月
死んだ方がいいのはわかっている、云わないで

ちょっといい加減に危機感を覚えないとまずい

このままじゃ査定下がる‥切実
ということでちょっと目標を立ててみた

  • 5月
    • 技術書2冊読破
    • なんとなくでもわかるようにする
  • 6月
    • すでに業務で書いたjQueryJavaScriptで書き直すとかやってみる
    • 既存のScriptをわからないなりに読んでみる
  • 7月
    • なんか自分で作ってみる
    • これ継続して毎月頑張るとかしないとだめだよなー‥知ってる
  • 8月
    • 簡単な作業は一人で十分!
  • 9月
    • 隣の席のYさんくらいになる(無謀)

結構無謀だけどこれくらいの必死さは必要だと思うの


以下5月に読もうと思ってる技術書

JavaScript本格入門 ~モダンスタイルによる基礎からAjax・jQueryまで
こっちはあと半分くらい読んでないので
最後までとりあえず読む
なんかこの章はやらなくてもいいよと言われている部分が
多々あるのだけれどとりあえずやるだけやる
無駄じゃないはず

JavaScript 第5版
こっちはおなじみオライリーですね、サイ本
なんかねJavaScript本格入門でやったけど曖昧、みたいなとことたくさんあるし
でももう一度JavaScript本格入門を頭から読むっていうのも結構しんどいし
ていうか読んでもぬるぬるになっちゃう自分がいて
なんとかしないとと思っていたのでちょうどいいかなと

ということでがんばります

早速ですがJavaScript本格入門は現在詰んでるので
今日からサイ本読んでみます

カフェいって集中してやるんだがんばるんだ

ということで宣言したので、やりまする

【ぼやき】なんかなんとなくいきています、あかん

だめだ、なんとなく生きているだけになってて
全然意識が変わってしまっている‥
あかーん!
ということでちょっと改めてブログを書きにきたよ

最近はSPページのコーディングやったり
jQueryつかってみたり
簡単なjs書いたりしてました、業務で
全然気づきや勉強したことをまとめてないからいけないんだね
そうだね、しってる

なんかねモバマスが全部悪い気がしている
狂わせている私の生活を
自覚はあるのでとりあえず会社に着いたら
iPhoneの電源を切ろうかーあーやだーきりたくないー←

ということでちょっとがんばります、ふたたび

もうすぐ今期の目標設定なので
それまでに半年後どうなっていたいかを
ちょっとでもイメージしておかないと‥ひー

とりあえずjQueryつかってあれこれやったのを
jQueryじゃなかったらどれだけ大変かとか
そういうのわかるようにしよう、うん

改めてテキスト読み直すところから、さーてやるぞー