AJAX调用后刷新ViewModel和视图

时间:2016-01-27 15:02:16

标签: javascript jquery ajax asp.net-mvc twitter-bootstrap-3

我正在尝试创建一个包含子行(每行一个子节点)的表作为详细信息部分。在此详细信息部分中,用户将能够查看日志历史记录,还可以输入特定日志。输入新日志并单击“添加”按钮后,日志历史记录应更新并显示新添加的事件。

我有以下AJAX调用,用于添加日志,并应刷新详细信息部分,在单击上面提到的“添加”按钮后触发:

 $('#addLog').click(function () {
        formData = {
            logType: logType.value, // Parameter to add a new log
            logComments: logComments.value, // Parameter to add a new log
            agent: agent.value // Parameter to add a new log
        }
        $.ajax({
            url: '@Url.Action("AddLog", "AgentUser")',
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            data: JSON.stringify(formData),
            cache: false,
            success: function (data) {
                // Here I should refresh the the details section
                // and clear the logType and logCommands inputs
            }
        });
    });

在我的控制器中:

[HttpPost]
public ActionResult AddLog(string logType, string logComments, string agent, AgentUserValidatePhoneIndexViewModel vm)
{
    DoDbStuff();

    // Here I need to update the view model and view without having to
    // refresh the page, so that it shows the recently added event.

    return View(vm);
}

我的ViewModel:

public class AgentUserValidatePhoneIndexViewModel
{
    public IEnumerable<AgentUserWithoutValidPhone> AgentUserWithoutValidPhoneList { get; set; }
}

我的模特:

public class AgentUserWithoutValidPhone
{
    private string phone;
    private DateTime creationDate;
    public string Agent { get; set; }
    public string Phone
    {
        get
        {
            return phone;
        }
        set
        {
            phone = PhoneNumberUtil.GetInstance().Parse("+" + value, String.Empty).NationalNumber.ToString();
        }
    }
    public DateTime CreationDate
    {
        get
        {
            return creationDate;
        }
        set
        {
            creationDate = value;
            TimeSpan timeSpan = (DateTime.Now) - creationDate;
            TimeGoneBy = (timeSpan.Days != 0 ? timeSpan.Days + "d " : String.Empty) + timeSpan.Hours + "h";
        }
    }
    public string TimeGoneBy { get; set; }
    public DateTime LastLogEventDate { get; set; }
    public LogEventTypePhone LastLogEvent { get; set; }
    public IEnumerable<AgentUsersLog> EventList { get; set; }
}

我的观点:

@foreach (var agentUser in Model.AgentUserWithoutValidPhoneList)
    {
        <tr data-toggle="collapse" data-target="#details" class="accordion-toggle">
            <td>
                <button class="btn btn-default btn-sm"><span class="glyphicon glyphicon-collapse-down"></span></button>
            </td>
            <td>
                @agentUser.Agent
            </td>
            <td>
                @agentUser.Phone
            </td>
            <td>
                @agentUser.CreationDate
            </td>
            <td>
                @agentUser.TimeGoneBy
            </td>
            <td>
                @agentUser.LastLogEventDate
            </td>
            <td>
                @agentUser.LastLogEvent.GetDescription()
            </td>
        </tr>
        <tr>
            <td colspan="12" class="hiddenRow" id="">
                <div class="accordian-body collapse" id="details">
                    <table class="table table-striped">
                        <thead>
                            <tr>
                                <input type="hidden" id="agent" value='@agentUser.Agent'>
                                <td>
                                    @Html.DropDownList("LogEventTypePhone", EnumHelper.GetSelectList(typeof(Enums.LogEventTypePhone)), "Select log event",
                                    new
                                    {
                                        id = "logType",
                                        @class = "form-control"
                                    })
                                </td>
                                <td colspan="2">
                                    <input type="text" class="form-control" placeholder="Comments" id="logComments">
                                </td>
                                <td>
                                    <a href="#" class="btn btn-default btn-sm" id="addLog">
                                        <i class="glyphicon glyphicon-plus"></i>
                                    </a>
                                </td>
                            </tr>
                            <tr>
                                <th>Event date</th>
                                <th>Event type</th>
                                <th>Comments</th>
                                <th>User</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var e in agentUser.EventList)
                            {
                                <tr>
                                    <td>@e.Date</td>
                                    <td>@(((Enums.LogEventTypePhone)e.Subtype).GetDescription())</td>
                                    <td>@e.Comments</td>
                                    <td>@e.AspNetUsers.UserName</td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>
            </td>
        </tr>
    }

