2011-08-13 15 views
34

OK, o to chodzi, widziałem kilka wpisów na temat SO związanych z tym problemem, ale nic nie działa dla mnie.MVC3 Dyskretna walidacja nie działa po wywołaniu Ajaxa

Zasadniczo, wybrałem rozwijane listy rozwijane, które są ładowane z widoków częściowych, próbuję filtrować zawartość każdego kolejnego rozwijania w oparciu o wcześniej wybrane rozwijane menu.

Jeśli właśnie wprowadziłem wywołanie do widoku częściowego w kontenerach div i załaduję stronę, sprawdzanie poprawności z adnotacji danych działa poprawnie, przede wszystkim Wymagany atrybut.

Jednakże, jeśli próbuję załadować to samo częściowe poprzez AJAX, jak to jest tutaj ustawione, Wymagana weryfikacja nie działa, każdy może opublikować formularz po tym i KABOOM.

Znalazłem ludzi mówiących, że w oddzwanianiu powodzenia musisz mieć narzędzie do sprawdzania poprawności formularza po stronie klienta i próbuję tego, ale nie działa.

Mam widoku, który wygląda tak ...

@model Area51.Models.Workflow.AddReportableItemToBatchActionModel 
@{ 
    ViewBag.Title = "Add Reportable Item to Batch"; 
    Layout = "~/Views/Shared/_Layout.cshtml"; 
} 

<script type="text/javascript"> 

    $(function() { 
     var fadeDelay = 150; 

     $(".jqDatePicker").datepicker({ 
      dateFormat: 'm/d/yy', 
      onSelect: function (date) { 
       $("#categoryContainer").show(fadeDelay); 
      } 
     }); 

     $('#Category').change(function() { 
      RetrieveItemsForCategory(); 
      $("#itemContainer").show(100); 
     }); 

     $('#Item').live('change', function() { 
      RenderPartialForUOMByItem();   
     }); 



     function RetrieveItemsForCategory() { 

      var category = $("#Category :selected").val(); 

      $.ajax({ 
       type: "POST", 

       url: '@Url.Action("RenderPartialForLocationItemsByCategory","BatchWorkflow")', 

       data: 'category=' + category, 

       success: function (result) { 
        $("#itemContainer").html(result.toString()); 
        $("#itemContainer").show(100); 
        RebindValidation(); 
       }, 

       error: function (req, status, error) { 
        alert("Sorry! Could not request items for your selection at this time."); 
       } 

      }); 


     } 


     function RenderPartialForUOMByItem() { 

      var item = $("#Item :selected").val(); 

      $.ajax({ 
       type: "POST", 

       url: '@Url.Action("RenderPartialForUOMByItem","BatchWorkflow")', 

       data: "item=" + item, 

       success: function (result) { 
        $("#quantityContainer").html(result.toString()); 
        $("#quantityContainer").show(100); 
        RebindValidation(); 
       }, 

       error: function (req, status, error) { 
        alert("Sorry! Could not request items for your selection at this time."); 
       } 

      }); 
     } 

     function RebindValidation() { 
      alert("Rebinding Validation"); 
      $.validator.unobtrusive.parse("#frmAddItem"); 
     } 

    });  // End OnLoad Event 
</script> 

<h3 class="pageHeader">Batch : @Model.BatchName</h3> 

<div align="center"> 

@{Html.BeginForm("AddItemToBatch", "BatchWorkflow", null, FormMethod.Post, new { id = "frmAddItem" });} 

    @Html.ValidationSummary(true) 

    <fieldset style="width:60%"> 
     <legend>Add an Item to the Batch</legend>  

    <div>  
      <h3>Select Date Item was Added</h3> 
      @Html.EditorFor(x => x.EventDate,null) 
      <br /> 
     </div> 

     <div id="categoryContainer" style="display:none"> 
     <hr /> 
      <h3>Select an Inventory Category</h3> 
      @Html.EditorFor(x => x.Category,null) 
      <br /> 
     </div> 

     <div id="itemContainer" style="display:none"> 
     @* @{Html.RenderAction("RenderPartialForLocationItemsByCategory", "BatchWorkflow", new { category = Model.Category });}*@ 
     </div> 


     <div id="quantityContainer" style="display:none"> 
     @* @{Html.RenderAction("RenderPartialForUOMByItem", "BatchWorkflow", new { item = Model.Item });}*@ 
     </div> 

     <div id="reportingDataContainer" style="display:none"> 
     <hr /> 
      <h3>What quantity of the batch was affected by this addition?</h3> 
      @Html.EditorFor(x => x.ConsumedWineQuantity) (Gallons) 
     <br /> 
     <hr /> 
      <h3>What was the increase in Batch Volume as a result of this addition?</h3> 
      @Html.EditorFor(x => x.ProducedWineQuantity) (Gallons) 
     </div> 

     <div style="display:block"> 
     <div></div>   
      <span><button type="button" id="btnCancel" class="linkButton" value="Cancel" onclick="location.href='@Url.Action("Home","Home",null)';">Cancel</button></span> 
      <span><button type="submit" id="btnSubmit" class="linkButton" value="Add">Add Item</button></span> 
     </div> 


    </fieldset> 
     @{ Html.EndForm(); } 
