问题
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