jquery 如何防止在Laravel 8应用中默认提交通过Ajax加载的表单?

tpgth1q7  于 5个月前  发布在  jQuery
关注(0)|答案(4)|浏览(54)

我在Laravel 8中做了一个blogging application。我目前正在通过jQuery(v3.5.0)AJAX添加 * 评论回复 *。
comment-form.blade.php中,我有:

<div class="form-wrapper">
  <div class="alert-box-ajax alert-box alert-box--success">
    Your comment is pending
  </div>

  <div class="alert-box-ajax alert-box alert-box--error">
    Failed to add comment!
  </div>

  <form class="commentForm" method="post" action="{{ route('comment.submit') }}" autocomplete="off" novalidate>
    @csrf
      <fieldset>
        <input type="hidden" name="article_id" value="{{ isset($article->id) ? $article->id : $article_id }}">
        <input type="hidden" name="parent_id" value="{{ $comment->id ?? '' }}">

        <div class="message form-field">
            <textarea name="msg" id="message" class="h-full-width" placeholder="Your Message" required></textarea>

            @error('msg')
            <p class="help-block text-danger">{{ $message }}</p>
            @enderror
        </div>
        <br>
        <input name="submit" id="submit" class="btn btn--primary btn-wide btn--large h-full-width" value="Add Comment" type="submit">
      </fieldset>
  </form>
</div>

字符串
当然,上面的模板对每个评论都重复,这样回复就可以添加到任何评论中。
回复通过jQuery Ajax提交:

$(".commentForm").each(function () {
    var form = $(this);
    form.validate({
        errorElement: "p",
        errorClass: "help-block text-danger",

        submitHandler: function (_form, event) {
            event.preventDefault();
            var $fields = form.find("textarea"),
                url = form.attr("action"),
                data = form.serialize();
            $.ajax({
                dataType: "json",
                type: "post",
                url: url,
                data: data,
                cache: false,
                success: function (response) {
                  if (response.status === 'success') {
                    form.closest(".form-wrapper").find(".alert-box--success").slideDown(250).delay(2500).slideUp(250)
                        .slideDown(250)
                        .delay(2500)
                        .slideUp(250);
                  $fields.val("");
                  } else {
                    form.closest(".form-wrapper").find(".alert-box--error").slideDown(250).delay(2500).slideUp(250)
                        .slideDown(250)
                        .delay(2500)
                        .slideUp(250);
                  }
                },
                error: function (err) {    
                  console.log(err);
                },
            });
        },
    });
});


问题
有一个选项可以为每个帖子初始加载最多10个comemnts,其余的通过Ajax调用加载到页面滚动中。
当此选项处于活动状态时,上面的脚本无法阻止通过Ajax加载的表单的默认行为。

**!注意:**问题不是提交事件,而是提交事件的 * 预防 *。

常见问题

1.是什么导致了这个问题?
1.解决这个问题最可靠的方法是什么?

q7solyqu

q7solyqu1#

这将工作,无论有多少形式为每个评论,因为每个形式将属于单一的评论。

$(document).on("submit", ".commentForm", function (event) {
    event.preventDefault();

    var form = $(this);
    form.validate({
      errorElement: "p",
      errorClass: "help-block text-danger",

      submitHandler: function (_form, event) {
        event.preventDefault();
        var $fields = form.find("textarea"),
          url = form.attr("action"),
          data = form.serialize();
        $.ajax({
          dataType: "json",
          type: "post",
          url: url,
          data: data,
          cache: false,
          success: function (response) {
            if (response.status === 'success') {
              form.closest(".form-wrapper").find(".alert-box--success").slideDown(250).delay(2500).slideUp(250)
                .slideDown(250)
                .delay(2500)
                .slideUp(250);
              $fields.val("");
            } else {
              form.closest(".form-wrapper").find(".alert-box--error").slideDown(250).delay(2500).slideUp(250)
                .slideDown(250)
                .delay(2500)
                .slideUp(250);
            }
          },
          error: function (err) {
            console.log(err);
          },
        });
      },
    });
  });

字符串

pu82cl6c

pu82cl6c2#

您遇到的问题是由于jQuery .each()函数和.validate()方法只应用于代码运行时存在于DOM中的元素。这意味着稍后(通过AJAX)添加到DOM的任何元素(在您的情况下,注解表单)都不会应用这些方法。
要解决这个问题,您可以使用事件委托。事件委托允许您将单个事件侦听器附加到父元素,该侦听器将为匹配选择器的所有后代触发,无论这些后代现在存在还是将来添加。
以下是如何修改jQuery代码以使用事件委托:

