Сообщение MVC Ajax для контроллера при событии щелчка - PullRequest
0 голосов
/ 24 декабря 2018

Я пытаюсь использовать ajax для отправки сообщений на контроллер, когда установлен флажок.Следует обновить существующий объект.Мои две проблемы:

  • Я не могу успешно вызвать метод действия контроллера
  • Только первый элемент в списке имеет событие щелчка

Надеюсь, кто-томожет помочь

Событие при нажатии с ajax

    $('#checkboxID').on('click', function () {
            $.ajax({
                url: '@Url.Action("Attending", "GuestBookings")',
                type: 'POST',
                data: JSON.stringify({
                    "cID": $(this).val('cID'), "eID": $(this).val('eID'), "check": $(this).is(':checked') ? 1 : 0
                }),
                success: function(result) {
                    alert("Succeeded post");
                },
                error: function(result) {
                    alert("Failed to post");
                }
            });
        });

Контроллер HttpPost

    [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Attending(string cID, string eID, string check)
        {
            if (ModelState.IsValid)
            {
                var guest = await _context.Guests
                                     .Where(g => g.CustomerId.ToString() == cID && g.EventId.ToString() == eID).FirstOrDefaultAsync();
                if (check == "0")
                {
                    guest.Attended = false;
                }
                else
                {
                    guest.Attended = true;
                }
                try
                {
                    _context.Update(guest);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {

                }
            }
            return Json(true);
        }

Флажок

    <tbody>
            @foreach (var item in Model.GuestsBooked)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Surname)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.FirstName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Email)
                    </td>
                    <td>
                        @Html.CheckBoxFor(modelItem => item.Attended, new { @id = "checkboxID", @cID = item.Id, @eID = Model.Id })
                    </td>
                    <td>
                        @Html.ActionLink("Details", "Details", "Customers", new { id = item.Id }) |
                        @Html.ActionLink("Unbook", "Delete", "GuestBookings", new { id = item.Id, eventId = Model.Id }) |
                    </td>
                </tr>
            }
        </tbody>

1 Ответ

0 голосов
/ 24 декабря 2018

Я вижу несколько проблем с вашим кодом.

Прежде всего, в вашем коде представления вы визуализируете строки таблицы внутри цикла.Внутри строк таблицы вы используете вспомогательный метод CheckBoxFor для визуализации и привязки флажка из значения свойства Attended.Но вы используете перегрузку, когда вы передаете анонимный объект в качестве атрибутов html, и там вы передаете значение атрибута Id как checkboxID.Это означает, что checkboxID будет отображаться как Id для всех флажков.Значения идентификатора должны быть уникальными.Если у вас есть одно и то же значение Id для более чем одного элемента, это недопустимый HTML.Это также приведет к тому, что ваше событие нажатия jQuery будет работать только для первого элемента из коллекции (флажок отображается в первой строке таблицы).

Давайте сначала исправим это.Вы можете использовать другой атрибут для подключения обработчика событий нажатия jQuery.Например, здесь я добавляю атрибут с именем ajaxupdate вместо Id

@Html.CheckBoxFor(modelItem => item.Attended, 
                                 new {  ajaxupdate="true", 
                                        @cID = item.Id, @eID = Model.Id })

С этим изменением будет отображаться HTML-разметка для элемента флажка, как это (некоторые атрибуты опущены длячитаемость).Важной частью здесь является наличие атрибута ajaxupdate.

<input ajaxupdate="true" checked="checked" 
       cid="1" eid="2" name="item.Active" type="checkbox" >

Теперь, чтобы подключить обработчик событий click, мы можем использовать этот селектор атрибутов данных.

$('[ajaxupdate="true"]').on('click', function () {
   // to do : code for ajax call
});

Как только мы исправим это, мы обнаружим, что событие click как минимум выполняет код обработчика события.Но вы заметите, что вызовы ajax получают 400 неверных запросов от сервера.Это происходит потому, что ваш метод действия украшен атрибутом ValidateAntiForgeryToken.Если метод действия оформлен таким образом, платформа проверит отправленные данные запроса и, если не найдет действительный токен защиты от подделки, это будет считаться неверным запросом, а ответ 400 будет отправлен обратно.

