2013-05-23 2 views
4

온 전성 검사를 찾으십시오. 나는 최근에 녹아웃을 배우기 시작했으며 기존의 다단계 형식을 변환하도록 지시 받았다.유효성 검사가 포함 된 녹아웃 -JS 다단계

기본 아이디어는 사용자가 계속 진행하기 전에 각 단계의 유효성을 검사하는 것입니다. 또한 앞으로 계속할 것인지 또는 모든 현재 데이터 (예 : 자격이없는 경우)를 사용하여 제출할 것인지 결정하는 특정 제한이 설정됩니다 (표시되지 않음).

<form id="register"> 
<fieldset> 
     <h2>About You</h2> 
    <ul> 
     <li> 
      <label for="firstName">First Name:</label> 
      <input type="text" data-bind="value: firstName" required="required" /> 
     </li> 
     <li> 
      <label for="lastName">Last Name</label> 
      <input type="text" data-bind="value: lastName" required="required" /> 
     </li> 
    </ul> 
</fieldset> 
<fieldset> 
    <h2>Your Business</h2> 

    <ul> 
     <li> 
      <label for="businessName">Business Name:</label> 
      <input type="text" data-bind="value: businessName" required="required" /> 
     </li> 
     <li> 
      <label for="currentCustomer">Were you referred by someone?</label> 
      <input type="checkbox" data-bind="checked: referred" /> 
     </li> 
    </ul> 
</fieldset> 
<fieldset> 
    <h2>User Info</h2> 

    <ul> 
     <li> 
      <label for="userName">Referrer's First Name:</label> 
      <input type="text" data-bind="value: referralFirst" required="required" /> 
     </li> 
     <li> 
      <label for="password">Referrer's Last Name:</label> 
      <input type="password" data-bind="value: referralLast" required="required" /> 
     </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> 

JS :

$("#register").children().hide().first().show(); 

ko.validation.init({ 
    parseInputAttributes: true, 
    decorateElement: true, 
    writeInputAttributes: true, 
    errorElementClass: "error" 
}); 

function myViewModel() { 

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

//validaiton observable init 
self.step1 = ko.validatedObservable({ 
    firstName: self.firstName, 
    lastName: self.lastName 
}); 

self.step2 = ko.validatedObservable({ 
    businessName: self.businessName, 
    referred: self.referred 
}); 

self.step3 = ko.validatedObservable({ 
    referralFirst: self.referralFirst, 
    referralLast: self.referralLast 
}); 

//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){ 
    var validationObservable = "step" + self.currentStep(); 
    if(self[validationObservable]().isValid()){ 
     self.currentStep(destIdx); 
     $("#register").children().hide().eq(self.currentStep() - 1).show(); 
     return true; 
    }else{ 
     self[validationObservable]().errors.showAllMessages(); 
    } 
    return false; 
} 

self.resetAll = function(){ 
    //TODO 
    return false; 
} 

} 

ko.applyBindings(new myViewModel()); 
여기

단순화 된 버전 바이올린 인

http://jsfiddle.net/dyngomite/BZcNg/

HTML (실제 형태는도 4 단계에 걸쳐 40 필드를 포함)

내 질문 :

  1. 모든 필드를 처음 관찰 가능으로 선언 한 다음 validatedObservables()에 함께 클러스터링하는 것이 합리적입니까?

  2. 마지막으로 전체 양식을 제출하려는 경우 ko.toJSON (self.step1())을 사용하여 각 단계를 연결하는 것보다 더 똑똑한 방법이 있습니까? 모든 입력 관측 값을 포함하는 "완전한 형식"관측 가능을 만들어야합니까? 즉, 전체 양식을 직렬화하는 가장 좋은 방법은 무엇입니까? ko.toJSON (self)를 사용하고 싶습니까?

  3. 양식을 초기 구성으로 재설정하는 가장 좋은 방법은 무엇입니까? ko.applyBindings (new myViewModel())을 다시 적용 할 수 있습니까?

이 문제는 올바르게 적용됩니까?

설명해 주셔서 감사합니다.

답변

5

좋은 시작입니다. 노크 아웃을 사용하여 가시성을 관리하고 다른 옵션이 없을 때만 jQuery를 사용하는 것이 좋습니다.

