Ajax post в MVC 3 с несколькими формами - PullRequest
2 голосов
/ 03 апреля 2012

Я удалил свой предыдущий вопрос, касающийся темы, так как контекст немного изменился, и проблема новая.

У меня сейчас одно представление с одной моделью.Вид имеет 2 формы.Каждая форма подчиняется своему собственному действию, каждое действие использует подмножество данных модели, использует данные для выполнения поиска.Результаты поиска затем добавляются в свойство модели и должны быть возвращены обратно в представление.Я могу выполнить все это с помощью стандартного HTML-сообщения, но теперь это должен быть пост Ajax.

Вот мой ViewModel:

public sealed class SearchUsersViewModel {

    [Display(Name = "Last Name")]
    public string LastName { get; set; }

    [Display(Name = "Username")]
    public string Username { get; set; }

    [Display(Name = "Email Address")]
    public string EmailAddress { get; set; }

    [Display(Name = "Entity Type")]
    public byte EntityTypeID { get; set; }

    [Display(Name = "Search Name")]
    public string SearchField { get; set; }

    public IEnumerable<SelectListDTO> EntityTypes { get; set; }

    public IEnumerable<UserEditViewModel> Users { get; set; }

    [Display(Name = "Total Rows")]
    public int TotalRowCount { get; internal set; }

    public SearchUsersViewModel() {
        EntityTypes = LookupEntityTypeService.Instance.SelectList;
        Users = new List<UserEditViewModel>();
    }
}

Вот мой вид:

@model SearchUsersViewModel

