我使用knockout js与Bootstrap一起在页面上显示模态窗口。我还有以下扩展来从标记中获取值,以便我的observable可以从剃刀中填充:
ko.bindingHandlers.initializeValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
valueAccessor()(element.getAttribute('value'));
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (element.nodeName == 'SPAN')
element.innerHTML = value;
element.setAttribute('value', value);
}
};
这非常有用,可以在第一次使用razor加载页面时填充挖空视图模型。当我从模态内部更新值时,将调用更新,并更新observable以及所有这些。问题是我关闭模态窗口,然后重新打开它。它在bindingHandler上再次调用init并重置了原始值属性中的值,尽管我将属性设置为更新函数底部的新值。
所以我的问题是:为什么在重新打开模态时再次调用初始化?我知道当模态隐藏时,标记会从DOM中删除,但是模态可观察的值是否仍然在内存中?
以下是我的整个页面的视图模型,以及弹出窗口的视图模型:
var userEditViewModel = function () {
var self = this;
self.template = 'editUserTemplate';
self.hasChanges = ko.observable(false);
self.isCanceling = ko.observable(false);
self.FirstName = ko.observable();
self.LastName = ko.observable();
self.EmailAddress = ko.observable();
self.onYes = function() {
self.modal.close();
self.isCanceling(false);
self.hasChanges(false);
};
self.onNo = function () {
self.isCanceling(false);
};
self.onSave = function () {
if (self.errors().length == 0) {
var options =
{
FirstName: self.FirstName(),
LastName: self.LastName(),
Email: self.EmailAddress()
};
repo.SaveProfile(options, function (result) {
self.modal.close(result.result);
});
} else {
self.errors.showAllMessages();
}
};
self.onCancel = function () {
if (self.hasChanges() == false) {
this.modal.close();
} else {
self.isCanceling(true);
}
};
self.errors = ko.validation.group(self);
}
}
var profileViewModel = (function () {
var self = this;
self.FirstName = ko.observable();
self.LastName = ko.observable();
self.EmailAddress = ko.observable();
self.EditUserModel = new userEditViewModel();
self.EditUser = function () {
bhn.ShowModal({
viewModel: self.EditUserModel,
context: this
})
.done(function (result) {
})
.fail(function () {
})
.then(self._updateProfile);
}
self._updateProfile = (function (result) {
self.FirstName(result.firstName);
self.LastName(result.lastName);
self.EmailAddress(result.email);
});
});
模态代码:
function createModal(templateName, viewModel) {
var temporaryDiv = addHiddenDivToBody();
var deferredElement = $.Deferred();
ko.renderTemplate(
templateName,
viewModel,
{
afterRender: function (nodes) {
var elements = nodes.filter(function (node) {
return node.nodeType === 1;
});
deferredElement.resolve(elements[0]);
}
},
temporaryDiv,
"replaceNode"
);
return deferredElement;
}
function showModal(options) {
if (typeof options === "undefined" || options === null) throw new Error("An options argument is required.");
if (typeof options.viewModel !== "object") throw new Error("options.viewModel is required.");
var viewModel = options.viewModel;
var template = options.template || viewModel.template;
var context = options.context;
if (!template) throw new Error("options.template or options.viewModel.template is required.");
return createModal(template, viewModel)
.pipe($)
.pipe(function ($ui) {
var deferredModalResult = $.Deferred();
addModalHelperToViewModel(viewModel, deferredModalResult, context);
showTwitterBootstrapModal($ui);
whenModalResultCompleteThenHideUi(deferredModalResult, $ui);
whenUiHiddenThenRemoveUi($ui);
return deferredModalResult;
});
}
function addHiddenDivToBody() {
var div = document.createElement("div");
div.style.display = "none";
document.body.appendChild(div);
return div;
};
function addModalHelperToViewModel(viewModel, deferredModalResult, context) {
viewModel.modal = {
close: function (result) {
if (typeof result !== "undefined") {
deferredModalResult.resolveWith(context, [result]);
} else {
deferredModalResult.rejectWith(context, []);
}
}
};
};
function showTwitterBootstrapModal($ui) {
// Display the modal UI using Twitter Bootstrap's modal plug-in.
$ui.modal({
backdrop: "static",
keyboard: false
});
};
function whenModalResultCompleteThenHideUi(deferredModalResult, $ui) {
deferredModalResult.always(function () {
$ui.modal("hide");
});
};
function whenUiHiddenThenRemoveUi($ui) {
$ui.on("hidden", function () {
//$ui.each(function (index, element) { ko.cleanNode(element); });
//$ui.remove();
});
};