LoginSignup
2
4

More than 5 years have passed since last update.

knockoutのscope(context)

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

knockoutにも、scope(context)の概念があります。
scopeが切り替わるタイミングは、foreachbindなどのイテレータでの子scopeや、withbindでの明示的なscope切換えを行った場合です。

例えば、このサンプルを見てみましょう。
Country(国)とState(州/県)とCity(市・区)はそれぞれ親子関係にあります。

index.html
<div data-bind="foreach:countries">
    <div class="country">
        <span>{{name}}</span>
        {{#foreach: states}}
        <div class="state">
            <span>{{name}}</span>
            {{#foreach: cities}}
            <div class="city">
                <span>{{name}}</span>は、{{$parents[1].name}}の{{$parents[0].name}}にあります
            </div>
            {{/foreach}}
        </div>
        {{/foreach}}
    </div>
</div>

<div data-bind="foreach:list">は、divの内側を繰り返し、
{{#foreach:list}} {{/foreach}}もまた、このタグの内側を繰り返します。
これは、<!-- ko foreach:list--><!-- /ko -->の構文糖衣です。
VirtualElementと呼ばれるもので、余計なタグのネストを避けるために利用しています。

(コメントを用いる方法を使ってもいいのですが、すこし長いですし、最適化ツールなどでコメントが消された場合に、不都合が生じるので注意が必要です。)

サンプルを眺めてみると、なんとなくわかる通り、

div.countryの内側が指す name は国名ですし、
div.stateの内側側す name は 県・州名です。
div.cityでは name は市・区名となっています。

子scopeから親scopeを参照するには、 $parentsを使います。
$parents[0]$parent は等価です。
cityのscopeからみて、
 \$parents[0]はstateのscopeで、
 \$parents[1]はcountryのscope
となっています。

script.js
function Country(name){
    this.states=[];
    this.name = name;
    ko.track(this);
}
function State(name){
    this.cities=[];
    this.name = name;
    ko.track(this);
}
function City(name){
    this.name = name;
    ko.track(this);
}

function VM(){
    var countries = this.countries = [];
    var src = [
        {
            name:'jp',
            state:[
                {name:'東京',city:[{name:'千代田'},{name:''},{name:' 渋谷'}]},
                {name:'大阪',city:[{name:'大阪'},{name:''},{name:'松原'}]},
                {name:'宮城',city:[{name:'仙台'},{name:'角田'},{name:'名取'}]}
            ]
        },
        {
            name:'us',
            state:[
                {name:'Texas',city:[{name:'SanAntonio'},{name:'Austin'},{name:' Huston'}]},
                {name:'NewYork',city:[{name:'Rochester'},{name:'Buffalo'}]}
            ]
        }
    ];
    // mapping to model
    src.forEach(function(c){
        var country = new Country(c.name);
        c.state.forEach(function(s){
            var state = new State(s.name);
            s.city.forEach(function(ci){
                state.cities.push(new City(ci.name));
            });
            country.states.push(state)
        });
        countries.push(country);
    });
    ko.track(this);
}
var vm = new VM();

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

scopeのcontextには、
$parent$parents[]$data そして、イテレータのscopeでは$indexを持っています。
 それぞれ、
  $parentは、自分の親scope、
  $parentsは、自分の先祖scope、
  $dataは、自分自身のscope、
  $indexは、親から見た自分のindex
 となります。

$dataの使い道は、例えば data-bind="foreach:['A','B','C']"など、propertyを有さないprimitiveな値をまわす際などに使ったりします。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4