2016-10-26 7 views
9

Mam formularz z polem wprowadzania dat. Daty powinny zostać zatwierdzone: dozwolone są tylko daty od dzisiaj + maksymalnie 3 lata. Jeśli data jest prawidłowa, pojawi się modal, w przeciwnym razie pojawi się alert z komunikatem o błędzie.onchange + sprawdzanie poprawności + wprowadź dziwne zachowanie

Zakładając somone zmienia datę na 26.10.2099:

Wszystko działa zgodnie z oczekiwaniami, jeśli ktoś opuści pole wejściowe (poprzez kliknięcie gdzieś indziej za pomocą myszki):

  • komunikat o błędzie pojawia
  • data zostanie automatycznie zmieniony z powrotem
  • modalne nie pokazuje

Ale jeśli ktoś naciska Enter zamiast po prostu pozostawiając pole wprowadzania dodaje się dzieje:

  • żaden komunikat o błędzie pokazuje
  • data zostanie automatycznie zmieniony z powrotem
  • modalne zjawia

Moja myśl jest to, że zmiana daty z powrotem na wartość początkową spowoduje, że zdarzenie onchange zostanie uruchomione ponownie, a następnie data jest ważna i modalny zostanie wyświetlony. Ale tak nie jest w przypadku pierwszego scenariusza. W drugim scenariuszu zdarzenie wyzwala dwa razy CZASAMI, ale nie zawsze.

można tryout się tutaj: https://jsfiddle.net/6x9n53fx/3/

Albo przeczytać poniższy kod:

HTML:

<div class="container"> 
    <form method="post" action="" enctype="multipart/form-data"> 
     <div class="row"> 
      <div class="col-sm-6"> 
       <div class="form-group"> 
        <label for="review_date">Valid until *</label> 
        <input id="review_date" type="text" name="review_date" value="26.10.2016" class="form-control"> 
        <p>Please set a validation date. (max 3 years)</p> 
       </div> 
      </div> 
     </div> 
    </form> 
</div> 
<!-- Modal --> 
<div class="modal fade" id="info_modal" tabindex="-1" role="dialog" aria-labelledby="modal_title"> 
    <div class="modal-dialog" role="document"> 
     <div class="modal-content"> 
      <div class="modal-header"> 
       <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> 
       <h4 class="modal-title" id="modal_title">Dialog</h4> 
      </div> 
      <div class="modal-body"> 
       <div class="form-group mbn"> 
        <p class="mb10">Date successfully changed.</p> 
       </div> 
      </div> 
      <div class="modal-footer"> 
       <button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button> 
      </div> 
     </div> 
    </div> 
</div> 

javascript:

var datumfeld = $("#review_date"); 
var initialdatum = datumfeld.val(); 
var i = 0; 
datumfeld.datepicker({ 
    minDate: 0, 
    maxDate: "3y", 
    dateFormat: 'dd.mm.yy' 
}); 
datumfeld.change(function() { 
i++; 
    console.log('onchange triggered: ' + i); 
    if (validateDatum()) { 
    $("#info_modal").modal({ 
     backdrop: "static", 
     keyboard: false 
    }); 
    } 
}); 

function validateDatum() { 
    var dateParts = datumfeld.val().split("."); 
    var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1)); 
    if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) { 
    alert("Error: The date must not exceed 3 years from now."); 
    datumfeld.val(initialdatum); 
    return false; 
    } 
    if ((review_date - (new Date)) < 0) { 
    alert("Error: The date must not be in the past."); 
    datumfeld.val(initialdatum); 
    return false; 
    } 
    return true; 
} 

EDIT:

Oto ostateczne rozwiązanie poszedłem z:

datumfeld.on('keydown', function(e) { 
    // when keydown is ENTER (13) 
    if (e.keyCode == 13) { 
     // Hide the datepicker 
     $(this).datepicker('hide'); 
     // Trigger a change event to trigger the validation 
     $(this).trigger('change'); 
    } 
    }) 
+0

skąd dzwoni validateDatum U R()? – user1844933

+0

datumfeld.change() jest tam, gdzie validateDatum() jest nazywane – Danmoreng

+0

Onchange będzie uruchamiany po opuszczeniu fokusu z niego, więc musisz również użyć onkeypress – user1844933

Odpowiedz

4

Problem z kodu jest po naciśnięciu Wpisz swoją wartość! = Po kliknięciu w innym miejscu. Można go zobaczyć podczas debugowania dateParts

