一个母版页上具有相同视图/模型的多个实例 - 元素ID?

时间:2014-05-26 15:55:21

标签: knockout.js durandal

我有一个小而简单的视图&显示某些数字和图表的viewmodel。我被要求提供一个“并排”的视图,其中最多可以并排显示6个实例。

有点天真,看起来,我只是在我看来这样做了:

<div class="container acd">
    <div class="row">
        <div class="col-md-2">
        <div data-bind="compose: { model: acd1}"></div>
        </div>
        <div class="col-md-2">
        <div data-bind="compose: { model: acd2 }"></div>
        </div>
        <div class="col-md-2">
        <div data-bind="compose: { model: acd3 }"></div>
        </div>
        <div class="col-md-2">
        <div data-bind="compose: { model: acd4 }"></div>
        </div>
        <div class="col-md-2">
        <div data-bind="compose: { model: acd5 }"></div>
        </div>
        <div class="col-md-2">
        <div data-bind="compose: { model: acd6 }"></div>
        </div>
    </div>
 </div>

,这在viewmodel中:

var acd1 = new acd({ header: 'Article 1'});
var acd2 = new acd({ header: 'Article 2'});
var acd3 = new acd({ header: 'Article 3'});
var acd4 = new acd({ header: 'Article 4'});
var acd5 = new acd({ header: 'Article 5'});
var acd6 = new acd({ header: 'Article 6'});

...其中“acd”是我的viewmodel中的“required”引用链接到独立视图&amp;视图模型。

这似乎首先起作用,我在页面上并排有6个实例,上面设置了不同的标题。

然而,当我开始实际触发一些加载事件,其中一个部分是数据绑定到一个控制它是否可见的observable时,似乎没有足够的实例分离,因为在第一个实例中更改了一个下拉列表实际上揭示了第6节中的部分!

当我通过chrome dev工具检查页面上的元素时,所有的div ID是相同的,所以我想我在这里尝试实现的是一个根本问题?我认为通过在母版页中创建“新”实例,它将创建自我感知的独立实例,以便在传递参数/更新时,他们会知道引用自己的ID实例,但它看起来不会。

有人有任何指示试着帮助我吗?

主页面viewmodel:

define(['services/datacontext', 'viewmodels/articleComparisonDetail'], function (datacontext, acd) {

    var acd1 = new acd({ header: 'Article 1'});
    var acd2 = new acd({ header: 'Article 2'});
    var acd3 = new acd({ header: 'Article 3'});
    var acd4 = new acd({ header: 'Article 4'});
    var acd5 = new acd({ header: 'Article 5'});
    var acd6 = new acd({ header: 'Article 6'});

    var acdMaster = {
        acd1: acd1,
        acd2: acd2,
        acd3: acd3,
        acd4: acd4,
        acd5: acd5,
        acd6: acd6
    };

    return acdMaster;

});

为了添加更多信息,我在“var acdMaster = ...”行上设置了一个调试停止点,此时,acd1-6似乎是独立的独立视图模型,其“header”属性设置为我使用的6个单独的值。不知何故,虽然各个细节视图中的输入框似乎与特定实例没有关联。

acd“detail”视图(简化):

      <div id="acdWrapper">
        <section id="acd">
            <div class="acdArticleCode" data-bind="text: header"></div>
                <div class="formGrid">
                    <input autocomplete="off"  data-bind="typeahead: { name: 'sectionNames', highlight: true, source: articleList}, value: artCode""/>
                </div>

                <!-- ko if: articleLoaded() == true -->
                <div id="articleSelected" data-bind="visible: articleLoaded()">
                    <div class="formGrid resultsTable">
                        <div class="formRow">
                            <div class="formCell">
                                <label>Article Weight:</label>
                            </div>
                            <div class="formCell text-right">
                                <span data-bind="numericText: loadedArticle().totalArticleWeight, precision: 2"></span>
                            </div>
                        </div>


                 ...


         </div>
        <!-- /ko -->
         <div id="articleNotSelected" data-bind="visible: !articleLoaded()">

            <p>Type a minimum of 2 characters into text box to see list of articles</p>

        </div>
 </section>

