Не отправляется запрос при использовании другого типа кнопки

134
02 июля 2019, 19:30

Подскажите пожалуйста почему если использовать Ajax.BeginForm, тогда нужно использовать кнопку с типом submit для отправки формы, а если использовать с помощью jquery $.ajax тогда можно просто button и форма всё равно отправиться. В чём разница? Код с хелпером:

<div>
    @using (Ajax.BeginForm("BookSearch", new AjaxOptions
    {
        UpdateTargetId = "results"
    }))
    {
        <input type="text" name="name" />
        <input type="submit" value="Поиск" />
    }
    <div id="results"></div>
</div>

Код с jquery:

<div>
    <input id="txt" type="text" name="name" />
    <input id="btn" type="button" value="Поиск" />
    <div id="results"></div>
</div>
@section scripts {
    <script type="text/javascript">
        $('#btn').on('click', function () {
            $.ajax({
                type: "POST",
                url: "/Home/BookSearch",
                data: { "name": $('#txt').val() },
                success: function (data) {
                    $('#results').html(data);
                },
                error: function (xhr) {
                    alert(xhr.status + 'Ошибка');
                },
            });
        });
    </script>
}

Вот так работают оба варианта, но если я в первом случае так же сделаю type у инпута, button, тогда запрос не отработает. Почему?

Answer 1

Давайте сначала отвлечёмся от ajax и обратимся к обычным html-формам. Если на веб-странице будет расположена веб-форма (<form></form>), то все стандарты на html говорят о том, что отправка формы происходит по нажатии на кнопку с type=submit, которых может быть более одной. В более новых стандартах кстати упоминается, что не только кнопки могут быть submittable elements формы.

Я не видел браузеров, которые бы отклонялись от стандартов в этом плане, всё очевидно: кликнул по кнопке submit — пошла отправка формы, всё остальное не вызывает отправку формы.

Формы в asp.net mvc вы можете вставить либо вручную (<form method="...) создав разметку, либо использовав helper для формы @Html.Form — который точно так же вставляет те же самые <form ....

Вот исходный код для этого хелпера:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
{
  ...
  return htmlHelper.FormHelper(url, method, htmlAttributes);
}
private static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
  TagBuilder tagBuilder = new TagBuilder("form");
  tagBuilder.MergeAttributes<string, object>(htmlAttributes);
  tagBuilder.MergeAttribute("action", formAction);
  tagBuilder.MergeAttribute(nameof (method), HtmlHelper.GetFormMethodString(method), true);
  bool flag = htmlHelper.ViewContext.ClientValidationEnabled && !htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled;
  if (flag)
    tagBuilder.GenerateId(htmlHelper.ViewContext.FormIdGenerator());
  htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
  MvcForm mvcForm = new MvcForm(htmlHelper.ViewContext);
  if (!flag)
    return mvcForm;
  htmlHelper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"];
  return mvcForm;
}
internal static void EndForm(ViewContext viewContext)
{
  viewContext.Writer.Write("</form>");
  viewContext.OutputClientValidation();
  viewContext.FormContext = (FormContext) null;
}

То есть никакой особой магии когда вы пишете @using(Html.BeginForm(... нет. Я как-то отвечал на вопрос, можно ли сделать подобный хелпер самостоятельно — и в принципе, вы сами можете потренироваться в создании кастомных хелперов.

Давайте теперь вернёмся к ajax. Вы в коде пишете @using(Ajax.BeginForm(... — и эта конструкция вызывает аналогичный код, который вписывает <form method="..., никаких изменений.

Важно:

Давайте определимся: отправка формы срабатывает только в случае нажатия на submittable элементы!

И неважно, ajax у вас или нет.

Но видите ли, никто не запретит вам на любом элементе формы сделать вызов любой javascript-функции. Можно сделать alert() или console.log(), раскрасить элементы или вызвать эфффект fade. Или — вызывать this.form.submit() Ну и даже (sic!) — сделать запрос к другому серверу. Собственно второй пример у вас именно такой: вы могли хоть onMouseOver или onKeyUp повесить вызов некоторого ajax-запроса, но навесили на событие onClick, которое вам кажется, что это событие onSubmit (для кнопок type=submit это действительно так!). Ну а что форма не отправится - ну так и не надо, действия оказываются выполненными практически одинаково.

Чисто гипотетически, я могу предположить, когда это может выстрелить, но такой случай вам в реальной практике не понадобится и так в ногу себе вряд ли получится выстрелить.

Никто не мешает вам сделать две кнопки:

  • кнопка submit будет отправлять запрос на какой-то контроллер, который будет парсить данные считая что запрос приходит application/x-www-form-urlencoded (именно так отправляются в большинстве случаев формы)
  • кнопка type=button будет отправлять запрос на какой-то другой экшн и в POST-запросе данные будут в json (тип application/json)

Вот тут мы разбирали как раз очень похожий случай, когда было написано не:

$('#btn').on('click', function () {
            $.ajax({
                type: "POST",

А было что-то типа (там использовалась библиотека axios, я для наглядности привожу эквивалент):

$('#btn').on('click', function () {
            $.ajax({
                type: "POST",
                contentType:"application/json; charset=utf-8",

И напоследок пара слов не о том, что вы спрашивали. Есть одна очень частая ошибка связанная с написанием ajax, вы её допустили во втором примере.

С учётом того, что "и так всё работает" и "форму отправлять не надо" некоторые вебмастера пишут невалидный код. По html стандарту полагается что элементы типа input и button могут находиться только внутри формы. А где она у вас? Нету вообще.

Правильно вот так:

<div>
    <form ...>
        <input id="txt" type="text" name="name" />
        <input id="btn" type="button" value="Поиск" />
    </form>
    <div id="results"></div>
</div>

Насчёт того, что "ненуачо, работает же". Я не буду говорить о том, вёрстка должна быть валидной — это на совести каждого конкретного специалиста, я буду говорить о том, что зачастую люди ходят на сайты с отключенным javascript. И хотя вряд ли у человека с отключенным js будет полноценная возможность работать с сайтом, но в случае если у вас есть валидная форма с кнопкой submit — у человека остаётся шанс заполнить форму и отправить. А в случае, когда у вас input'ы и submit'ы висят в воздухе — никакого. Подумайте об этом.

Answer 2

Form для получения данных через перезагрузку страницы

Ajax Post для динимаческой отрисовки.

Этот вопрос был решён ранее

READ ALSO
Не удается вычитать поток данных, всегда пуст

Не удается вычитать поток данных, всегда пуст

Пытаюсь скачать видео (любое) с сервиса Sibnet, провел тестирование получения ссылки на видео-файл, и успешно получаю нормальный Url, но при этом,...

154
Action который принимает разное кол-во аргументов

Action который принимает разное кол-во аргументов

Как мне можно присвоить Action'у методы (разные) с разным кол-вом параметров и при этом параметры разные

135
Как получить полное число перед знаком

Как получить полное число перед знаком

Мне нужно распарсить строкуОна может иметь один из вот таких видов:

125
Узнать куда было перенаправление

Узнать куда было перенаправление

Как можно узнать куда был перенаправлен запрос HttpClient если для запроса указывать только запрос заголовков?

154