Po wprowadzeniu przykład: 28.10.2099 i kliknąć dateParts jest [ "28", "10", "2099"] Ale kiedy wchodzi przykład: 28.10.2099 i naciśnij ENTER dateParts to ["28", "10", "2019"] Tutaj datepicker sprawdza poprawność pola wprowadzania i automatycznie ustawia datę na 28.10.2019, ponieważ ustawiłeś maxDate na 3y.

Tak więc, moim rozwiązaniem jest powiązanie keydown i ominięcie datepicker przed automatyczną zmianą wartości.

Oto link z kodem roboczym: https://jsfiddle.net/95qbs86x/2/

Aktualizacja: dodany kod

var datumfeld = $("#review_date"); 
var initialdatum = datumfeld.val(); 
var i = 0; 

// bind keydown event 
datumfeld.on('keydown', function(e) { 
    // when keydown is ENTER (13) 
    if (e.keyCode == 13) { 

    // trigger tab to hide datepicker 
    var e = $.Event("keydown"); 
    e.which = 9; //tab 
    e.keyCode = 9; 
    e.key = 'Tab'; 
    $(this).trigger(e); 

    return false; 
    } 
}).datepicker({ 
    minDate: 0, 
    maxDate: "3y", 
    dateFormat: 'dd.mm.yy', 
    onClose: function(){ 
    this.blur(); 
    } 
}).on('change', function(e) { 
    i++; 
    console.log('onchange triggered: ' + i); 
    if (validateDatum()) { 
    $("#info_modal").modal({ 
     backdrop: "static", 
     keyboard: false 
    }); 
    } 
}); 


function validateDatum() { 
    var dateParts = datumfeld.val().split("."); 
    console.log(dateParts); 
    var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1)); 

    if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) { 
    alert("Error: The date must not exceed 3 years from now."); 
    datumfeld.val(initialdatum); 
    return false; 
    } 
    if ((review_date - (new Date)) < 0) { 
    alert("Error: The date must not be in the past."); 
    datumfeld.val(initialdatum); 
    return false; 
    } 
    return true; 
} 

Wskazówka: Niektóre kod może być usunięcie jak: e.which = 9;e.key = 'Tab';return false;

jednak do stosując ten sam efekt co kliknięcie, należy dodać następujący wiersz kodu:

onClose: function(){ 
    this.blur(); 
} 

Niektóre kod został zabrany z tego answere: Disable enter key in JQuery ui datepicker

+0

Dziękuję za odpowiedź. Pomogło to całkiem sporo, chociaż nie chciałem tworzyć zdarzenia keypress, ale wbudowaną metodę ukrywania w datepicker. Również po prostu wywołuję zdarzenie zmiany zamiast duplikowania kodu walidacyjnego. Na to pytanie zredagowałem moje ostateczne rozwiązanie. – Danmoreng

0

Trzeba użyć preventDefault(), aby obsługiwać ten problem, demo podane poniżej pracy ...

  $(document).ready(function() { 
 
       var datumfeld = $("#review_date"); 
 
       var initialdatum = datumfeld.val(); 
 
       var i = 0; 
 
       datumfeld.datepicker({ 
 
        minDate: 0, 
 
        maxDate: "3y", 
 
        dateFormat: 'dd.mm.yy' 
 
       }); 
 
       datumfeld.change(function(e) { 
 
       i++; 
 
        console.log('onchange triggered: ' + i); 
 
        if (validateDatum()) { 
 
        e.preventDefault(); 
 
        $("#info_modal").modal({ 
 
         backdrop: "static", 
 
         keyboard: false 
 
        }); 
 
        } 
 
       }); 
 

 
       function validateDatum() { 
 
        var dateParts = datumfeld.val().split("."); 
 
        var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1)); 
 
        if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) { 
 
        alert("Error: The date must not exceed 3 years from now."); 
 
        datumfeld.val(initialdatum); 
 
        return false; 
 
        } 
 
        else if ((review_date - (new Date)) < 0) { 
 
        alert("Error: The date must not be in the past."); 
 
        datumfeld.val(initialdatum); 
 
        return false; 
 
        } else { 
 
        return true; 
 
        } 
 
       } 
 

 
       function handleSubmit() { 
 
        console.log("form submitted...."); 
 
        return false; 
 
       } 
 
      });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> 
 
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css"> 
 
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script> 
 
<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> 
 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> 
 
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css"> 
 
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script> 
 
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> 
 
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> 
 