...和viewmodel(也简化)

define(['plugins/dialog', 'knockout', 'config', 'services/datacontext'], function (dialog, ko, config, datacontext) {

    var acdvm = function (params) {
        var self = this;
        self.content = ko.observable();
        self.header = ko.observable(params.header);
        self.loadedArticle = ko.observable(); //contains entity object for display
        self.articleLoaded = ko.observable(false); //is article loaded true/false
        self.articleList = ko.observableArray([]); //holds list of matching articles from search
        self.selectedRow = ko.observable('e1');
        self.chartID = ko.computed(function () {
            var str = self.header() + "_chart";
            return str.replace(" ","");
        }, this, { deferEvaluation: true });

        self.displayPrecision = ko.observable(6);
        self.artCode = ko.observable('');

    };

    return acdvm;
});

编辑2 所以我进一步调查了。我补充说:

function externalActivate(fakeself) {
    if (fakeself.header() == "Article 2") { fakeself.blah("I blow") };
}

var acdvm = function (args) {
    var self = this;
    self.blah = ko.observable('blah');

    self.activate = function () {
        externalActivate(self);
        if(self.header()=="Article 5") {self.blah("Really Sucks")};
    };

... rest unchanged
}

return acdvm;

并改变视图以在我实例化的6个视图中的每个视图上显示blah。 在我的主视图模型中,我添加了:

    acd3.blah("sucks");

到模块的“激活”方法,所有这些都完全符合预期。

在屏幕上的6栏中,我得到了“等等”,“我吹”,“糟透了”,“等等”,“真的很糟糕”,“等等”,这就是我所需要的。然而,如果我使用第一列/ viewmodel上的输入字段来选择某些内容,那么只要viewmodel加载数据并更改了observable,触发该视图中的html“填入”然后它就出现在第6列中,不是第一个!

这太疯狂......我真的不知道这是怎么回事。

2 个答案:

答案 0 :(得分:0)

更多信息而不是答案。

根据Composition文档,如果您将模块ID传递给撰写绑定,它将&#34;找到模块,找到它的视图,绑定它们并将它们注入到DOM中。 #34; 。传递对象实例时,它将&#34;找到它的视图,绑定它并将它们注入到DOM中。&#34; 。也许这里有微妙的区别?我对Durandal的内部结构并不太熟悉。

另一个想法是,不是绑定到主视图模型的属性,而是可以尝试这样做:

<div class="container acd">
    <div class="row">
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article1' }"></div>
        </div>
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article2' }"></div>
        </div>
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article3' }"></div>
        </div>
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article4' }"></div>
        </div>
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article5' }"></div>
        </div>
        <div class="col-md-2">
            <div data-bind="compose: 'viewmodels/articleComparisonDetail', activationData: { header: 'Article6' }"></div>
        </div>
    </div>
 </div>

请记住,您必须将articleComparisonDetail视图模型重构为:

 var vm = {
    var self = this;

    self.header = ko.observable();

    self.activate = function (data) {
        self.header(data.header); // or whatever
    }

    // rest of code...
 }

 return vm;

答案 1 :(得分:0)

事实证明,除了......之外,我所做的一切都很好。

我嵌入在&#34;详细信息中的自定义绑定处理程序&#34; viewmodel(我没有在上面的代码中包含这个,因为我认为它不相关 - 我有多么错误。)

我所做的一切就是首先将绑定处理程序移到viewmodel之外,然后我在bindinghandler初始化(这是viewmodel)上添加了第4个参数,以便它知道vm的哪个实例已经调用它。

在我打电话来填充可观察量并显示图表的绑定处理程序中,我刚刚提到了&#34; vm&#34; param我现在包括在初始化而不是&#34; self.whatever&#34;和宾果游戏,一切都再次变得很好。

所以我似乎正确地设置了我的观点/模型(正如我在测试中所怀疑的那样)并且它只是一个不正确的&#34;自我&#34;在作为罪魁祸首的自定义绑定处理程序中。

感谢输入的破解,很有用。