</div> 

częściowego widoki są bardzo proste, w zasadzie wyglądają tak ...

@model Area51.Models.Workflow.AddReportableItemToBatchActionModel 

     <hr /> 
      <h3>Select the Item to Add</h3> 
      @Html.EditorFor(x => x.Item) 
      <br /> 

Ponownie, jeśli tylko renderPartial sprawdzanie poprawności działa dobrze, jednak gdy próbuję to zrobić za pomocą ajax, walidacja znika. Alert "Rebinding Validation" zostanie uruchomiony, ale $ .validator.unobtrusive.parse ("# frmAddItem"); chyba nic nie robi.

Czy ktoś może pomóc w tym, czego mi brakuje? Byłoby to bardzo docenione.

< ======================= AKTUALIZACJA 1 ==================== =========>

OK, próbowałem dodać $ .validator.unobtrusive.parse ("# frmAddItem"); w dolnej części częściowego widoku w przypadku zdarzenia gotowego do druku i też nie działało, zasadniczo nic się nie zmieniło, wciąż mógłbym przesłać formularz.

Znalazłem post tutaj: http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/, który wspomniał, że gdy wersja jqwaldztwa MVC widzi formularz już związany z regułami sprawdzania powiązanymi z nim, to po prostu ignoruje wywołanie .validator. Zaimplementowałem rozszerzenie skryptu, którego ten dżentelmen używał, a sprawdzanie poprawności odwołuje się teraz do formularza przy użyciu nowego rozszerzenia. Mogę to przetestować poprzez dołączenie html do formularza i wywołanie nowego rozszerzenia i ponowne przypisanie do nowego pola tekstowego.

Jednak nadal nie rozwiązało to całkowicie problemu. Użyłem Firebug do sprawdzenia rzeczywistej zawartości pól powracających z połączenia ajax i zauważyłem coś bardzo dziwnego.

Kiedy używam renderPartial zadzwonić akcję, to pisze się następujące wybierz:

<select id="Item" name="Item" data-val-required="The Item field is required." data-val-number="The field Item must be a number." data-val="true"> 

Jednak, kiedy nawiązać połączenie ajax do tego samego działania kontrolera dokładnym, to daje mi to z powrotem:

<select id="Item" name="Item"> 

Próbowałem dodać tagi skryptów do częściowego widoku, ale nie rozwiązało problemu. Czy jest jakiś powód, dla którego wywołanie ajax byłoby pozbawione dyskretnych znaczników walidacyjnych?

< ======================= UPDATE 2 ==================== =========>

Ok, więc co się stało, to miałem szablon edytora dla rozwijanego, który wziął listę wyboru i przekonwertował ją do html select. Znalazłem wpis, w którym wspomniałem, że aby uzyskać atrybuty sprawdzania poprawności danych do wypisania na szablonie edytora, musisz mieć kontekst formularza. Ponieważ program Html.RenderPartial był wykonywany w formularzu, szablon edytora miał kontekst formularza do pracy. Kiedy próbowałem wywoływać częściowe poprzez ajax, nie było kontekstu formularza do pracy, a zamiast narzekać, po prostu nie wypisałem atrybutów sprawdzania poprawności danych. Dodanie nowego Kontekstu formularza w szablonie edytora dla SelectListDropDown rozwiązało problem.

@{ // fix to stop stupid crappy brad wilson mvc3 code from stripping the jq data valdiation attributes 
    if (ViewContext.FormContext == null) 
    { 
     ViewContext.FormContext = new FormContext(); 
    } 
} 
+0

