Composing separate module instances in Durandal

对着背影说爱祢 提交于 2019-12-11 10:04:16

问题


I am composing the same form multiple times in the same module view but when I change the data in one field it reflects on every forms.

Here is some cleaned up code. As you can see I made sure not to use the singleton pattern for the form I want to compose multiple times...

view.html

<button data-bind="click: append">Append</button>

<div data-bind="foreach: odbcForms">
    <div data-bind="compose: { model: $data, activationData: settings }"></div>
</div>

viewmodel.js

define(['knockout', 'forms/odbc'], function ( ko, odbcForm) {
    var odbcForms = ko.observableArray()

    var append = function () {
        odbcForms.push(new odbcForm({ hostname: 'v1', db: 'v2' }));
    };

    return {
        odbcForms: odbcForms,
        append: append
    }
}

forms/odbc.html

<div>
    <form class="form-horizontal" role="form">
        <fieldset>
            <div class="form-group" data-bind="validationElement: hostname">
                <label for="hostname" class="col-sm-2 control-label">ODBC Link Name</label>

                <div class="col-xs-4">
                    <input data-bind="value: hostname" type="text" class="form-control" id="hostname">
                </div>
            </div>

            <div class="form-group" data-bind="validationElement: db">
                <label for="db" class="col-sm-2 control-label">Database</label>

                <div class="col-xs-4">
                    <input data-bind="value: db" type="text" class="form-control" id="db">
                </div>
            </div>
        </fieldset>
    </form>
</div>

forms/odbc.js

define(['knockout'], function(ko) {
    var ctor = function (settings) {
        this.settings = settings;
    };

    ctor.prototype = {
        constructor: ctor,

        activate: function (settings) {
            this.hostname(this.settings.hostname);
            this.db(this.settings.db);
        },

        hostname: ko.observable().extend({
            required: true,
            minLength: 2
        }),

        db: ko.observable().extend({
            required: true,
            minLength: 2
        }),
    };

    return ctor;
}

Thank you in advance


回答1:


Change your forms/odbc.js to the following:

define(['knockout'], function(ko) {
    var ctor = function () {
        this.settings = settings;
        this.hostname = ko.observable().extend({
            required: true,
            minLength: 2
        };
        this.db = ko.observable().extend({
            required: true,
            minLength: 2
        });
    };        

    ctor.prototype.activate = function (settings) {
        this.hostname(this.settings.hostname);
        this.db(this.settings.db);
    };

    return ctor;
});

It might be that Durandal is confused by your approach. Among other issues in your forms/odbc module, there should be no argument on the constructor (ctor function). Also, it is not a good idea to place observables on a prototype--you'll leak memory. If you really wish to establish hostname and db as some sort of global, create a separate config module, make it a singleton, and then inject it using RequireJS, like so:

define('config', ['knockout'], function(ko) {
    var 
        hostname = ko.observable(),
        db = ko.observable();

    return {
        hostname: hostname,
        db: db
    }
});

Then change your odbc.js to the following:

define(['knockout', 'config'], function(ko, config) {
    var ctor = function (settings) {
        this.settings = null;     
        this.config = null;
    };        

    ctor.prototype.activate = function (settings) {
        this.settings = settings;
        this.config = config;
        config.hostname(settings.hostname);
        config.db(settings.db);
    };

    return ctor;
});

Your view would need to be updated slightly: Instead of value: hostname, for example, you would need to change to value: config.hostname.

With this approach, you can build out your config module as your application grows without having to refactor every module. Also, you do know that you don't have to call it ctor, right? In order to facilitate debugging, give your module an explicit name, say OdbcForm, so that you would have:

var OdbcForm = function()
...
return OdbcForm;

It will show up in the debugger as OdbcForm instead of ctor.




回答2:


Prototypes are shared. You should not put property values on the prototype. property values should go on instances. Put only functions. All properties (observables) should go on the "this" object instance.



来源:https://stackoverflow.com/questions/23388743/composing-separate-module-instances-in-durandal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!