如何将ViewModel与参数一起传递给我的控制器操作?现在,当我采取行动时,它是空的。我需要将其传递给操作,与DB交互,更新ViewModel,返回View并使用当前ViewModel更新它。

我从来没有做过我在这里想做的事情,我对此感到困惑。不确定它是否可能,或者我应该使用多个ViewModel。

2 个答案:

答案 0 :(得分:1)

无需将视图模型传递给控制器​​并再次返回(这会不必要地降低性能)。如果您只想根据发布到控制器方法的值添加新行,则创建一个包含要在新行中显示的值的匿名对象(或AgentUsersLog的新实例),将其返回作为json并通过添加新的<tr>元素来更新DOM。

您的代码还存在一些其他问题,包括您在id循环中创建无效html(重复foreach属性)的事实。删除id属性并使用类名与相对选择器一起使用(您显示的代码只会处理.click()的第一个链接的id="addLog"事件。您应该查看代码

@foreach (var agentUser in Model.AgentUserWithoutValidPhoneList)
{
    <tr data-toggle="collapse" data-target=".details" class="accordion-toggle">
        ....
    </tr>
    <tr>
        <td colspan="12" class="hiddenRow">
            <div class="accordian-body collapse details"> // use class name
                <table class="table table-striped">
                    <thead>
                        <tr>
                            <td>
                                <input type="hidden" class="agent" value='@agentUser.Agent'> // must be inside a td element
                                @Html.DropDownList("LogEventTypePhone", EnumHelper.GetSelectList(typeof(Enums.LogEventTypePhone)), "Select log event", new
                                {
                                    id = "", // remove id
                                    @class = "form-control logType" // add class name
                                })
                            </td>
                            <td colspan="2">
                                <input type="text" class="form-control logComments" placeholder="Comments"> // use class name
                            </td>
                            <td>
                                <a href="#" class="btn btn-default btn-sm addLog"> // use class name
                                    <i class="glyphicon glyphicon-plus"></i>
                                </a>
                            </td>
                        </tr>
                        <tr>
                            ....
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var e in agentUser.EventList)
                        {
                            ....
                        }
                    </tbody>
                </table>
            </div>
        </td>
    </tr>
}

脚本变为

var url = '@Url.Action("AddLog", "AgentUser")';
$('.addLog').click(function () {
    var table = $(this).closest('table');
    var logType = table.find('.logType').val();
    var logComments = table.find('.logComments').val();
    var agent = table.find('.agent').val();
    $.post(url, { logType: logType, logComments: logComments, agent: agent }, function(data) {
        var row = $('<tr></tr>');
        row.append($('<td></td>').text(data.Date));
        .... // add other cells for data.Subtype, data.Comments and data.UserName
        table.children('tbody').append(row);
    });
});

然后在控制器中

[HttpPost]
public JsonResult AddLog(string logType, string logComments, string agent)
{
    DoDbStuff();
    // Build the data to return
    var data = new
    {
      Date = .... ,
      Subtype = .... ,
      Comments = ..... ,
      UserName = ....
    };
    return Json(data);
}

答案 1 :(得分:0)

您可以通过创建子对象来实现此目的。让我们假设模型“AgentUserValidatePhoneIndexViewModel”具有以下属性

  1. 电话(国际)
  2. AgentDetail(字符串)
  3. 然后生成formData,如下所示

    formData = {
                logType: logType.value, // Parameter to add a new log
                logComments: logComments.value, // Parameter to add a new log
                agent: agent.value // Parameter to add a new log
                vm : { // Parameter to add values to view model
                   phone : answer.value,
                   agentDetail : agentDetail.value
                }
            }
    

    查看此帖子以了解如何渲染部分视图

    这篇文章解释了https://www.simple-talk.com/dotnet/asp.net/revisiting-partial-view-rendering-in-asp.net-mvc/