<fieldset data-bind="visible: currentStep() === 1"> 
  1. 예, 그것은 처음에 관찰 가능한 모든 필드를 가지고 이해가 않습니다 그하여 나는 필드 셋의 관리 가시성을 의미한다. 좋은 전략은 데이터를 서버에서 JSON으로 가져와 매핑 플러그인을 사용하여 모든 것을 관측 가능으로 변환하는 것입니다. 손으로 모든 것을 코딩하고 싶다면 괜찮습니다.

  2. 결국 전체보기 모델을 제출하십시오. ko.toJSON (self)이 JSON에 직렬화하는 작업을 수행합니다. 이를 JS 객체 (ko.toJS)로 변환 한 다음 제출하지 않으려는 데이터 (예 : 데이터 조회 등)를 정리 한 다음 JSON.stringify를 사용하여 JSON으로 변환 할 수 있습니다.

  3. 유효성 검사 플러그인을 사용하여 유효성 검사 상태를 재설정하기가 어렵습니다. 양식을 재설정하려면 기존 양식을 DOM에서 제거하고 applyBindings를 새 HTML에서 제거하십시오.페이지에 편리한 곳에 HTML을 유지 :

양식을 재설정하려면 다음을 수행하십시오

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

양식 태그는이 경우에 필요하지 않습니다, 당신은 모든 것을 관리하기 때문에 JS 객체를 사용합니다.

+0

감사합니다. currentStep()에 대한 가시성을 바인딩하는 것이 더 깨끗한 접근법임을 알 수 있습니다. 1. 모든 기본 기능을 재 작성한 후 매핑 플러그인을 통합 할 계획입니다. 2. ko.toJS()를 사용하고 전달되는 필드를 제한해야한다는 것이 맞다고 생각합니다. 3. 흥미 롭지 만 KO 템플릿을 사용해야합니까? 이 경우 div # 컨텍스트 내부뿐만 아니라 스크립트 태그 내부에 양식 마크 업을 갖습니다. 템플릿을 피하고 문서의 전역 변수에 HTML 형식으로 저장 한 다음 나머지 절차를 수행하는 것은 좋지 않은 아이디어입니까? – lyma

0

Carl Schroedl의 ValidatedViewModel을 살펴보십시오.

우수 Knockout Validation plugin과 함께 사용하면 유효성 제한 조건 그룹을 만들고 필요에 따라 적용 할 수 있습니다.

유효성 검사 루틴을 실행할 때마다 모든 제약 조건 그룹을 제거한 다음 해당 단계에 대해 원하는 제약 조건 그룹을 적용합니다. 또는 관찰 가능한 단계에 가입하여 제약 그룹을 설정하십시오.

는 (적용 할 때 나는 그것이 제약 그룹이 이미 적용/제거 된 경우 오류가 발생하지으로 제약 그룹을 제거/시도/catch 문을 사용하는 것이 좋습니다.)

이 부착 된 학습 곡선의 비트가 그러나 그것은 각 단계마다 적절한 검증을 통해 바구니/체크 아웃 페이지를 만드는 데 정말로 도움이되었습니다.

업데이트 : Here is an updated jsfiddle using ValidatedViewModel. currentStep에 따라 보이는 단계를 관찰 가능하게 만들고 필요한 태그를 제거했습니다. 이제 모든 유효성 검사가 모델에서 처리됩니다. 보너스로 jsfiddle의 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()); 

html로 지금은 다음과 같습니다

<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> 
+0

흥미로운 접근 방법이지만 validatedObservable에 개별 단계를 클러스터링하고 validateViewModel을 사용하여 isValid() 메서드를 호출하는 것의 이점을 실제로 볼 수는 없습니다. 최종 결과는 try/catch를 사용할 필요없이 동일하게 보입니다. – lyma

+0

또한 parseInputAttributes = true로 설정하고 사용 가능한 경우 기본 브라우저 동작을 활용하기 위해 유효성 검사 제약 조건을 인라인으로 유지하지만 이는 개인적인 취향입니다. – lyma

+0

이 접근법은 모두 확장성에 관한 것입니다. 모델이 작고 검증 요구 사항이 상대적으로 기본이라면 초기 접근 방식이 잘 작동합니다. 비밀번호/비밀번호 입력란과 같은 다른 유효성 검사 옵션이 필요할 때 어떻게되는지 생각해보십시오. 속성을 파싱하는 것을 어떻게 구현할 것인가? 암호 필드는 최소 8 자 이상이어야하며 암호와 확인 암호는 일치해야합니다.또한 적절한 유효성 검증 메시지를 표시하려고합니다. 제약 그룹의 경우보기 편하고 깔끔하고 분리되어 있지만 제약없이 매우 까다로워집니다. – 79IT

관련 문제