$(document).on('submit', '.commentForm', function(event) {
    event.preventDefault();

    var form = $(this);
    var $fields = form.find("textarea"),
        url = form.attr("action"),
        data = form.serialize();

    $.ajax({
        dataType: "json",
        type: "post",
        url: url,
        data: data,
        cache: false,
        success: function (response) {
            if (response.status === 'success') {
                form.closest(".form-wrapper").find(".alert-box--success").slideDown(250).delay(2500).slideUp(250)
                    .slideDown(250)
                    .delay(2500)
                    .slideUp(250);
                $fields.val("");
            } else {
                form.closest(".form-wrapper").find(".alert-box--error").slideDown(250).delay(2500).slideUp(250)
                    .slideDown(250)
                    .delay(2500)
                    .slideUp(250);
            }
        },
        error: function (err) {    
            console.log(err);
        },
    });
});

字符串
我是这么想的。新代码:

$(document).on('submit', '.commentForm', function (event) {
    event.preventDefault();

    var form = $(this);
    form.validate({
      errorElement: "p",
      errorClass: "help-block text-danger",
      rules: {
        msg: "required",
      },
      messages: {
        msg: "Enter a comment",
      }
    });

    // Check if the form is valid
    if (!form.valid()) {
      return;
    }

    var $fields = form.find("textarea"),
      url = form.attr("action"),
      data = form.serialize();

    $.ajax({
      dataType: "json",
      type: "post",
      url: url,
      data: data,
      cache: false,
      success: function (response) {
        if (response.status === 'success') {
          form.closest(".form-wrapper").find(".alert-box--success").slideDown(250).delay(2500).slideUp(250)
            .slideDown(250)
            .delay(2500)
            .slideUp(250);
          $fields.val("");
        } else {
          form.closest(".form-wrapper").find(".alert-box--error").slideDown(250).delay(2500).slideUp(250)
            .slideDown(250)
            .delay(2500)
            .slideUp(250);
        }
      },
      error: function (err) {
        console.log(err);
      },
    });
});

91zkwejq

91zkwejq3#

这个问题已经在评论中解释过了。你所展示的JavaScript在页面加载时运行,那里的选择器只会匹配页面加载时存在的元素。如果你稍后动态添加元素,Javascript不会再次运行,那些选择器不会匹配它们。
在这种情况下,这意味着$(".commentForm")只匹配那些在页面加载时存在的具有该类的表单,因此只有这些表单才会应用验证代码。当您稍后向页面添加新的$(".commentForm") s时,在页面加载时运行的JS不会再次为新表单运行,并且它们根本没有验证。提交这些表单不会运行任何JavaScript,它们只是正常提交,这就是你所看到的
为了解决这个问题,你可以让你的验证成为一个可以随时调用的函数,例如:

// Function to initialise validation on the passed form element.  
// $form is a jQuery object.  Note you now need to use $form to
// reference the form being validated, eg $form.find("textarea"), 
// $form.closest(), etc, inside the function.
function commentFormValidation($form) {
    $form.validate({
        // ... your validation code. 
        submitHandler: function (_form, event) {
            event.preventDefault();
            let $fields = $form.find("textarea");
            $.ajax({
                // ...
            });
        },
    });
}

// At page load, apply validation to each form that exists at that time
$(".commentForm").each(function () {
    commentFormValidation($(this));
});

字符串
现在你可以在一个新表单被添加到DOM的时候动态地添加验证。你还没有给我们展示添加新表单的代码,但是为了演示的目的,假设你正在克隆一些主表单模板,可能是这样的:

// Pseudo/simplified code, this is just for demonstration
let $template = $('#commentForm-template');   // some master template
let $copy = $template.clone();                // create a copy
$copy.appendTo('.someContainer');             // add it to DOM somewhere
commentFormValidation($copy);                 // add validation to it


无论代码是什么样子,你需要做的唯一重要的部分就是在新表单上调用新的验证函数:

commentFormValidation($newFormJQueryObject);


类似问题供参考:

或者,您也可以使用事件委托来实现这一点,尽管这有点棘手,而且IMO并不是一个整洁的解决方案。
首先,我们需要将事件处理程序附加到页面加载时存在的选择器,并且将成为当前和未来所有表单的父级。让我们称之为.someContainer。接下来我们过滤选择器以仅匹配表单:

