【问题标题】:ASP.NET MVC rendering partial view with jQuery ajaxASP.NET MVC 使用 jQuery ajax 渲染局部视图
【发布时间】:2011-04-08 17:56:20
【问题描述】:

我有一个呈现部分视图的控制器操作:

public ActionResult Details(int id)
{
    DetailsViewModel model = 
        ModelBuilder.GetDetailsViewModel(id, _repository);
    return PartialView("Details", model);
}

我正在将返回的内容加载到动态元素中,如下所示:

$container = appendContainer(); // adds a div to the dom with the correct id
$container.load("MyController/Details", function(response, status, xhr) {
    if (status != "success") {
        $(container).html('an error has occured');
    }
});

所以这会创建一个 div,然后将返回的内容加载到该 div 中。

我想稍微改变一下,以便容器 div 仅在调用时创建 到控制器是成功的。

所以:

  1. jQuery 调用控制器动作
  2. 控制器返回 PartialView,如果未找到 Id,则返回 null
  3. 如果返回 PartialView,则创建容器并加载返回的内容。
  4. 如果控制器未找到 Id,则不会创建任何内容并显示警报。

如果我能最好地实现这一目标,我将不胜感激。

【问题讨论】:

    标签: asp.net-mvc ajax jquery partial-views


    【解决方案1】:

    在你的情况下,我会使用 $.ajax 而不是 .load() 让您更好地控制流程+感觉更干净

    $.ajax({
    url: "MyController/Details",
       type: "GET",
       success: function (response, status, xhr)
       {
          var jqContainer = appendContainer();
          jqContainer.html(response);
       },
       error:function(XMLHttpRequest, textStatus, errorThrown)
       {
         //show the error somewhere - but this is a bad solution
       }
    });
    

    关于错误状态 - 我也讨厌依赖异常 - 丑陋且效率低下, 你有几种方法来处理这个:

    1. 仅从您的视图中返回 JSON 并使用某种模板解决方案绑定返回的数据,这样您可以返回带有特定错误消息的错误对象并以相同的方式处理所有错误(认为这是最好的解决方案)。
    2. 返回 204 成功状态码 - 无响应,就像从您的操作中返回 null - 然后检查状态码并弹出错误消息。
    3. 返回一个 278 成功状态码(不是一个真正的状态码,但它是成功的计数并且允许你发送数据) - 在这里你发送一个带有错误消息的 json 对象,你可以解析并播下一个很好的错误消息(看到这个 278 解决方案在 SO 前一段时间)。
    4. 为错误返回不同的视图 - 但如果您想采取更多操作,则必须将其插入容器或虚拟容器以检查是否存在错误。

    在我的代码中,我使用 $(document).ajaxSend(..) 全局检查 278 代码的所有 Ajax 响应并显示错误消息(如果有),或调用原始挂钩成功函数。

    要从操作中返回错误,我使用以下结果

        public class AjaxErrorWithDetailsResult : JsonResult
        {
        public object ErrorResult { get; set; }
    
        public AjaxErrorWithDetailsResult(object errorResult)
        {
            this.ErrorResult = errorResult;
        }
    
    
        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            this.Data = ErrorResult;
            context.HttpContext.Response.StatusCode = 278;
            base.ExecuteResult(context);
        }
    }
    

    其中 ErrorResult 可以是匿名对象,也可以是实现具有 ErrorMessage 属性的接口的对象,因此您将知道在 JS 中要查找的内容

    【讨论】:

    • 我同意你的看法! $ajax 对流程有更多的控制权。
    【解决方案2】:

    load 所做的只是从服务器返回 HTML,那么为什么不直接附加到一个临时 div,然后在成功时从中获取 HTML?

    var $dummy = $("<div>");
    $dummy.load("MyController/Details", function(response, status, xhr) {
        var $container = appendContainer();
        if (status != "success") {
            $container.html('an error has occured');
        }
        else
        {
            $container.html($dummy.html());
        }
        $dummy.remove();
    });
    

    更新:

    如果您期待异常,那么您应该处理它。如果您基本上只是为了获得status != "success" 而允许发生错误,那么这是一种严重的代码异味。您应该捕获错误并返回不同的 PartialView。

    public ActionResult Details(int id)
    {
        try
        {
            DetailsViewModel model = 
                ModelBuilder.GetDetailsViewModel(id, _repository);
            return PartialView("Details", model);
        }
        catch (SomeException ex)
        {
            return PartialView("Error", ex.Message);
        }
    }
    

    那么你就可以保证总是得到一个有效的 HTML 响应,如果你没有,那么你的基本错误an error occured 就会起作用。

    【讨论】:

    • 我对此的保留意见是,我实际上是在我的视图中使用未捕获的异常来向 UI 返回空/未找到状态。如果找不到该项目,我宁愿从我的控制器返回一个空值,但我看不出有一种方法可以让这种方法与它一起工作。对我来说似乎有点代码味道。
    • @fearofawhackplanet - 更新了我的答案。
    猜你喜欢
    • 2010-10-19
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    相关资源
    最近更新 更多