<div>
    <div class="SearchByUserDataTable">
        @using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new {model = Model})) {
            @Html.ValidationSummary(true)
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 30px;">
                    <td class="Header01">
                        User Search:
                    </td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 20px;">
                    <td class="Header02">
                        Search By User Information:
                    </td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 1px;">
                    <td class="ContentDividerHoriz_425"></td>
                </tr>
            </table>
            <table id="searchByUserDataTable" cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 26px;">
                    <td class="leftColumn">
                        @Html.LabelFor(model => model.LastName):
                    </td>
                    <td class="rightColumn">
                        @Html.TextBoxFor(model => model.LastName, new { id = "lastNameSearchField", @class = "TextField_220" })
                    </td>
                </tr>
                <tr style="height: 26px;">
                    <td class="leftColumn">
                        @Html.LabelFor(model => model.Username):
                    </td>
                    <td class="rightColumn">
                        @Html.TextBoxFor(model => model.Username, new { id = "userNameSearchField", @class = "TextField_220" })
                    </td>
                </tr>
                <tr style="height: 26px;">
                    <td class="leftColumn">
                        @Html.LabelFor(model => model.EmailAddress):
                    </td>
                    <td class="rightColumn">
                        @Html.TextBoxFor(model => model.EmailAddress, new { id = "emailAddressSearchField", @class = "TextField_220" })
                    </td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td id="filterByUserError" style="width: 375px;"></td>
                    <td align="right" style="width: 50px; padding-right: 75px;">
                        <div>
                            <input id="filterByUserButton" type="submit" value="Search" />
                        </div>
                    </td>
                </tr>
            </table>
        }
    </div>

    <div class="SearchByEntityDataTable">
        @using (Html.BeginForm("FilterByEntityData", "Admin", FormMethod.Post, new { model = Model })) { 
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 28px;">
                    <td style="width: 425px;"></td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 20px;">
                    <td class="Header02">
                        Search By Entity Information:
                    </td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 1px;">
                    <td class="ContentDividerHoriz_425"></td>
                </tr>
            </table>
            <table id="searchByEntityDataTable" cellpadding="0" cellspacing="0" border="0">
                <tr style="height: 26px;">
                    <td class="leftColumn">
                        @Html.LabelFor(model => model.EntityTypeID):
                    </td>
                    <td class="rightColumn">
                        @Html.DropDownListFor(model => model.EntityTypeID, new SelectList(Model.EntityTypes, "ID", "Name"), new { id = "entityTypeDropDown", @class = "DropDown_220" })
                    </td>
                </tr>
                <tr style="height: 26px;">
                    <td class="leftColumn">
                        @Html.LabelFor(model => model.SearchField, new { id = "entityTypeSearchLabel"}):
                    </td>
                    <td class="rightColumn">
                        @Html.TextBoxFor(model => model.SearchField, new { id = "entityTypeSearchField", @class = "ui-widget TextField_220" })
                    </td>
                </tr>
                <tr style="height: 26px;">
                    <td class="leftColumn"></td>
                    <td class="rightColumn"></td>
                </tr>
            </table>
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td id="filterByEntityError" style="width: 375px;"></td>
                    <td align="right" style="width: 50px; padding-right: 75px;">
                        <div>
                            <input type="submit" value="Search" />
                        </div>
                    </td>
                </tr>
            </table>
        }
    </div>

    <div id="searchResults">
        @(Html.Telerik().Grid(Model.Users)
            .Name("Users").TableHtmlAttributes(new { style = "width: 870px;"})
            .Columns(columns => {
                columns.Bound(o => o.EntityTypeName).Title("Entity Type");
                columns.Bound(o => o.FirstName).Title("First Name");
                columns.Bound(o => o.LastName).Title("Last Name");
                columns.Bound(o => o.Username).Title("Username");
                columns.Template(
                    @<text>
                        <a href="mailto:@item.EmailAddress" target="blank">@item.EmailAddress</a>
                    </text>).Title("Email").HtmlAttributes(new { style = "text-align: center" }).HeaderHtmlAttributes(new { style = "text-align: center" });
                columns.Template(
                    @<text>
                        <div class="ActionIcon_ResendInvitationOn" title="Resend Invitation" onclick="location.href='@Url.Action("ResendInvitation", "Admin", new { entityTypeID = item.EntityTypeID, emailAddress = item.EmailAddress })'"></div> 
                        @{
                            if (item.IsApproved) {
                                <div class="ActionIcon_AccountStatusOn" title="Disable Account" onclick="setApprovalStatus('@item.Username', false);"></div> 
                            }
                            else {
                                <div class="ActionIcon_AccountStatusOn" title="Enable Account" onclick="setApprovalStatus('@item.Username', true);"></div> 
                            }
                        }
                        @{
                            if (item.IsLockedOut) {
                                <div class="ActionIcon_ResetPasswordOn" title="Unlock Account" onclick="unlockAccount('@item.Username')"></div> 
                            }
                            <div class="ActionIcon_ResetPasswordOn" title="Reset Password"  onclick="resetPassword('@item.Username')"></div> 
                        }
                        <div class="ActionIcon_EditOn" title="Edit User" onclick="location.href='@Url.Action("Edit", "Admin", new { id = item.MembershipID, username = item.Username })'"></div>
                    </text>).Title("Actions");
                columns.Bound(o => o.RowNumber).Hidden(true);
                columns.Bound(o => o.MembershipID).Hidden(true);
                columns.Bound(o => o.EntityTypeID).Hidden(true);
            })
            .Pageable(paging => paging.PageSize(10))
            .Sortable()
        )
        <span>Total Rows: </span> @Html.DisplayFor(model => Model.TotalRowCount)

        <p>
            @Html.ActionLink("Create New User", "Create", "Invitation")
        </p>
    </div>
</div>

Я использовал это представление с этой строкой как BeginForm:

@using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new {model = Model})) 

И использовал это:

 @using (Html.BeginForm())

с этим сценарием Ajax

$('#filterByUserButton').click(function () {
    $.ajax({
        url: '/Admin/FilterByUserData',
        type: 'POST',
        success: function (result) {
            alert(result);
        }
    });
});

С первым методом, использующим сообщение HTML, он работает нормально, но мне нужно использовать функциональность ajax, поэтому 2-й метод - моя проблема

1) Используя вызов ajax, модель, отправляемая в действие, содержитвсе значения NULL в текстовых полях вместо значений, которые я ввожу в форму.Модель хорошо выполняет публикацию, используя метод HTML

2) Даже если мне удастся заставить модель разместить правильно, чтобы у меня были значения для поиска, как вернуть данные в таблицу и как показать модельошибки при сбое проверки вместо отправки результата в UpdateTargetID?

3) Возможность отправки обеих форм на контроллер и получения одинаковых результатов в представлении, результат поиска

Кажется, у меня может быть только 1 UpdateTarget - что хорошо, еслиу вас никогда не бывает ошибок ... но поведение плохое, мне нужно показать ошибки проверки на поле точно так же, как если бы это был синхронный вызов.Поэтому результат ошибки, получаемый в результате действия, должен иметь свою собственную цель.