$('.someContainer').on('submit', '.commentForm', function(e) {
    e.preventDefault();
    // ...


现在,在该容器内发生的任何submit事件都会触发此处理程序-即使是页面加载后添加的表单。无需添加单独的代码来处理页面加载时存在的表单,这将捕获所有表单。
接下来,我们显然需要添加代码来初始化刚刚提交的表单上的验证。我们可以使用现有的commentFormValidation()函数来完成这一点:

$('.someContainer').on('submit', '.commentForm', function(e) {
    e.preventDefault();
    commentFormValidation($(this));
    // ...


但是有一个问题。提交表单会添加验证,但它实际上不会 * 运行 * 验证。因此,第一次提交表单时,什么都不会发生,因为提交操作已被此处理程序拦截,添加了验证,.
所以我们需要在添加验证后手动运行它,你可以通过在表单上调用the .valid() method来完成--尽管它在这里不起作用,我不知道为什么。
因此,我们可以手动重新提交表单,这将运行验证。
这里有一个演示这种委托方法的工作片段。检查控制台输出以查看发生的各个阶段。

function commentFormValidation($form) {
    $form.validate({
        rules: {
            foo: 'required'
        },
        submitHandler: function (_form, event) {
            event.preventDefault();
            console.log('submitHandler running');
        },
    });
}

$('.someContainer').on('submit', '.commentForm', function(e) {
    e.preventDefault();
    console.log('event handler running');

    // Initialise validation on this form
    commentFormValidation($(this));

    // Manually run the validation on this form - not sure why, does 
    // not work
    // $(this).valid();
    
    // Manually re-submit the form to trigger validation
    $(this).submit();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.validate.min.js"></script>

<div class="someContainer">
    <form class="commentForm">
        <input type="text" name="foo">
        <button>Submit</button>
    </form>
</div>

的字符串

nfzehxib

nfzehxib4#

一个简单的解决方法是区分初始化和未初始化的内容。让我们创建一个函数,将其 Package 在代码中,并确保稍微修改代码以初始化未初始化的元素:

function initializeForms() {
    $(".commentForm:not(.initialized)").each(function () {
        var form = $(this);
        form.addClass("initialized"); //We initialized your form, so we mark it as such
        form.validate({
            errorElement: "p",
            errorClass: "help-block text-danger",

            submitHandler: function (_form, event) {
                event.preventDefault();
                var $fields = form.find("textarea"),
                    url = form.attr("action"),
                    data = form.serialize();
                $.ajax({
                    dataType: "json",
                    type: "post",
                    url: url,
                    data: data,
                    cache: false,
                    success: function (response) {
                      if (response.status === 'success') {
                        form.closest(".form-wrapper").find(".alert-box--success").slideDown(250).delay(2500).slideUp(250)
                        .slideDown(250)
                        .delay(2500)
                        .slideUp(250);
                    $fields.val("");
                    } else {
                    form.closest(".form-wrapper").find(".alert-box--error").slideDown(250).delay(2500).slideUp(250)
                        .slideDown(250)
                        .delay(2500)
                        .slideUp(250);
                  }
                },
                error: function (err) {    
                  console.log(err);
                },
            });
        },
    });
});
}

字符串
请确保在页面加载时以及“下一个内容”AJAX完成并追加新表单时调用此函数。
编辑
你还需要小心,因为如果容器的innerHTML被改变,那么所有的事件监听器都会被破坏。所以你需要测试当你加载下一个10个元素时,你的第一个元素是否仍然工作。如果是这样,那么我的初始解决方案就可以工作。如果不是,那么你可以将初始行改为$(".commentForm:not(.initialized)").each(function () {并删除form.addClass("initialized");行。
编辑2
下面是一个创建事件并在容器的.innerHTML`更改后重新创建事件的工作示例:

function customSubmit(evt) {
    evt.preventDefault();
    evt.currentTarget.querySelector("input").value = "clicked me";
}

function customGroupSubmit(container) {
    for (let form of container.querySelectorAll("form")) {
        form.addEventListener("submit", customSubmit);
    }
}

let container = document.querySelector(".container");

customGroupSubmit(container);

document.getElementById("add").addEventListener("click", function() {
    let template = `<div class="commentForm"><form><input type="submit" value="click me"></form></div>`;
    template = template + template + template;
    container.innerHTML += template;
    customGroupSubmit(container);
});
<div class="container">
    <div class="commentForm"><form><input type="submit" value="click me"></form></div>
    <div class="commentForm"><form><input type="submit" value="click me"></form></div>
    <div class="commentForm"><form><input type="submit" value="click me"></form></div>
</div>
<input type="button" id="add" value="add">

的数据

相关问题