możliwy duplikat [Problem z uzyskaniem dyskretnego sprawdzania poprawności działającego z mvc 3 na jquery ajax post] (http: //stackoverflow.com/questions/7005052/trouble-getting-unobtrusive-validation-working-with-mvc-3-on-jquery-ajax-post) – jgauffin

+0

Również duplikat: http://stackoverflow.com/questions/6812779/mvc-3-razor-load-partial-with-validation – jgauffin

+1

Dodanie rzeczy ViewContext.FormContext naprawiło mój problem. – K0D4

Odpowiedz

67

$.validator.unobtrusive.parse("#frmAddItem"); będzie działać. Należy pamiętać, że musi być częściowe, które załadować za pośrednictwem AJAX (poniżej w formie częściowego)

<form id="frmAddItem" method="POST" action="..."> 
    <!-- all the items --> 
</form> 
<script type="text/javascript"> 
    $.validator.unobtrusive.parse("#frmAddItem"); 
</script> 
+2

Ok, po dodaniu samego skryptu w formularzu na końcu częściowego, aka: Zamiast próbować zdarzenia gotowego do pracy, wydawało się działać zgodnie z oczekiwaniami. Odpowiednio zaznaczam tę odpowiedź, ponieważ kwestia związana z walidacją, która nie przechodzi przez ajax, jest oddzielną kwestią.Dzięki bardzo jgauffin –

+0

+1 niesamowite, zajęło mi wieki, aby znaleźć rozwiązanie tego problemu – Liam

+9

Po prostu zwrócić uwagę, wziąłem nieco inne podejście i dodałem go do funkcji sukcesu mojego wezwania ajax '$ .ajax ({success: function () {$. validator.unobtrusive.parse ('formulacje');}}); ' – Liam

8

Dodaję moje doświadczenie jak powyższe zalecenia nie działa dla mnie. To rozwiązanie nie i mogą pomóc innym, że przekierowanie do tej strony z wyszukiwarki:

Dodaj OnSuccess="$.validator.unobtrusive.parse('YourFormName');" wam AjaxOptions

Przykładem korzystania Ajax.ActionLink:

@Ajax.ActionLink("This is a test to get unobtrusive javascript working", 
       "Name_of_your_controller_action", 
       new AjaxOptions { HttpMethod = "POST", 
            InsertionMode = InsertionMode.Replace, 
            UpdateTargetId = "UserDiv", 
            OnSuccess="$.validator.unobtrusive.parse('UserDetailsForm');" 
           } 
       ) 

To rozwiązanie zostało znalezione pod adresem: http://blog.janjonas.net/2011-07-24/asp_net-mvc_3-ajax-form-jquery-validate-supporting-unobtrusive-client-side-validation-and-server-side-validation

4

Inna opcja, a raczej sztuczka, która zadziałała dla mnie. Wystarczy dodać następującą linię na początku częściowego widoku, który jest zwracany przez wywołanie ajax

this.ViewContext.FormContext = new FormContext(); 

Reference

+0

Ah, dzięki czemu możesz wznowić kontekst formularza w częściowym zamiast szablonu edytora. Szczerze mówiąc, szablon wydaje się bardziej modułowy, ponieważ zadziałałby przy każdym wywołaniu w dowolnym widoku. Jedną rzeczą, którą możesz chcieć zrobić, jest sprawdzenie, czy kontekst jest pusty przed utworzeniem nowego i zastąpienie starego ... –

+0

@DavidC Przejście do szablonu edytora lub częściowego, zależy od scenariusza. Przy ładowaniu pierwszej strony kontekst nie jest pusty, ale po wszystkich wywołaniach ajaxu kontekst ma wartość null. Czy to naprawdę będzie bolało, jeśli kontekst zostanie ustawiony na nowy, nawet jeśli nie jest zerowy? – bjan

+0

prawda, że ​​zależy to od scenariusza i twojej infrastruktury, niektórzy ludzie nawet nie używają szablonów. Ale jeśli przejdziesz ścieżkę szablonu, to jest bardziej modułowa i sucha. Co do twojego drugiego pytania, myślę, że to by zależało od jakich innych danych walidacji, jakie miał kontekst formy, zanim ty tupałeś na tym. –

7

pisałem ten mały fragment, który można umieścić w pliku JavaScript i będzie obsługiwać wszystkie formularze załadowane ajax.

//enable unobtrusive validation for ajax loaded forms 
$(document).ajaxSuccess(function (event, xhr, settings) { 
    //process only if html was returned 
    if ($.inArray('html', settings.dataTypes) >= 0) { 
     //will parse the element with given id for unobtrusive validation 
     function parseUnobtrusive(elementId) { 
      if (elementId) { 
       $.validator.unobtrusive.parse('#' + elementId); 
      } 
     } 

     //get the form objects that were loaded. Search within divs 
     //in case the form is the root element in the string 
     var forms = $('form', '<div>' + xhr.responseText + '</div>'); 

     //process each form retrieved by the ajax call 
     $(forms).each(function() { 
      //get the form id and trigger the parsing. 
      //timout necessary for first time form loads to settle in 
      var formId = this.id; 
      setTimeout(function() { parseUnobtrusive(formId); }, 100); 
     }); 
    } 
}); 
+0

SetTimeout pomógł mi. Nienawidzę dodawać takich rzeczy - wydaje się zbyt kruche. – Andy

+0

Nagranie ze względu na setTimeout. Takie brzydkie podejście. –

+1

Zgłaszamy brzydotę? Wznawiane, ponieważ lubię pudding. –

1

mogę dostać tylko walidację do pracy wewnątrz OnComplete zamiast OnSuccess:

Oto kod AJAX:

@using (Ajax.BeginForm("Index", null, 
         new AjaxOptions { OnSuccess = "onSuccess", 
             OnComplete = "onComplete"}, 
         new { id = "mainForm" })) 

A oto mój skrypt:

function onComplete(result) { 
    $.validator.unobtrusive.parse("#mainForm"); 
    alert("Complete"); 
}; 
Powiązane problemy