Can't get past “A jquery script reference is required in order to enable Ajax support in the ”WebGrid“ helper”

瘦欲@ 提交于 2020-01-16 04:16:24

问题


I am having a similar as the user here: ASP.NET MVC 3.0 WebGrid - Ajax Enabled and here: http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/22be0501-1b0b-496a-9d0c-f9f5138996ac

However none of the suggestions from those threads is helping here.

The specifics: When running in my local debugger on my Windows 7/IIS 8 machine, I am getting the 'A jQuery script reference is required in order to enable Ajax support in the "WebGrid" helper' message after an ajax postback trying to update. The same code however does not result in a problem in FF or when using IE against a version of the same code running on a server (IIS 6). To make it more confusing, when I first wrote this code, I never had this problem - it has only recently started throwing error.

When the error occurs, the 'correct' updated content flashes on the screen before the whole page redirects to just the partial view and throws the popup on screen. It's like it works correctly but something then resets it and causes it to stop using ajax.

To try to troubleshoot I replaced the .min versions of jquery with the full versions and step through the code. In the debugger the jQuery behaves differently and triggers an "ajaxStop" because of the value in the global ajax counter. When I run the external script debugger against the server version of the same code in the same IE browser, this does not appear to occur (though I still have the 'min' version on the server so can't see exactly). It is this ajaxStop which appears to be forcing the webgrid to think that jQuery isn't loaded on the page and doesn't let the ajax behavior 'stick' - forcing a new page load of just the partial view.

My page is not ultra simple: the main View has several divs containing partial views - divSearch contains the search partial view which is the one calling the ajax postback, and divList contains the grid that needs to be updated based on the search results. The controller method called by the search partial view renders the 'new' contents for the search results into a string and sends them back as part of a JsonResult, which is then assigned to the divList's html via jQuery. (I use this technique in several places in the app, and I've verified that the string being sent back is the correct content for the partial view).

The jQuery (and all the other js includes) are at the top of the layout page and render before any of the partial views.

