我有一个按钮订阅,它应该通过 ajax 向我的控制器提交一个发布请求以插入到我的表中。
我的观点是这样的:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8">
<div class="flash-message"></div>
<div class="card">
<div class="card-header">
<div class="level">
<span class="flex"><a href="{{route('profile',$thread->creator->name)}}">{{$thread->creator->name}}</a> posted:
{{$thread->title}}
</span>
@if(auth()->check())
@if($subscription)
<button class="btn btn-secondary" id="unsubscribe">Unsubscribe</button>
@else
<button class="btn btn-danger" id="subscribe">Subscribe</button>
@endif
@endif
@can('update',$thread)
<a href="{{$thread->path()}}/edit" class="btn btn-link">Edit Thread</a>
<form action="{{$thread->path()}}" method="POST">
@csrf
@method('delete')
<button class="btn btn-link" type="submit">Delete Thread</button>
</form>
@endcan
</div>
</div>
<div class="card-body">
{{$thread->body}}
</div>
</div>
..............
我的 app.blade:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!--jQuery/share.js -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>
<script src="{{ asset('js/share.js') }}"></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<style>
body{
padding-bottom:100px;
}
.level{
display: flex;
align-items: center;
}
.flex{
flex: 1;
}
</style>
</head>
<body>
<div id="app">
@include('layouts.nav')
<main class="py-4">
@yield('content')
</main>
<flash message="{{session('flash')}}"></flash>
</div>
</body>
<style>
.btn-width{
min-width: 70px;
}
</style>
</html>
调用按钮的代码:
<script type="application/javascript">
$(document).ready(function(){
$('#subscribe').click(function(e){
e.preventDefault();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "{{route('subscription.store')}}",
method:'POST',
data: {
thread_id: "{{$thread->id}}",
},
success:function(response){
$('div.flash-message').html(response);
},
error:function(error){
console.log(error);
}
});
});
});
据我所知,没有其他元素与我的按钮共享相同的 ID。而且,我的按钮不在表单提交中,因此不应调用两次。检查开发工具没有显示错误,并且在网络选项卡中,两个请求被相同的发起者调用。
所以,我有点想知道为什么会发生这种情况。 ajax post 请求不应该只提交一次请求吗?
我真的很想深入了解这个问题,因为大多数其他类似问题都调用了两次提交,而我的代码只应该调用一次。相反,它对我的数据库进行了两次插入。
我还能做些什么来找出问题的根本原因?
答案 0 :(得分:1)
您的 javascript 是否有可能以某种方式加载了两次?这将附加两个相同的侦听器,并在单击时发送两次请求。如果您将 console.log 放在事件处理程序中,您是否也看到了两倍?
此外,显然,.click
为与传递给 jQuery 对象的选择器匹配的每个元素添加了一个单独的事件侦听器,而 .on
only adds a single one.。如果你改为这样做会发生什么?
$(document).ready(function () {
$("#subscribe").on("click", function(e) {
e.preventDefault();
$.ajaxSetup({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
});
$.ajax({
url: "{{route('subscription.store')}}",
method: "POST",
data: {
thread_id: "{{$thread->id}}",
},
success: function (response) {
$("div.flash-message").html(response);
},
error: function (error) {
console.log(error);
},
});
});
});
答案 1 :(得分:0)
你调用你的函数两次,一个是在文档准备好,另一个是在按钮点击移除文档
答案 2 :(得分:0)
你试过给 return false 吗?像这样:
$(document).ready(function(){
let subscribeClick = function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "{{route('subscription.store')}}",
method:'POST',
data: {
thread_id: "{{$thread->id}}",
},
success:function(response){
$('div.flash-message').html(response);
},
error:function(error){
console.log(error);
}
});
return false;
}
$('#subscribe').click(function(e){
e.preventDefault();
e.stopImmediatePropagation();
subscribeClick();
});
});
答案 3 :(得分:0)
您可以尝试以下选项:
(1) 在你的 ajax 调用中使用 async: false
来停止其他代码的执行,直到你收到当前 ajax 调用的响应。
$('#subscribe').click(function(e) {
e.preventDefault();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "{{route('subscription.store')}}",
method: 'POST',
async: false,
data: {
thread_id: "{{$thread->id}}",
},
success: function(response) {
$('div.flash-message').html(response);
},
error: function(error) {
console.log(error);
}
});
});
或
(2) 您可以使用 Event 接口的 stopPropagation()
方法,以防止当前事件在捕获和冒泡阶段进一步传播。
$('#subscribe').click(function(e) {
e.preventDefault();
e.stopPropagation();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "{{route('subscription.store')}}",
method: 'POST',
async: false,
data: {
thread_id: "{{$thread->id}}",
},
success: function(response) {
$('div.flash-message').html(response);
},
error: function(error) {
console.log(error);
}
});
});
或
(3) 使用存储请求状态的变量。
var isLoading = false;
$(document).ready(function() {
$('#subscribe').click(function(e) {
if (!isLoading ) {
isLoading = true; //make true when request starts
e.preventDefault();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: "{{route('subscription.store')}}",
method: 'POST',
data: {
thread_id: "{{$thread->id}}",
},
success: function(response) {
$('div.flash-message').html(response);
isLoading = false; //make false when response is received
},
error: function(error) {
console.log(error);
isLoading = false; //make false when error is received
}
});
}
});
});