Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@MKGaru

knockoutでのList(配列)処理

この記事は、knockout.js Advent Calendar 2015の3日目の記事です。 先に2日目に目を通すことを推奨しています。
knockout , knockout-es5 , knockout.punches環境を想定しています。

knockoutでview部分でイテレータを用いるには、foreachを利用します。
このサンプルでは、FruitShopを例に、Shopで取り扱うフルーツ(Item)の名前と価格を一覧表示しています。

this.items = [
    new Item("apple",60),
    new Item("banana",25),
    new Item("cinnamon",80),
    new Item("dragonfruit",120)
];

の部分を、

this.items = [
    {name:"apple",price:60},
    {name:"banana",price:25},
    {name:"cinnamon",price:80},
    {name:"dragonfruit",price:120}
];

と書き換えても問題はありません

先ほどのサンプルでは、bindingの恩恵が少ないので、ShopへのItemの動的追加のサンプルを見てみましょう。

index.html
<h1>Fruit Shop</h1>
<ul data-bind="foreach:items">
    <li>
        <span>{{name}}</span>
        <span>({{price}})</span>
    </li>
</ul>
<form data-bind="submit: register"> 
    <fieldset>
        <legend>商品登録:</legend>
        <label>商品名:<input type="text" id="item-name-input"></label>
        <label>価格:<input type="text" id="item-price-input"></label>
        <button>登録</button>
    </fieldset>
</form>
script.js
function Item(name,price){
    this.name = name;
    this.price = price;
    ko.track(this);
}
function Shop(){
    this.items = [
        new Item("apple",60),
        new Item("banana",25),
        new Item("cinnamon",80),
        new Item("dragonfruit",120)
    ];
    ko.track(this);
}
Shop.prototype.register = function(){
    this.items.push(
        new Item(
            document.querySelector("#item-name-input").value,
            +document.querySelector("#item-price-input").value
        )
    );
};

var vm = new Shop();

ko.punches.enableAll();
ko.applyBindings(vm);

document.querySelector("#foo").value

の部分は、

document.getElementById("foo").value

でももちろんOKですし、
jQueryを使うのであれば、

$("#foo").val()

でも何でもいいです。

イテレータの要素番号を取得する場合には、$indexを利用します。
もっとも、このサンプルではolを使えばいいだけではあるのですが。

また、$indexは0から始まる番号ですが、1から始めたい場合は、

このように {{ $index() + 1 }}とします。

view部分で{{ }} でくくられた中身は ko.observale()のgetterを展開してくれますが、 ko.observable()はあくまで関数なので、
関数になんらかのものを結合すると、関数が文字列になってしまうので、このようにする必要があります。
knockout-es5で適用した部分は、object.defineされているのですが、 生のknockoutではko.observableで実装されているのがもどかしくもありますが、しょうがないですね。

また、蛇足ですが先ほどのサンプルをTypescriptで書くと次のようになります。

class Item{
    constructor(
        public name:string,
        public price:number
    ){
        ko.track(this);
    }
}
class Shop{
    public items:Item[] = [
        new Item("apple",60),
        new Item("banana",25),
        new Item("cinnamon",80),
        new Item("dragonfruit",120)
    ];
    constructor(){
        ko.track(this);
    }
    public register(){
        this.items.push(
            new Item(
                document.querySelector("#item-name-input").value,
                +document.querySelector("#item-price-input").value
            )
        );
    }
}

var vm = new Shop();

ko.punches.enableAll();
ko.applyBindings(vm);

配列への値の追加・削除は次のように行います。 これらはバニラのjavascriptと同じです。

  • list.push(value) listという配列の末尾に、valueを追加
  • list.splice(index,length) listという配列の、index番目から、length個の要素を削除

listを空にしたいからといって、listに空配列を上書きをすることは非推奨です(ko-es5でtrackしているのであれば禁止ではありません)。 list = []

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?