web-dev-qa-db-ja.com

ノックアウトはバインディング「foreach」を処理できません

私はKnockoutを初めて使用し、効果的に大規模な計算機となるアプリを作成しています。これまでのところ、1つのページで2つのノックアウトインスタンスが実行されています。 1つのインスタンスは完全に正常に機能していますが、もう1つのインスタンスは完全に壊れており、まったく登録されていないように見えますか?

以下は私のJavascriptです。fetchYearは完全に正常に機能する関数であり、fetchPopulationは完全に壊れている関数です。 HTMLから「ageview」を登録していないようで、わかりません。

エラー:

Uncaught ReferenceError:バインディングを処理できません "foreach:function(){return ageView}"メッセージ:ageViewが定義されていません

前もって感謝します。

JS:

var index = {

    fetchYear: function () {
        Item = function(year){
            var self = this;
            self.year = ko.observable(year || '');
            self.chosenYear = ko.observable('');
            self.horizon = ko.computed(function(){
                if(self.chosenYear() == '' || self.chosenYear().horizon == undefined)
                    return [];
                return self.chosenYear().horizon;
            });
        };
        YearViewModel = function(yeardata) {
            var self = this;
            self.yearSelect = yeardata;
            self.yearView = ko.observableArray([ new Item() ]);
            self.add = function(){
                self.yearView.Push(new Item("New"));
            }; 
        };
        ko.applyBindings(new YearViewModel(yearData));
    },

    fetchPopulation: function () {
        popItem = function(age){
            var self = this;
            self.age = ko.observable(age || '');
            self.chosenAge = ko.observable('');
            self.population = ko.computed(function(){
                if(self.chosenAge() == '' || self.chosenAge().population == undefined)
                    return [];
                return self.chosenAge().population;
            });
        };
        PopulationViewModel = function(populationdata) {
            var self = this;
            self.ageSelect = populationdata;
            self.ageView = ko.observableArray([ new popItem() ]);
            self.add = function(){
                self.ageView.Push(new popItem("New"));
            }; 
        };
        ko.applyBindings(new PopulationViewModel(populationData));
    }

}

index.fetchYear();
index.fetchPopulation();

HTML:

<div class="row" data-bind="foreach: yearView">
    <div class="grid_6">
        <img src="assets/img/index/calendar.png" width="120" height="120" />
        <select class="s-year input-setting" data-bind="options: $parent.yearSelect, optionsText: 'year', value: chosenYear"></select>
        <label for="s-year">Start year for the model analysis</label>
    </div>
    <div class="grid_6">
        <img src="assets/img/index/clock.png" width="120" height="120" />
        <select class="s-horizon input-setting" data-bind="options: horizon, value: horizon"></select>
        <label for="s-horizon">Analysis time horizon</label>
    </div>
</div>

<div class="row" data-bind="foreach: ageView">
    <div class="grid_6">
        <img src="assets/img/index/calendar.png" width="120" height="120" />
        <select class="s-year input-setting" data-bind="options: ageSelect, optionsText: 'age', value: chosenAge"></select>
        <label for="s-agegroup">Age group of <br> target population</label>
    </div>
    <div class="grid_6">
        <img src="assets/img/index/clock.png" width="120" height="120" />
        <input class="s-population input-setting"></input>
        <label for="s-population">Size of your patient <br> population <strong>National</strong> </label>
    </div>
</div>
8
leaksterrr

これを行うと(fetchYearで):

ko.applyBindings(new YearViewModel(yearData));

ページ全体をYearViewModelビューモデルでバインドしています。ただし、YearViewModelにはageViewというプロパティがないため、エラーが発生し、ノックアウトは他のものをバインドしようとしなくなります。

あなたがする必要があるのは、あなたが望む要素を渡すことによって、domの一部だけをカバーするようにバインディングを制限することですko.applyBindings。例えば:

<div class="row" id="yearVM" data-bind="foreach: yearView">
//....
<div class="row" id="popVM" data-bind="foreach: ageView">

その後:

ko.applyBindings(new YearViewModel(yearData), document.getElementById("yearVM"));
//...
ko.applyBindings(new PopulationViewModel(populationData), document.getElementById("popVM"));

これで、バインディングは、そのモデルからのものを実際に表示するDOMの部分だけに制限されます。

もう1つの方法は、2つのビューモデルを親ビューモデルの一部として持つだけで、ページ全体にバインディングを適用できます。これにより、両方のVMのパーツを混在させる必要があり、ページの個別のセクションに分割されていない場合に簡単になります。何かのようなもの:

var myParentVM = {
    yearVM : index.fetchYear(),          // note, make this return the VM instead of binding it
    popVM : index.fetchPopulation(),     // ditto
}

ko.applyBindings(myParentVM);

そして、次のようにバインディングを宣言します。

<div class="row" data-bind="foreach: yearVM.yearView">
17
Matt Burland

これが機能しない主な理由は、1ページでko.applyBindings()を複数回呼び出すためです(これは実際には禁止されていませんが、私の意見では悪い習慣です)。

2回呼び出す必要がある場合は、このバインドの対象となるリージョンのコンテナーを使用して呼び出す必要があります。

このようなもの:

ko.applyBindings(new YearViewModel(yearData), document.getElementById('YourYearViewElementId'));

発生するエラーは、ページ全体を処理しようとし、ViewModelで「ageView」が見つからない最初のバインディングからのものです。

必要に応じてセクションのサブモデルがある単一のページに対して単一のViewModelを構築するとよいでしょう。

このようなシナリオのいくつかの擬似コード:

var Section1ViewModel = function() {
    var self = this;

    self.property1 = ko.observable();
    self.myComputed = ko.computed(function () {
        // do some fancy stuff
    });
    self.myFunc = function() {
        // do some more fancy stuff
    };
}

var Section2ViewModel = function() {
    var self = this;

    self.property1 = ko.observable();
    self.myComputed = ko.computed(function () {
        // do some fancy stuff
    });
    self.myFunc = function() {
        // do some more fancy stuff
    };
}

var PageViewModel = function() {
    var self = this;

    self.section1 = ko.observable(new Section1ViewModel());
    self.section2 = ko.observable(new Section2ViewModel());

    self.myGlobalFunc = function() {
        // do some even more fancy stuff
    }
}

ko.applyBindings(new PageViewModel());

お役に立てば幸いです。

よろしく、クリス

2
Chris