刷新视图模型和 AJAX 调用后的视图

Refreshing ViewModel and view after AJAX call

本文关键字:视图 调用 AJAX 新视图 模型 刷新      更新时间:2023-09-26

我正在尝试创建一个表,其中子行(始终每行一个子行)充当详细信息部分。在此详细信息部分中,用户将能够看到日志历史记录,并且还可以输入特定日志。输入新日志并单击"添加"按钮后,日志历史记录应更新并显示新添加的事件。

我有以下 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);
}

我的视图模型:

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 与参数一起传递到控制器操作中?现在,当我开始行动时,它已经是空的了。我需要将其传递到操作中,与数据库交互,更新视图模型,返回到视图并使用当前视图模型对其进行更新。

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

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

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

@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);
}

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

  1. 电话(整数)
  2. 代理详细信息(字符串)

然后生成表单数据,如下所示

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/