Чтобы устранить эту проблему, вы можете явно прочитать значение __RequestVerificationToken скрытого ввода (генерируемого вызовом метода @Html.AntiForgeryToken() в вашем представлении) и отправить его в заголовки вашего запроса ajax.

var t = $("input[name='__RequestVerificationToken']").val();

$.ajax({  url: '@Url.Action("Attending", "Home")',
          type: 'POST',
          headers:
                {
                    "RequestVerificationToken": t
                },
        //existing code for ajax
       })

Другойопция заключается в удалении ValidateAntiForgeryToken.Но нанося удар по безопасности. '

Теперь с помощью вышеуказанного шага мы должны исправить нашу проблему с 400 ответами.Теперь вы, вероятно, получите 500 Внутренняя ошибка сервера, потому что вы получаете некоторую ошибку нулевой ссылки, потому что параметры вашего метода действия неправильно связаны с ожидаемыми значениями, а ваш запрос LINQ может возвращать вам нулевой объект, и вы пытаетесь обновить Attended значение свойства этого объекта без предварительной проверки, является ли он объектом NULL или нет.

Давайте сначала исправим код на стороне клиента.Внутри обработчика события щелчка флажка выражение this представляет элемент флажка, который был нажат.В своем коде бритвы вы устанавливаете значения cID и eID в качестве атрибутов элемента.Так что вы должны читать те, у кого есть метод attr.Также вам не нужно отправлять строковую версию JSON.Просто передайте объект JavaScript как свойство data.

Таким образом, окончательная очищенная версия клиентского кода будет

$(function () {

    $('[ajaxupdate="true"]').on('click', function () {
        var t = $("input[name='__RequestVerificationToken']").val();
        var $this = $(this);
        $.ajax({
            url: '@Url.Action("Attending", "GuestBookings")',
            type: 'POST',
            headers:
            {
                "RequestVerificationToken": t
            },
            data: {
                "cID": $this.attr('cID'),
                "eID": $this.attr('eID'),
                "check": $this.is(':checked') ? 1 : 0
            },
            success: function(result) {
                alert("Succeeded post");
                console.log(result);
            },
            error: function(xhr,status,errorThrown) {
                alert("Failed to post");
                console.log(errorThrown);
            }
        });
    });

});

Еще одно предложение, которое у меня есть, - использовать правильные типы вваш код на стороне сервера.Вы используете тип string для своих параметров, а затем выполняете вызов ToString() для своих числовых свойств для сравнения (с предикатом в предложении Where).Вместо этого используйте соответствующий числовой тип в качестве параметра.

public async Task<IActionResult> Attending(int cID, int eID, int check)
{
    var guest = await _context.Guests
                              .Where(g => g.CustomerId == cID 
                                       && g.EventId == eID)
                              .FirstOrDefaultAsync();
    if(guest!=null)
    {
       guest.IsActive = check == 0;
       try
       {
           _context.Update(guest);
           await _context.SaveChangesAsync();
       }
       catch (Exception ex)
       {
          // Make sure to log the exception and not leak the ToString version to client.
          return Json(new { status = false, message = ex.ToString() });
       }
       return Json(new { status = true, message = "Updated" });
    }
    return Json(new { status = false, message = "Customer not found!" });
}

В приведенном выше коде я возвращаю объект JSON со свойством status и message обратно клиенту.В случае использования исключения я отправляю версию исключения ToString() в свойстве сообщения.Это следует делать только в том случае, если вы хотите увидеть это на стороне клиента (в основном во время разработки).Когда вы отправляете его в производство, вы не хотите передавать эту информацию клиенту.Вместо этого зарегистрируйте его.

Внутри обработчика success вызова ajax вы можете при необходимости проверить свойство status или message.

success: function(result) {
    alert(result.message);                   
},
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...