Knockout.js 带验证的淘汰JS多步骤表单

Knockout.js 带验证的淘汰JS多步骤表单,knockout.js,knockout-2.0,knockout-validation,Knockout.js,Knockout 2.0,Knockout Validation,在这里寻找一个精神检查。我最近开始学习knockout,并被指示转换现有的多步骤表单 基本思想是在允许用户继续之前验证每个步骤。还设置了某些限制(未显示),以确定是继续前进还是使用所有当前数据提交(例如:如果不符合条件) 这里是一个简化版本的提琴(实际表单包含4个步骤中的大约40个字段) HTML: 关于你 名字: 姓 你的生意 企业名称: 有人介绍过你吗? 用户信息 推荐人的名字: 推荐人的姓氏: JS: $(“#寄存器”).children().hi

在这里寻找一个精神检查。我最近开始学习knockout,并被指示转换现有的多步骤表单

基本思想是在允许用户继续之前验证每个步骤。还设置了某些限制(未显示),以确定是继续前进还是使用所有当前数据提交(例如:如果不符合条件)

这里是一个简化版本的提琴(实际表单包含4个步骤中的大约40个字段)

HTML:


关于你
  • 名字:
你的生意
  • 企业名称:
  • 有人介绍过你吗?
用户信息
  • 推荐人的名字:
  • 推荐人的姓氏:
JS:

$(“#寄存器”).children().hide().first().show();
ko.validation.init({
ParseInputAttribute:true,
装饰元素:是的,
WriteInputAttribute:true,
errorElementClass:“错误”
});
函数myViewModel(){
var self=这个;
//可观测初始
self.firstName=ko.observable();
self.lastName=ko.observable();
self.businessName=ko.observable();
自参考=可观察();
self.referralFirst=ko.observable();
self.referralLast=ko.observable();
//validaiton可观测初始
self.step1=ko.validatedObservable({
名字:self.firstName,
lastName:self.lastName
});
self.step2=ko.validatedObservable({
businessName:self.businessName,
转介:自我转介
});
self.step3=ko.validatedObservable({
referralFirst:self.referralFirst,
referralLast:self.referralLast
});
//导航初始化
self.currentStep=ko.可观察(1);
self.stepfroward=函数(){
if(self.currentStep()1){
self.changeSection(self.currentStep()-1);
}
}
self.changeesection=函数(destIdx){
var validationObservable=“步骤”+self.currentStep();
if(self[validationObservable]().isValid()){
自电流阶跃(destIdx);
$(“#寄存器”).children().hide().eq(self.currentStep()-1.show();
返回true;
}否则{
self[validationObservable]()。errors.showAllMessages();
}
返回false;
}
self.resetAll=函数(){
//待办事项
返回false;
}
}
应用绑定(新的myViewModel());
我的问题是:

  • 最初将所有字段声明为可观察字段,然后将它们聚集到validatedObservables()中有意义吗

  • 如果最后我想提交整个表单,有没有比使用ko.toJSON(self.step1())连接每个步骤更聪明的方法呢。我是否需要创建一个包含所有输入可观察项的“完整形式”可观察项?换句话说,序列化完整表单的最佳方式是什么? 我想使用ko.toJSON(self)吗

  • 将表单重置为初始配置的最佳方法是什么?有没有重新应用ko.applyBindings(新的myViewModel())的方法

  • 我这样做对吗


    感谢您的澄清。

    这是一个好的开始。我建议您使用knockout管理可见性,只有在没有其他选项时才使用jQuery。我的意思是管理字段集的可见性:

    <fieldset data-bind="visible: currentStep() === 1">
    
    在这种情况下,表单标签是不必要的,因为您可以使用JS对象管理所有内容。

    看看Carl Schroedl的文章

    与“优秀”结合使用时,您可以创建验证约束组,并根据需要应用它们

    ko.validation.init({
        parseInputAttributes: false,
        decorateElement: true,
        insertMessages: true,
        messagesOnModified: true,
        grouping: { deep: true, observable: true }
    });
    
    var myViewModel = ValidatedViewModel(function () {
        var self = this;
    
        //observable init
        self.firstName = ko.observable();
        self.lastName = ko.observable();
        self.businessName = ko.observable();
        self.referred = ko.observable();
        self.referralFirst = ko.observable();
        self.referralLast = ko.observable();
    
        //navigation init
        self.currentStep = ko.observable(1);
    
        self.stepForward = function () {
            if(self.currentStep()<4){
                self.changeSection(self.currentStep() + 1);
            }
        }
    
        self.stepBack = function () {
            if (self.currentStep() > 1) {
                self.changeSection(self.currentStep() - 1);
            }
        }
    
        self.changeSection = function(destIdx){
            //remove all constraint groups
            try { self.removeConstraintGroup('step1'); } catch (e) { }
            try { self.removeConstraintGroup('step2'); } catch (e) { }
            try { self.removeConstraintGroup('step3'); } catch (e) { }
    
            //apply constraint group for current step
            try{self.applyConstraintGroup('step' + self.currentStep());} catch(e){}
    
            var errorCount = self.errors().length;
    
            self.errors.showAllMessages();
            if(errorCount===0){
                self.currentStep(destIdx);
                return true;
            }
            return false;
        }
    
    
        self.constraintGroups = {
            step1: {
                firstName: { required: true },
                lastName: { required: true }
            },
            step2: {
                businessName: { required: true }
            },
            step3: {
                referralFirst: { required: true },
                referralLast: { required: true }
            }
    
        }
    
        self.resetAll = function(){
            //TODO
            return false;
        }
    
        this.errors = ko.validation.group(this);
    
    });
    
    ko.applyBindings(new myViewModel());
    
    在每次运行验证例程时,您将删除所有约束组,然后为给定步骤应用所需的约束组。或者订阅可观察的步骤以设置约束组

    (我建议在应用/删除约束组时使用try/catch语句,因为如果约束组已应用/删除,则会出错。)

    这是一个学习曲线,但它确实帮助我创建了一个篮子/结帐页面,每个步骤都有适当的验证

    更新: . 我使可视步骤依赖于currentStep observable,并删除了所需的标记。所有验证现在都在模型中处理。作为奖励,JSFIDLE中的CSS还为验证消息设置样式,而不需要额外的标记

    ko.validation.init({
        parseInputAttributes: false,
        decorateElement: true,
        insertMessages: true,
        messagesOnModified: true,
        grouping: { deep: true, observable: true }
    });
    
    var myViewModel = ValidatedViewModel(function () {
        var self = this;
    
        //observable init
        self.firstName = ko.observable();
        self.lastName = ko.observable();
        self.businessName = ko.observable();
        self.referred = ko.observable();
        self.referralFirst = ko.observable();
        self.referralLast = ko.observable();
    
        //navigation init
        self.currentStep = ko.observable(1);
    
        self.stepForward = function () {
            if(self.currentStep()<4){
                self.changeSection(self.currentStep() + 1);
            }
        }
    
        self.stepBack = function () {
            if (self.currentStep() > 1) {
                self.changeSection(self.currentStep() - 1);
            }
        }
    
        self.changeSection = function(destIdx){
            //remove all constraint groups
            try { self.removeConstraintGroup('step1'); } catch (e) { }
            try { self.removeConstraintGroup('step2'); } catch (e) { }
            try { self.removeConstraintGroup('step3'); } catch (e) { }
    
            //apply constraint group for current step
            try{self.applyConstraintGroup('step' + self.currentStep());} catch(e){}
    
            var errorCount = self.errors().length;
    
            self.errors.showAllMessages();
            if(errorCount===0){
                self.currentStep(destIdx);
                return true;
            }
            return false;
        }
    
    
        self.constraintGroups = {
            step1: {
                firstName: { required: true },
                lastName: { required: true }
            },
            step2: {
                businessName: { required: true }
            },
            step3: {
                referralFirst: { required: true },
                referralLast: { required: true }
            }
    
        }
    
        self.resetAll = function(){
            //TODO
            return false;
        }
    
        this.errors = ko.validation.group(this);
    
    });
    
    ko.applyBindings(new myViewModel());
    
    ko.validation.init({
    ParseInputAttribute:false,
    装饰元素:是的,
    insertMessages:true,
    messages:true,
    分组:{deep:true,observeable:true}
    });
    var myViewModel=ValidatedViewModel(函数(){
    var self=这个;
    //可观测初始
    self.firstName=ko.observable();
    self.lastName=ko.observable();
    self.businessName=ko.observable();
    自参考=可观察();
    self.referralFirst=ko.observable();
    self.referralLast=ko.observable();
    //导航初始化
    self.currentStep=ko.可观察(1);
    self.stepfroward=函数(){
    if(self.currentStep()1){
    self.changeSection(self.currentStep()-1);
    }
    }
    self.changeesection=函数(destIdx){
    //删除所有约束组
    尝试{self.removeConstraintGroup('step1');}catch(e){}
    尝试{self.removeConstraintGroup('step2');}catch(e){}
    尝试{self.removeConstraintGroup('step3');}catch(e){}
    //为当前步骤应用约束组
    尝试{self.applyConstraintGroup('step'+self.currentStep());}catch(e){}
    var errorCount=self.errors().length;
    self.errors.showAllMessages();
    如果(errorCount==0){
    自电流阶跃(destIdx);
    返回true;
    }
    
    <script type="text/html" id="ko-template">
       <form id="register"> 
       ...
       </form>
    </script>
    
    <div id="context"></div>
    
    var template = $('#ko-template').html();
    
    $('#context').empty().html(template);
    
    ko.applyBindings(new myViewModel(), document.getElementById('context'));
    
    ko.validation.init({
        parseInputAttributes: false,
        decorateElement: true,
        insertMessages: true,
        messagesOnModified: true,
        grouping: { deep: true, observable: true }
    });
    
    var myViewModel = ValidatedViewModel(function () {
        var self = this;
    
        //observable init
        self.firstName = ko.observable();
        self.lastName = ko.observable();
        self.businessName = ko.observable();
        self.referred = ko.observable();
        self.referralFirst = ko.observable();
        self.referralLast = ko.observable();
    
        //navigation init
        self.currentStep = ko.observable(1);
    
        self.stepForward = function () {
            if(self.currentStep()<4){
                self.changeSection(self.currentStep() + 1);
            }
        }
    
        self.stepBack = function () {
            if (self.currentStep() > 1) {
                self.changeSection(self.currentStep() - 1);
            }
        }
    
        self.changeSection = function(destIdx){
            //remove all constraint groups
            try { self.removeConstraintGroup('step1'); } catch (e) { }
            try { self.removeConstraintGroup('step2'); } catch (e) { }
            try { self.removeConstraintGroup('step3'); } catch (e) { }
    
            //apply constraint group for current step
            try{self.applyConstraintGroup('step' + self.currentStep());} catch(e){}
    
            var errorCount = self.errors().length;
    
            self.errors.showAllMessages();
            if(errorCount===0){
                self.currentStep(destIdx);
                return true;
            }
            return false;
        }
    
    
        self.constraintGroups = {
            step1: {
                firstName: { required: true },
                lastName: { required: true }
            },
            step2: {
                businessName: { required: true }
            },
            step3: {
                referralFirst: { required: true },
                referralLast: { required: true }
            }
    
        }
    
        self.resetAll = function(){
            //TODO
            return false;
        }
    
        this.errors = ko.validation.group(this);
    
    });
    
    ko.applyBindings(new myViewModel());
    
    <form id="register">
        <h1>Current Step: <span data-bind="text:currentStep()"></span></h1>
        <fieldset data-bind="visible: currentStep()===1">
             <h2>About You</h2>
    
            <ul>
                <li>
                    <label for="firstName">First Name:</label>
                    <input type="text" data-bind="value: firstName"  />
                </li>
                <li>
                    <label for="lastName">Last Name</label>
                    <input type="text" data-bind="value: lastName"  />
                </li>
            </ul>
        </fieldset>
        <fieldset data-bind="visible:currentStep()===2">
             <h2>Your Business</h2>
    
            <ul>
                <li>
                    <label for="businessName">Business Name:</label>
                    <input type="text" data-bind="value: businessName"  />
                </li>
                <li>
                    <label for="currentCustomer">Were you referred by someone?</label>
                    <input type="checkbox" data-bind="checked: referred" />
                </li>
            </ul>
        </fieldset>
        <fieldset data-bind="visible:currentStep()===3">
             <h2>User Info</h2>
    
            <ul>
                <li>
                    <label for="userName">Referrer's First Name:</label>
                    <input type="text" data-bind="value: referralFirst"  />
                </li>
                <li>
                    <label for="password">Referrer's Last Name:</label>
                    <input type="password" data-bind="value: referralLast"  />
                </li>
            </ul>
        </fieldset>
    </form>
    <div class="nav-buttons"> <a href="#" data-bind='click: stepForward'>Continue</a>
     <a href="#" data-bind='click: stepBack'>Back</a>
     <a href="#" data-bind='click: resetAll'>Cancel</a>
    
    </div>