<div class="container"> 
 
      <form method="post" action="" enctype="multipart/form-data" onsubmit="return handleSubmit();"> 
 
       <div class="row"> 
 
        <div class="col-sm-6"> 
 
         <div class="form-group"> 
 
          <label for="review_date">Valid until *</label> 
 
          <input id="review_date" type="text" name="review_date" value="26.10.2016" class="form-control"> 
 
          <p>Please set a validation date. (max 3 years)</p> 
 
         </div> 
 
        </div> 
 
       </div> 
 
      </form> 
 
     </div> 
 
     <!-- Modal --> 
 
     <div class="modal fade" id="info_modal" data-controls-modal="info_modal" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="modal_title" data-keyboard="false"> 
 
      <div class="modal-dialog" role="document"> 
 
       <div class="modal-content"> 
 
        <div class="modal-header"> 
 
         <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button> 
 
         <h4 class="modal-title" id="modal_title">Dialog</h4> 
 
        </div> 
 
        <div class="modal-body"> 
 
         <div class="form-group mbn"> 
 
          <p class="mb10">Date successfully changed.</p> 
 
         </div> 
 
        </div> 
 
        <div class="modal-footer"> 
 
         <button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button> 
 
        </div> 
 
       </div> 
 
      </div> 
 
     </div>

Wyjaśnienie:

Masz rację co do zmiany daty z powrotem na jej wartość początkową powoduje, że zdarzenie onchange zostanie uruchomione ponownie, w tym czasie musisz obsłużyć ten problem, więc aby obsłużyć go istnieje opcja preventDefault(), mam załączony przykład pracy które są potrzebne do tego celu i możesz je sprawdzić, klikając tutaj. Reference_1, Reference_2, Reference_3 ...

+1

Nie działa dla mnie. Kliknij w polu wprowadzania, ręcznie zmień rok na 2099, a następnie naciśnij Enter -> pojawi się modal. Zrób to samo bez naciskania Enter, ale zamiast tego kliknij gdzieś na zewnątrz -> Pojawia się komunikat o błędzie. (drugie zachowanie powinno nastąpić po naciśnięciu klawisza Enter) – Danmoreng

0

Datepicker wyzwala zmianę zdarzenia, gdy tylko naciśniesz "Enter" i zmieni datę z powrotem, gdy tylko data nie będzie pasować do samego Datepicker'a w minDate lub maxDate.

Tak więc zaktualizowałem program obsługi zdarzeń o keyup i zniszczę datepicker, gdy tylko wpiszesz coś za pomocą klawiatury (=> oznacza, że ​​nie chcesz wpisać daty za pomocą datepika) i zresetowałem natychmiast po naciśnięciu klawisza ENTER.

To jest ostatni kod JavaScript:

var datumfeld = $("#review_date"); 
    var initialdatum = datumfeld.val(); 
    var i = 0; 

    datumfeld.datepicker({ 
     minDate: 0, 
     maxDate: "3y", 
     dateFormat: 'dd.mm.yy' 
    }); 

    datumfeld.on('keyup change', function(e) { 
    e.preventDefault(); 
    if(e.key && e.key === "Enter") { 
     e.stopImmediatePropagation(); 
     datumfeld.datepicker({ 
     minDate: 0, 
     maxDate: "3y", 
     dateFormat: 'dd.mm.yy' 
     }); 
    } else if(e.key) { 
     datumfeld.datepicker("destroy"); 
    } 
    if(!e.key || e.key === "Enter") { 
     i++; 
     console.log('onchange triggered: ' + i); 
     if (validateDatum()) { 
     $("#info_modal").modal({ 
      backdrop: "static", 
      keyboard: false 
     }); 
     } 
    } 
    }); 

    function validateDatum() { 
     var dateParts = datumfeld.val().split("."); 
     var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1)); 
     if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) { 
     alert("Error: The date must not exceed 3 years from now."); 
     datumfeld.val(initialdatum); 
     return false; 
     } 
     if ((review_date - (new Date)) < 0) { 
     alert("Error: The date must not be in the past."); 
     datumfeld.val(initialdatum); 
     return false; 
     } 
     return true; 
    } 

Jakoś .datepicker("destroy") nie działa na JSFiddle, ale na pewno istnieje: http://api.jqueryui.com/datepicker/#method-destroy

e.stopImmediatePropagation(); pomógł także gdy tylko sprawdzanie dla ENTER keyup, jednak działa to tylko co drugi raz. Czasami keyup jest szybszy, czasami jest datepicker. Dlatego właśnie chciałem zniszczyć datepicker.

0

jeśli zmiana zdarzenie jest opalane dynamicznie dostaniesz nieruchomość originalEvent w przypadku można użyć

if(typeof e.originalEvent!='undefined') return; 

zamiast preventDefault chociaż oba sposoby są takie same skrzypce tutaj https://jsfiddle.net/6x9n53fx/4/