Main View:

 @model WebUI.Areas.Admin.Models.Client.ManageClientsModel
 @{
    ViewBag.Title = "ManageClients";
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<style type="text/css">
.inv
{
    visibility: hidden;
}
.vis
{
    visibility: visible; 
}
</style>

<h2>ManageClients</h2>
<div id="divSearch">
    @Html.Partial("_ClientSearch", Model.ClientList)
</div>
<div id="divList">
    @Html.Partial("_ClientList", Model.ClientList)
</div>
<br/>
<div id="newSection">

    <div id="divEdit"> <button class="toggleNew">
       Add Client
       </button>
    </div>
    div class="inv" id="divNew">  @Html.Partial("_Create", Model.ClientVM ) </div>
</div>
<script type="text/javascript">
   $(function () {
    $(".toggleNew").click(function () {
        $("#divNew").toggleClass("inv");
        return false;
    });
   });

</script>

Client Search partial:

 @using  Core.Entities
 @model  WebUI.Areas.Admin.Models.Client.ClientListViewModel
 <div id="clientSearch">
     <form action="@Url.Action("JsonSearch","Client", new { area = "Admin"})"  
                 onsubmit="return formSearchSubmit(this);"  >
         <div class="divReturnErrors"></div>
     @if(TempData["SearchName"] == null)
     {
         TempData["SearchName"] = Model.SearchName;
     }
         <br/>
         @Html.LabelFor(model => model.SearchName, "Search for client name:")
         @Html.EditorFor(model => model.SearchName)
          <input type="submit" value="Search" name="btnSearch"   />
     </form>
 </div>
 <script type="text/javascript">
   function formSearchSubmit(formToSubmit) {
     //this line submits the form data to the JsonSearch method
      $.post($(formToSubmit).attr("action"),
             { SearchName: $(formToSubmit).find("#SearchName").val() },
        function (data) {  //this is the callback from JsonSearch
                                        // that handles the results.
          if (data["IsSuccess"] == undefined || data["IsSuccess"] == false)
            $('div.divReturnErrors').html(data["Errors"]); 
                              //put errors in divReturnErrors
          else { //if it succeeds we stuff the string containing the 
                              //partial view into the _ClientList control's div to 
                             //replace previous grid.
                    $("#divList").html(data["PartialViewHtml"]);
                }
            }, "json");

                       return false;
             }  
</script>

Client List partial view

 @model WebUI.Areas.Admin.Models.Client.ClientListViewModel
 <h2>Clients</h2>
  @helper TrueFalseToYesNo(bool val) {
    if (val)
    {
       <span>Yes</span>
    }
    else
    {
       <span>No</span>
    }
   }
<div id="clientListing">

  @{
    if(Model.SearchName != null)
    {
        TempData["SearchName"] = Model.SearchName;
    }

    var grid = new WebGrid<NeedleFinder.Core.Entities.Client>(null, rowsPerPage: 10, 
              canSort: false, defaultSort: "ClientName", 
                       ajaxUpdateContainerId:"clientListing");
    grid.Bind(Model.Clients, rowCount: Model.TotalRows, autoSortAndPage: false);
    @grid.GetHtml(htmlAttributes: new {id= "clientListing"},
        tableStyle: "table90",
        alternatingRowStyle: "duncanTableAltRows",
        headerStyle: "duncanTableHeaders",
        columns: grid.Columns(
            grid.Column(columnName: "Client ID", style: "logcolumn", 
                    format: item =>              
                    @Ajax.ActionLink(((object)item.ClientID).ToString(), 
                    Model.LinkAction, new { id = item.ClientID }, new AjaxOptions { 
                    HttpMethod = "GET", UpdateTargetId = "divEdit", InsertionMode = 
                    InsertionMode.Replace })),
            grid.Column(columnName: "ClientName", style: "logcolumn"),
            grid.Column(columnName: "Abbreviation", style: "logcolumn"),
            //grid.Column(columnName: "IsActive", style: "logcolumn")
            grid.Column(columnName: "IsActive", style: "logcolumn", 
               format: item => @TrueFalseToYesNo(item.IsActive))
            )
               )
       }
</div>

The 'error' is occurring in this line: $("#divList").html(data["PartialViewHtml"]); from the Client Search partial view ajax callback function. This line jumps into the jQuery and while in there is calling ajaxStop.

Please note I have already incorporated the suggestions from the other thread (jQuery includes at the top, putting the webgrid in a div with the same name as the ajaxUpdateContainer target, adding an id property to the webgrid with the same name as well. The suggestion to load the partial explicitly in document.ready does not seem applicable to me since I am trying to populate this div with a string based on inputs rather than just plain load the default 'get' version of the partial view.

Here is the rendered html for the page when it first loads (it doesn't update when you do the ajax post anyway): (Apologies for the wonky formatting but adding 4 indents to each line didn't really work cleanly)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ManageClients</title>
<link href="/Content/Site.css" rel="stylesheet" type="text/css" />
<link href="/Content/themes/redmond/jquery-ui.css" rel="stylesheet" type="text/css" />

<script src="/Scripts/jquery-1.5.1.js" type="text/javascript"></script>
<script src="/Scripts/jquery-ui-1.8.18.js" type="text/javascript"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script src="/Scripts/modernizr-1.7.js" type="text/javascript"></script>
<script src="/Scripts/jQuery.Validate.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
</head>
<script type="text/javascript">

$(document).ready(function () {
    $('.dateEditor').datepicker({ dateFormat: "mm/dd/yy" });
});

//This function should be called in your ajax post return are staying on same page
     after success and/or you do have server side errors that couldn't have been found
//if there were still client side errors, otherwise you will still have the previous 
 validation errors.

function ClearValidationErrors() {

    var container = $('form').find('[data-valmsg-summary="true"]');
    var list = container.find('ul');

    if (list && list.length) {
        list.empty();
        container.addClass('validation-summary-valid').removeClass('validation-summary-
         errors');
    }
}


</script>
<body>
<style type="text/css">
#topbar
{
    background-color: Black;
    margin: 0px;
    padding: 5px;
}

#adminmenu_nav a
{
    float: left;
    width: 150px;
}

.logcolumn
{
    padding-left: 10px;
    padding-right: 10px;
    border: 1px solid #BBBBBB;
}

</style>
<script>
$(function () {
    $("#adminmenu_nav a").button();
    $("#optionsPanel input").button();
    $(".asButton input").button();
});
</script>
<div id="topbar">
<img style="margin-left:20px" src="/Content/Images/Logos/NFWhite.png" 
alt="NeedleFinder" />
</div>
<div>
<div id="adminmenu_nav" style="float: left">
    <table>
        <tr><td><a href="/Admin/Client/ManageClients">Clients</a></td></tr>
        <tr><td>Cases</td></tr>
        <tr><td><a href="/Admin/User/ManageUsers">Users</a></td></tr>
        <tr><td>Roles</td></tr>
        <tr><td><a href="/Admin/Logging/Summary">Logs</a></td></tr>
    </table>
</div>
<div style="overflow: hidden">
    <span class="validation-summary-errors"></span>
    <style type="text/css">
.inv
{
  visibility: hidden;
}
.vis
{
    visibility: visible; 
}
</style>

<h2>ManageClients</h2>
<div id="divSearch">
  <div id="clientSearch">
   <form action="/Admin/Client/JsonSearch" onsubmit="return formSearchSubmit(this);"  >
        <div class="divReturnErrors"></div>
        <br/>
        <label for="SearchName">Search for client name:</label>
        <input class="text-box single-line" id="SearchName" name="SearchName" 
          type="text" value="" />
         <input type="submit" value="Search" name="btnSearch"   />
    </form>
</div>
<script type="text/javascript">
function formSearchSubmit(formToSubmit) {
    //this line submits the form data to the JsonSearch method
    $.post($(formToSubmit).attr("action"),
            { SearchName: $(formToSubmit).find("#SearchName").val() },
        function (data) {  
        if (data["IsSuccess"] == undefined || data["IsSuccess"] == false)
            $('div.divReturnErrors').html(data["Errors"]); 
         else 
                     { 
            $("#divList").html(data["PartialViewHtml"]);
        }
    }, "json");

    return false;
    }  
</script>
</div>
<div id="divList">
  <h2>Clients</h2>

  <div id="clientListing">

<script type="text/javascript">if (typeof(jQuery)=='undefined') alert("A jQuery script 
reference is required in order to enable Ajax support in the \"WebGrid\" helper.");
</script><table class="table90" id="clientListing"><thead><tr 
  class="duncanTableHeaders"><th scope="col">Client ID</th><th 
  scope="col">ClientName</th><th scope="col">Abbreviation</th><th 
  scope="col">IsActive</th></tr></thead><tfoot><tr><td colspan="4">1 <a href="#" 
  onclick="$(&#39;#clientListing&#39;).load(&#39;/Admin/Client/ManageClients?page=2&
  amp;__=634750282355486955 #clientListing&#39;);">2</a> <a href="#" 
  onclick="$(&#39;#clientListing&#39;).load(&#39;/Admin/Client/ManageClients?page=3&
  amp;__=634750282355506956 #clientListing&#39;);">3</a> <a href="#" 
  onclick="$(&#39;#clientListing&#39;).load(&#39;/Admin/Client/ManageClients?page=4&
  amp;__=634750282355516957 #clientListing&#39;);">4</a> <a href="#" 
  onclick="$(&#39;#clientListing&#39;).load(&#39;/Admin/Client/ManageClients?page=5&
  amp;__=634750282355536958 #clientListing&#39;);">5</a> <a href="#" 
  onclick="$(&#39;#clientListing&#39;).load(&#39;/Admin/Client/ManageClients?page=2& 
  amp;__=634750282355546959 #clientListing&#39;);">&gt;</a> </td></tr></tfoot><tbody>
  <tr><td class="logcolumn"><a data-ajax="true" data-ajax-method="GET" data-ajax-
  mode="replace" data-ajax-update="#divEdit" href="/Admin/Client/_Edit/2042">2042</a>
  </td><td class="logcolumn">ABC Legal</td><td class="logcolumn">ABC123</td><td 
  class="logcolumn">           <span>Yes</span>

  </td></tr><tr class="duncanTableAltRows"><td class="logcolumn"><a data-ajax="true" 
  data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#divEdit" 
  href="/Admin/Client/_Edit/2044">2044</a></td><td class="logcolumn">ABC Legal 
  3</td><td class="logcolumn">ABC125</td><td class="logcolumn">           
  <span>Yes</span>

  </td></tr><tr><td class="logcolumn"><a data-ajax="true" data-ajax-method="GET" 
  data-ajax-mode="replace" data-ajax-update="#divEdit" href="/Admin/Client/_Edit
  /2045">2045</a></td><td class="logcolumn">ABC Legal 4b</td><td 
  class="logcolumn">ABC4bb</td><td class="logcolumn">           <span>Yes</span>

  </td></tr><tr class="duncanTableAltRows"><td class="logcolumn"><a data-ajax="true" 
  data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#divEdit" 
  href="/Admin/Client/_Edit/2047">2047</a></td><td class="logcolumn">ABC Legal 
  6</td><td class="logcolumn">ABC6</td><td class="logcolumn">           <span>No</span>

  </td></tr><tr><td class="logcolumn"><a data-ajax="true" data-ajax-method="GET" 
  data-ajax-mode="replace" data-ajax-update="#divEdit" href="/Admin/Client/_Edit
  /2048">2048</a></td><td class="logcolumn">ABC Legal 7</td><td 
  class="logcolumn">ABC7</td><td class="logcolumn">           <span>Yes</span>

  </td></tr><tr class="duncanTableAltRows"><td class="logcolumn"><a data-ajax="true"   
  data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#divEdit" 
  href="/Admin/Client/_Edit/2049">2049</a></td><td class="logcolumn">ABC Legal 
  8a</td><td class="logcolumn">ABC8a</td><td class="logcolumn">           
  <span>Yes</span>

  </td></tr><tr><td class="logcolumn"><a data-ajax="true" data-ajax-method="GET" 
  data-ajax-mode="replace" data-ajax-update="#divEdit" href="/Admin/Client/_Edit
  /2050">2050</a></td><td class="logcolumn">ABC Legal 9</td><td 
  class="logcolumn">ABC9</td><td class="logcolumn">           <span>Yes</span>

  </td></tr><tr class="duncanTableAltRows"><td class="logcolumn"><a data-ajax="true" 
  data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#divEdit" 
  href="/Admin/Client/_Edit/2043">2043</a></td><td class="logcolumn">ABC 
  Legal2</td><td class="logcolumn">ABC124</td><td class="logcolumn">           
  <span>Yes</span>
  </td></tr><tr><td class="logcolumn"><a data-ajax="true" data-ajax-method="GET" 
  data-ajax-mode="replace" data-ajax-update="#divEdit" href="/Admin/Client/_Edit
  /2046">2046</a></td><td class="logcolumn">ABC Legal5</td><td 
  class="logcolumn">ABC5</td><td class="logcolumn">           <span>Yes</span>
  </td></tr><tr class="duncanTableAltRows"><td class="logcolumn"><a data-ajax="true" 
  data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#divEdit" 
  href="/Admin/Client/_Edit/2051">2051</a></td><td class="logcolumn">ACE Legal 
  1</td><td class="logcolumn">ACE1</td><td class="logcolumn">           
  <span>Yes</span>

  </td></tr></tbody></table></div>


  </div>
<br/>
<div id="newSection">

   <div id="divEdit"> <button class="toggleNew">
     Add Client
  </button></div><!-- placeholder for _Edit., will replace button when editing//-->
  <div class="inv" id="divNew">
 <form action="/Admin/Client/JsonCreate" onsubmit="return formCreateSubmit(this);">
  <div>
    <div class="titleText">Add Client</div>
    <div class="divClientSideVal">
    <div class="validation-summary-valid" data-valmsg-summary="true"><ul><li 
      style="display:none"></li>
    </ul></div>
    </div>
    <div class="divCreateErrors"></div>
    <fieldset>
        <table>

            <tr>
                <td>
                    <label for="CurrentClient_ClientName">Name</label>
                </td>
                <td><input data-val="true" data-val-length="Client Name must be 50 
                       characters or fewer" data-val-length-max="50" data-val-
                      required="Client Name is required." 
                     id="CurrentClient_ClientName" name="CurrentClient.ClientName" 
                      style="width: 120px;" type="text" value="" /> 
                </td>
                <td><span class="field-validation-valid" data-valmsg-
               for="CurrentClient.ClientName" data-valmsg-replace="false">*</span></td>
            </tr>
            <tr>
                <td>
                    <label for="CurrentClient_Abbreviation">Abbreviation</label>
                </td>
                <td><input data-val="true" data-val-length="Abbreviation must be 6 
                characters or fewer" data-val-length-max="6" data-val-
                required="Abbreviation is required." id="CurrentClient_Abbreviation" 
                name="CurrentClient.Abbreviation" style="width: 120px;" type="text" 
                value="" />
                </td>
                <td><span class="field-validation-valid" data-valmsg-
               for="CurrentClient.ClientName" data-valmsg-replace="false">*</span></td>
            </tr>
            <tr>
                <td>
                    <label for="CurrentClient_IsActive">Is Active:</label>
                </td>
                <td>

                <input data-val="true" data-val-required="The IsActive field is 
                required." id="CurrentClient_IsActive" name="CurrentClient.IsActive" 
                 type="checkbox" value="true" /><input name="CurrentClient.IsActive" 
                  type="hidden" value="false" />
                </td>
            </tr>
            <tr>
                <td>Enable for installations:</td>
                <td>
                    <select Multiple="multiple" id="SelectedInstallations" 
              multiple="multiple" name="SelectedInstallations" style="width: 
               120px;">       
                 <option value="1">Dev</option>
                 <option value="2">FakeDev</option>
                </select>
                </td>
            </tr>
        </table></fieldset>
    <p>
        <input type="submit" value="Create" name="btnCreate"  />
    </p>
</div>
</form>

<script type="text/javascript">


function formCreateSubmit(formToSubmit) {

    var installations = "";
    $('#SelectedInstallations option').each(function (i) {
        if (this.selected == true) {
            if (installations.length > 0) {
                installations += ",";
            }
            installations += this.value;
        }
    });

    //this line submits the form data to the JsonCreate method
    $.post($(formToSubmit).attr("action"),
            { ClientName: $(formToSubmit).find("#CurrentClient_ClientName").val(),
                Abbreviation:  
               $(formToSubmit).find("#CurrentClient_Abbreviation").val(),
                IsActive: 
             $(formToSubmit).find("#CurrentClient_IsActive").is(':checked'),
                SelectedInstallations: installations,
                Action: "Create"
            },
    function (data) {  
    if (data["IsSuccess"] == undefined ||  data["IsSuccess"] == false)
    {
       if (data["Errors"] != undefined &&                          
                   data["Errors"].length > 0) 
                {
                        ClearValidationErrors();                    

     ('div.divCreateErrors').html(data["Errors"]);                      
      } else {
$('div.divCreateErrors').html("");
   }

} else { 
        window.location = "/Admin/Client/ManageClients";
    }
}, "json");

    return false;
   }
</script> </div><!-- placeholder for _Create //-->
</div>
<script type="text/javascript">
   $(function () {
    $(".toggleNew").click(function () {
        $("#divNew").toggleClass("inv");
        return false;
    });
   });

</script>



  </div>
</div>
  <div class="InternalMenu"><a href="/Admin/Logging">Logging</a> - <a href="/Admin
          /Client/ManageClients">Client</a></div>
  </body>
</html>

Any suggestions would be greatly appreciated as I'm pretty stumped as to what is causing the problem.


回答1:


Ok - I figured out the problem, so figure I will report back.

The issue was actually more MVC than jQuery related but it was a problem with how I had put my search form together.

I had my search button set with type=submit and also had an onsubmit eventhandler doing the ajax postback. What was occurring was that the ajax postback was doing exactly what it was supposed to but when it completed, the submit was triggering a "get" and the "get" handler in the controller for the search form returns just a PartialViewResult --> so this was replacing the screen contents as a normal load. The error was being thrown because the partial view did not have the layout with the includes.

So the fix was to a) change the button type to "button" b) remove the "onsubmit" from the form declaration c) add an id="frmSearch" to the form (for easy selectivity) d) modify the formSearchSubmit to take the action from $("#frmSearch").action instead of from the function argument (which is a button, not the form).

After that, it submitted the ajax post correctly and handled the return update w/o triggering another submit of the form.



来源:https://stackoverflow.com/questions/10987855/cant-get-past-a-jquery-script-reference-is-required-in-order-to-enable-ajax-su

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!