操纵DOM的数据绑定不适用于Angular,Knockout

时间:2014-03-04 06:40:18

标签: javascript jquery angularjs knockout.js

我希望实现Angular,Knockout或其他数据绑定向导式应用程序形式概念验证(无服务器端代码)。但是,当我克隆数据绑定div时,我似乎打破了数据绑定。

申请表的前几个步骤捕获数据,而后面的步骤将数据呈现给用户,以允许他们确认输入的内容。我在按下'next'时插入适当的步骤操作DOM,并在按下'previous'时取出最后一步。我是使用detatchcloneremove执行此操作的。

任何人都可以就他们为实现这项工作所采取的方法提供建议,以及我应该考虑哪些框架?

下面是伪代码,以了解结构。伪数据绑定代码就是我认为它可以工作的方式,我没有任何框架。

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>

3 个答案:

答案 0 :(得分:0)

大多数前沿的javascript框架试图做的是尝试管理当前应用程序中的大量代码,其中在客户端使用javascript实现大量业务逻辑。因此,他们主要尝试为您提供一些architecture来组织您的代码,以便于管理,阅读和扩展。

在你的情况下,你试图忽略他们提供的MVCMVWhatever这样的架构,并使用框架来做一些模板,如果我理解正确的话。为此,您可以在handlebars等javascript中更好地获取某些模板引擎的帮助,并使用它来手动呈现存储在当前javascript应用中的数据。

在此处查看http://handlebarsjs.com/

答案 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中的同一个模型/实体。
  • 要强调绑定的发布/订阅性质正在发生的事情:
    • 用户输入也会在页面底部中继。
    • 表单标题是动态的,以及“步骤”
    • ko.computed用于'计算'全名,如果还有任何“步骤”,
  • 特定于Knockout:注意在该位置周围突然出现括号。如果您选择学习Knockout,这可能偶尔会让您感到困惑。它只是意味着您正在评估绑定容器以获取值。

查看模型

<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());