我希望实现Angular,Knockout或其他数据绑定向导式应用程序形式概念验证(无服务器端代码)。但是,当我克隆数据绑定div时,我似乎打破了数据绑定。
申请表的前几个步骤捕获数据,而后面的步骤将数据呈现给用户,以允许他们确认输入的内容。我在按下'next'时插入适当的步骤操作DOM,并在按下'previous'时取出最后一步。我是使用detatch
,clone
和remove
执行此操作的。
任何人都可以就他们为实现这项工作所采取的方法提供建议,以及我应该考虑哪些框架?
下面是伪代码,以了解结构。伪数据绑定代码就是我认为它可以工作的方式,我没有任何框架。
HTML查看
<div id="wizard">
<div id="step1">Enter your name: <input type="text" id="name" /></div>
</div>
<div id="actions"><input type="button" value="Previous" /><input type="button" value="Next" onClick="goNext();" /></div>
<div id="steps">
<div id="stepA">Enter your age: <input type="text" id="age" databind="theAge" /></div>
<div id="stepB">The age you entered - {{ theAge }} is too young!</div>
<div id="stepC">Enter your favourite colour: <input type="text" id="faveColour" databind="faveCol" /></div>
<div id="stepD">Hi {{ name }}. You are {{ age }} years old and your favourite colour is {{ faveCol }}</div>
</div>
的JavaScript
<script>
function goNext() {
// figure out which step is next
insertStepIntoWizard(step, index, title);
}
function insertStepIntoWizard(step, index, title) {
var element = step.detach();
wizard.steps('insert', index, {
title: title,
content: element.clone()
});
console.log('insertStepIntoWizard - just inserted ' + step.attr('id') + ' into wizard position ' + index);
}
</script>
答案 0 :(得分:0)
大多数前沿的javascript框架试图做的是尝试管理当前应用程序中的大量代码,其中在客户端使用javascript实现大量业务逻辑。因此,他们主要尝试为您提供一些architecture
来组织您的代码,以便于管理,阅读和扩展。
在你的情况下,你试图忽略他们提供的MVC
或MVWhatever
这样的架构,并使用框架来做一些模板,如果我理解正确的话。为此,您可以在handlebars
等javascript中更好地获取某些模板引擎的帮助,并使用它来手动呈现存储在当前javascript应用中的数据。
答案 1 :(得分:0)
只需重新初始化您的绑定。 这解决了我在使用淘汰赛时遇到的问题。
当您更改实际为MVVM引用的主DOM元素时,结果是该元素的任何更改或重新构造都会妨碍dom关系。 最终,虽然项目的位置看起来相同,但技术上,在java脚本引擎中它不是。所以问题就出现了。
为了修复这样的问题,只需要一个构造函数来初始化或重新初始化DOM中特定元素的映射。
希望能解决你的问题。
示例:
function ReInitializeVM()
{
ko.cleanNode(document.getElementById("userDetails"));
ko.applyBindings(viewModel, document.getElementById("userDetails"));
}
只要您觉得需要重新初始化绑定,就可以调用该函数。调用该函数将删除id为“userDetails”的元素上的任何绑定,然后可以调用applyBindings来初始化绑定。这将调用任何新/更改元素的绑定。
答案 2 :(得分:0)
我认为您正在考虑让view
反映您的实体model
,这基本上是模板化的。如果您希望使用Knockout / Angular,除了控制实体外,还应考虑使用它view model
来管理页面状态/流/动作。 (编写jQuery代码来讨论DOM和克隆,显示/隐藏等等并不好玩)。 @sabithpocker提出了类似的观点。
工作示例:我熟悉Knockout,并创建了一个示例jsFiddle:http://jsfiddle.net/overflew/BfRq8/5/
注意:
template
标记来容纳向导的每个部分,所有步骤都指向viewmodel中的同一个模型/实体。查看模型
<div>
<h3 data-bind="text: currentStep().name"></h3>
<div data-bind="template: { name: 'wizard-step1' }, visible: currentStep().id === 0"></div>
<div data-bind="template: { name: 'wizard-step2' }, visible: currentStep().id === 1"></div>
<div data-bind="template: { name: 'wizard-step3' }, visible: currentStep().id === 2"></div>
<input type="button" value="Next step" data-bind="click: onNext, visible: hasNextSteps" />
<input type="button" value="Submit" data-bind="click: onSubmit,visible: !hasNextSteps()" />
<div data-bind="visible: submitResultMessage, text: submitResultMessage"></div>
</div>
<div>
<h3>Your inputs</h3>
<div data-bind="visible: questions.fullName">Full name: <span data-bind="text: questions.fullName"></span></div>
<div data-bind="visible: questions.age">Age: <span data-bind="text: questions.age"></span>
</div>
<div data-bind="visible: questions.favouriteColour">Favourite colour: <span data-bind="text: questions.favouriteColour"></span>
</div>
</div>
<script type="text/html" id="wizard-step1">
<div>
First name: <input data-bind="value: questions.firstName, valueUpdate:'afterkeydown'" />
</div>
<div>
Last name: <input data-bind="value: questions.lastName, valueUpdate:'afterkeydown'" />
</div>
</script>
<script type="text/html" id="wizard-step2">
<div>
Age: <input data-bind="value: questions.age, valueUpdate:'afterkeydown'" />
</div>
</script>
<script type="text/html" id="wizard-step3">
<div>
Favourite colour: <input data-bind="value: questions.favouriteColour, valueUpdate:'afterkeydown'" />
</div>
</script>
查看强>
// Entity for holding form data.
var FormData = function() {
var self = this;
self.firstName = ko.observable("");
self.lastName = ko.observable("");
self.age = ko.observable("");
self.favouriteColour = ko.observable("");
self.fullName = ko.computed(function() {
if (!self.firstName() && !self.lastName()) {
return "";
}
return self.firstName() + " " + self.lastName();
});
}
// Quick handling for managing steps of the wizard
var wizardSteps = [
{ id: 0, name: "Wizard step 1"},
{ id: 1, name: "More questions"},
{ id: 2, name: "Last step"}
];
var ViewModel = function() {
var self = this;
// Properties
self.questions = new FormData();
self.currentStep = ko.observable(wizardSteps[0]);
self.submitResultMessage = ko.observable();
// Actions
self.onNext = function() {
var currentIndex = self.currentStep().id;
if (self.hasNextSteps()) {
// Move forward one step on the wizard
self.currentStep(wizardSteps[currentIndex + 1]);
}
};
self.onSubmit = function() {
self.submitResultMessage("Data is now submitted ");
};
// Page control
self.hasNextSteps = ko.computed(function() {
var currentIndex = self.currentStep().id;
return currentIndex < wizardSteps.length - 1;
});
};
ko.applyBindings(new ViewModel());