PartialView 在 ajax 重新加载时无法正确呈现

PartialView not rendering properly on ajax reload

我在使用 ajax 重新加载部分视图时遇到问题。

我在局部视图中有我的国家/地区表单,最初当我加载主页时,一切都正确呈现。

如下图所示,我可以使用自动完成功能搜索国家/地区,也可以从我的组合框中 select 一个国家/地区(两者都是 kendo-mvc 控件)

当我 select 从我的自动完成中尝试通过 ajax 加载 selected 国家/地区的信息时,问题出现了。表单已重新加载,信息已显示,但控件未正确呈现。自动完成功能停止工作,组合框呈现为普通文本框,显示国家 ID 而不是国家/地区名称。

我认为的代码

@using (Html.BeginForm("Index", "CountryManagement", FormMethod.Post, new { id = "country-form" }))
{  
    @Html.ValidationSummary(true);
    <div id="form-content">
         @Html.Partial("_CountryForm", Model)
    </div>

}

我的部分视图中的代码

<div class="form-group">
        @Html.Label("Search Country", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-3">
            @(Html.Kendo().AutoCompleteFor(m => m.Search)
                          .DataTextField("Designation")
                          //.DataValueField("CountryID")
                          .Filter("contains")
                          .MinLength(2)
                          .DataSource(d => { d.Read(r => r.Action("SearchCountry", "Common")); })
                          .Events(e => e.Change("onChange")).Deferred()
            )
        </div>
    </div>

我控制器中的代码

[HttpPost]
public PartialViewResult Edit(int id)
{
    //HTTP GET: api/Country/CountryDetails?id={id}&lang={lang}
    dynamic model =  //code to get selcted country data
    return PartialView("_CountryForm", model);
}

我的 .js 文件中的代码

function onChange() {
    
    if ($("#Search").data("handler")) {
        var data = $("#Search").data("handler").dataSource.data();
        var country = data.find(x => x.Designation == $("#Search").val());
        console.log("Country")
        if (country) {
            var request = $.post('/CountryManagement/Edit', { id: country.CountryID });
            request.success(function (data) {
                $("#form-content").html(data);
            });
        }
    }
}

HTML 页面加载时生成的代码(仅限自动完成和下拉菜单)

<div class="form-group">
    <label class="control-label col-md-2" for="Search_Country">Search Country</label>
    <div class="col-md-3">
        <span tabindex="-1" role="presentation" class="k-widget k-autocomplete k-header k-state-default k-state-hover"><input data-val="true" data-val-length="Description  must have between 1  and 150 characters" data-val-length-max="150" data-val-length-min="1" id="Search" name="Search" type="text" data-role="autocomplete" class="k-input" autocomplete="off" role="textbox" aria-haspopup="true" aria-disabled="false" aria-readonly="false" aria-owns="Search_listbox" aria-autocomplete="list" has-focus="false" style="width: 100%;"><span class="k-icon k-loading" style="display:none"></span></span>
    </div>
</div>
<br>
<br>
<div class="form-group">
    <label class="control-label col-md-2" for="Country">Country</label>
    <div class="col-md-3">
       <span class="k-widget k-combobox k-header"><span tabindex="-1" unselectable="on" class="k-dropdown-wrap k-state-default"><input name="CountryID_input" class="k-input" type="text" autocomplete="off" title="" role="combobox" aria-expanded="false" tabindex="0" aria-disabled="false" aria-readonly="false" aria-autocomplete="list" aria-owns="CountryID_listbox" has-focus="false" style="width: 100%;"><span tabindex="-1" unselectable="on" class="k-select"><span unselectable="on" class="k-icon k-i-arrow-s" role="button" tabindex="-1" aria-controls="CountryID_listbox">select</span></span></span><input data-val="true" data-val-number="The field CountryID must be a number." id="CountryID" name="CountryID" type="text" value="0" data-role="combobox" aria-disabled="false" aria-readonly="false" has-focus="false" style="display: none;"></span>
        <span class="field-validation-valid text-danger" data-valmsg-for="CountryID" data-valmsg-replace="true"></span>
    </div>
</div>

HTML 部分视图重新加载时生成的代码(仅限自动完成和下拉)

<div class="form-group">
    <label class="control-label col-md-2" for="Search_Country">Search Country</label>
    <div class="col-md-3">
        <input data-val="true" data-val-length="Description  must have between 1  and 150 characters" data-val-length-max="150" data-val-length-min="1" id="Search" name="Search" type="text" value="South Africa">
    </div>
</div>
<br>
<br>
<div class="form-group">
    <label class="control-label col-md-2" for="Country">Country</label>
    <div class="col-md-3">
       <input data-val="true" data-val-number="The field CountryID must be a number." id="CountryID" name="CountryID" type="text" value="1003">
        <span class="field-validation-valid text-danger" data-valmsg-for="CountryID" data-valmsg-replace="true"></span>
    </div>
</div>

我不确定这是否是 ASP.Net MVC 局部视图、Kendo 控件或部分视图重新加载时应重新 运行 的某些脚本的问题。 有人可以帮我吗?

经过无数次失败的尝试和在 Telerik 论坛深处的挖掘无果,我终于找到了问题所在。

Kendo 部分视图中的小部件不应使用延迟初始化。

@(Html.Kendo().AutoCompleteFor(m => m.Search)
                      ///.. code removed to reduce complexity
                      .Events(e => e.Change("onChange")).Deferred()
 )

当视图作为服务器请求加载时,它会正确呈现,因为在布局文件的末尾,所有具有延迟初始化的小部件都使用 @Html.Kendo().DeferredScripts() 进行了初始化。但是,当通过 ajax 重新加载局部视图时,延迟的脚本初始化永远不会发生,因为脚本不会重新 运行.

@Html.Kendo().DeferredScripts() 添加到局部视图解决了 ajax 重新加载的问题,但在服务器加载时会出现问题,因为: 1 - 延迟初始化将 运行ning 两次,并且2 - 因为 kendo 小部件具有 jquery 依赖关系,并且在 jquery 脚本包含在页面中之前会 运行ning。

我找到的解决方案是不延迟小部件的初始化,但是这会让我们回到上面关于 jquery 依赖项的观点。尽管我试图避免它,但唯一真正起作用的是在页眉中包含 jquery 。所有其他脚本(验证、kendo、自定义等)仍在底部,但主要的 jquery 脚本在顶部。现在我的部分视图可以完美地加载到服务器或 ajax 请求上。

TL;DR;

  1. 不要在部分视图中使用延迟初始化
  2. 将 jquery.min.js 移动到页面顶部。

希望有更好的方法来做到这一点,但现在它可以解决问题。

所以我在论坛上搜索也找不到合适的修复方法。但我做了以下,它似乎工作得很好。基本上,如果部分正常呈现,则布局视图会处理延迟的脚本,但如果请求通过 AJAX,则部分视图将继续呈现它们。

我把这个放在我部分的底部:

@if (Context.Request.IsAjaxRequest())
{
    <div id="kendo-scripts">
        @Html.Kendo().DeferredScripts()
    </div>
}

仅供参考,将 .Deffered() 留在 kendo 对象的末尾,以防不明显。

检查是否有任何页面脚本初始化错误!

我 运行 在这里遇到了同样的问题,并为此耗费了 3 天时间,对我来说,问题最终是围绕 no MutationObserver 在旧版 safari 浏览器中不可用的页面初始化脚本。添加 polyfill 并修复初始错误后,使用 Kendo 控件动态注入 ajax 内容工作正常,无需延迟。希望这可以避免其他人的挫败感。

此初始化错误影响了 jquery 对任何 ajax 内容的就绪初始化程序回调,Telerik 依赖这些内容来呈现它发出的脚本块中的每个控件。