Я пришел с этим Ajax-вызовом, который прекрасно работает с действиями, которым не нужно возвращать данные, только с сообщением об успехе или сообщении об ошибке.Каждый загружается в свой собственный div.

$(function () {
    $('form').submit(function () {
        if ($(this).valid()) {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    if (result.toString().indexOf("Success") == -1) {
                        $('#successDiv').hide();
                        $('#errorDiv').html('');
                        $('#errorDiv').fadeIn(100).append($('<ul />').append(result));
                    }
                    else {
                        $('#errorDiv').hide();
                        $('#successDiv').fadeIn(1000).html(result).fadeOut(6000);
                    }
                }
            });
        }
        return false;
    });
});

Это действия, которые обрабатывают поиск (действие FilterByUserData отличается тем, что я пытался понять, как получить правильный результат, я непока он возвращает данные должным образом.

    public ActionResult Search() {
        var model = new SearchUsersViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult FilterByUserData(SearchUsersViewModel model) {
        var result = string.Empty;
        if (model.LastName != null || model.Username != null || model.EmailAddress != null) {
            var listOfMatchingUsers = SearchUserService.SearchByUserData(model.LastName, model.Username, model.EmailAddress);
            model = PrepareResultsModel(listOfMatchingUsers, model);
        }
        else {
            ModelState.AddModelError("", "Last Name, Username or Email Address must be entered for search");
        }
        if (ModelState.IsValid)
            result = "Success: Thanks for your submission: " + model.Username;
        else {
            result = ModelState.SelectMany(item => item.Value.Errors).Aggregate(result, (current, error) => current + error.ErrorMessage);
        }
        return Content(result, "text/html");
    }

    [HttpPost]
    public ActionResult FilterByEntityData(SearchUsersViewModel model) {
        if(model.EntityTypeID > 0 &&  model.SearchField != null) {
            var listOfMatchingUsers = SearchUserService.SearchByEntityData(model.EntityTypeID, model.SearchField);
            model = PrepareResultsModel(listOfMatchingUsers, model);
        }
        else {
            var entityType = string.Empty;
            if(model.EntityTypeID == 2) entityType = "Lender";
            if (model.EntityTypeID == 3) entityType = "School";
            ModelState.AddModelError("", entityType + " name must be entered for search");
        }
        return View("Search", model);
    }

    private SearchUsersViewModel PrepareResultsModel(ICollection<SearchUserResultsDTO> listOfMatchingUsers, SearchUsersViewModel model) {
        if (listOfMatchingUsers.Count != 0) {
            model.Users = listOfMatchingUsers.Select(item => new UserEditViewModel(item)).ToList();
            model.TotalRowCount = model.Users.Count();
        }
        return model;
    }

Как я могу получить модель для сообщения ajax, чтобы оно соответствовало моим действиям? и как мне вернуть правильную модель, чтобы моя сетка имела результаты?и если есть ошибка, как я могу получить это, как показано в валидации?

Обновление: для @Shyju Я попробовал то, что вы предложили, пытаясь включить ваш пример в мой код, нозначения свойств модели по-прежнему равны нулю и не устанавливаются. Это то, что я сделал в моей функции ajax, обратите внимание, что она отличается от вашего метода form.post:

$('#filterByUserButton').click(function () {
    $.ajax({
        url: '/Admin/FilterByUserData',
        type: 'POST',
        data: {LastName : $('#LastName').val(), Username : $('#Username').val(), EmailAddress : $('#EmailAddress').val()},
        success: function (result) {
            processResult(result);
        }
    });
});

Я такжепопробовал это:

$('form').submit(function() {
    alert("submitting");
    $.post('@Url.Action("FilterByUserData","Admin")', { LastName: $("#LastName").val(), UserName: $("#Username").val(), EmailAddress: $("#EmailAddress").val() },
        function(data) {
            alert(data);
    });
});

Страница мигает, и первое предупреждение - это оно, но оно никогда не попадает во второе предупреждение и никогда не попадает в контроллер, поэтому похоже, что оно даже не публикуется.Я также попробовал это, но он также не воздействует на действие контроллера:

$('#filterByUserButton').click(function () {
    alert("submitting");
    $.ajax({
        url: '/Admin/FilterByUserData',
        type: 'POST',
        data: {LastName : $('#LastName').val(), Username : $('#Username').val(), EmailAddress : $('#EmailAddress').val()},
        success: function (result) {
            alert(result);
            processResult(result);
        }
    });
});

Я также попробовал вышеупомянутое с пропущенной строкой data: и это коснется моего действия контроллера, но опять же, отправляемая модель имеет нулевое значениезначения в свойствах.Модель не нулевая, просто значения свойств.У меня есть значения в свойствах раскрывающегося списка модели, EntityTypes по-прежнему показывают 4 значения.Так что есть что-то в публикации этой формы, но значения формы не входят в свойства модели.

Обновление 2

@ Shyju Я использую ваш код ajax какИтак:

$(function () {
    $('#SearchByUserForm').submit(function () {
        $.post('@Url.Action("FilterByUserData", "Admin")', { LastName: $("#LastName").val(), UserName: $("#UserName").val(), EmailAddress: $("#EmailAddress").val() },
        function (data) {
            alert(data);
        });
        return false;
    });
});

Я могу сделать это после нажатия кнопки отправки, но она не может выполнить действие post моего контроллера.Я посмотрел на HTML, представленный для формы, и это то, что я вижу .. что неверно:

<form action="/Admin/Search/SearchByUserForm" method="post">         

Как видите, действие POST здесь неверно. Контроллер верен, но все остальное неправильно. Это должно быть отправка в / Admin / FilterByUserData. Я уверен, что это просто синтаксический беспорядок, в котором я нахожусь, и я просто не уверен, что я делаю неправильно. В стандартной форме я бы сделал это:

@using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new { model = Model })) { 

Который работает правильно. Но я не могу объединить эту подпись формы с постом действия URL из вашего кода Ajax. Я попытался просто оставить форму полностью с идентификатором, но у меня возникла проблема, о которой я говорил выше:

@using (Html.BeginForm(new {@id = "SearchByUserForm"})) {

Я думаю, что эта проблема возникает из-за того, что мое представление отображается путем нажатия на действие «Поиск» моего контроллера, поэтому URL-адрес - / Admin / Search, но формы в представлении необходимо публиковать в / Admin / FilterByUserData и / Администратор / FilterByEntityData. Как я уже говорил выше, если я явно создаю Html.BeginFrom с правильной подписью, тогда он работает, но это просто не Ajax

Обновление 3

@ Shyju

У меня все получилось, проблема была определенно в подписи формы, я изменил ее, и я могу успешно выполнить действие моего контроллера, а также данные передаются! Спасибо за вашу помощь!

Вот как это работает:

@using (Html.BeginForm(new {id = "SearchByUserForm", @controller = "Admin", @action = "FilterByUserData"})) {

1 Ответ

2 голосов
/ 03 апреля 2012

Используйте то же имя, что и для имени вашего свойства (вашей модели представления, которая является параметром вашего метода действия), когда вы передаете данные в свой пост jquery.вы получите объект, заполненный данными.

('form').submit(function () {
    $.post('@Url.Action("Logon","Account")', { LastName : $("#username").val(), 
                     UserName:   $("#password").val() },
                     EmailAddress:   $("#password").val() },  function (data) {

    //process the result and update the grid

});

РЕДАКТИРОВАТЬ: Поскольку ОП сказал, что он не работает, я создал образец проекта с нуля, чтобы проверить это, и этоработает нормально.Вот мой вид выглядит как

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>

<h2>Index</h2>
<form id="frm1" action="Search">
LastName <input type="text" id="LastName" /><br />
UserName <input type="text" id="UserName" /><br />
Email Address <input type="text" id="EmailAddress" />
<input type="submit" value="go" />
</form>
<script type="text/javascript">
    $(function () {
        $('#frm1').submit(function () {
            $.post('@Url.Action("Search", "Home")', { LastName: $("#LastName").val(),
                UserName: $("#UserName").val(),
                EmailAddress: $("#EmailAddress").val()
            }, function (data) {

                alert(data)
            });
            return false;
        });
    });
</script>

И мой метод действия, который получает почтовый вызов:

public ActionResult Search(SearchUsersViewModel objVM)
{
   return View();
}

А вот скриншоты результатов

Клиент

enter image description here

Метод действия контроллера

enter image description here

Вы даже можете отправить форму надействие контроллера с использованием метода jquery serialize ().

http://api.jquery.com/serialize/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...