如何在 Laravel 5.3 中修复 AJAX 模态形式
How to fix AJAX modal form in Laravel 5.3
我已将我的应用程序从 Laravel 4.2 升级到 Laravel 5.3。在列出引文的索引页上,我有一个 AJAX 模态表单来编辑或查看引文的登录凭据。这在 Laravel 4.2 中运行良好,但我无法在 5.3 中正常运行。在谷歌搜索和尝试不同的东西大约 5 小时后,我想我会 post 在这里,这样比我更有经验的人可以给我指明正确的方向。
这是索引页上的link:
<a style="cursor: pointer; " title= "Login Credentials" data-loopback="cit-pg-1" data-citationid="1079" class="getCitationdetails"><span class="glyphicon glyphicon-lock " title="Login Credentials"></span></a>
这是 JavaScript:
<script type="text/javascript">
$(document).on('click','.getCitationdetails',function(){
var citationid = $(this).data('citationid');
var loopback = $(this).data('loopback');
$.ajax({
url : '/citation-password',
type:'post',
data : {citationid :citationid, loopback :loopback},
success:function(resp){
$('#AppendLoginDetails').html(resp);
$('#LoginCredentialsModal').modal('show');
$('.loadingDiv').hide();
},
error:function(){
alert('Error');
}
})
})
这是我的路线:
Route::match(['get', 'post'], '/citation-password', 'CitationsController@citationpassword');
这里是在 get 上生成表单并在 post 上保存数据的 Controller 方法:
public function citationpassword()
{
if (Request::ajax()) {
$data = Request::all();
if (!$data['citationid']) {
return redirect('/citations')
->with('flash-danger', 'Missing citation id for Login credentials form!!');
}
// Save loopback variable if we have it in order to return user to the page where they came from; default return location is citations
$loopback = 'citations';
if (array_key_exists("loopback", $data)) {
$loopback = $data['loopback'];
}
$getcitationdetails = Citation::where('id', $data['citationid'])->select('id', 'site_id', 'username', 'password', 'login_email', 'login_notes')->first();
$getcitationdetails = json_decode(json_encode($getcitationdetails), true);
$getsitedetails = Site::where('id', $getcitationdetails['site_id'])->select(
'id',
'directory_username',
'directory_password',
'security_questions',
'email_account',
'email_account_password',
'email_account_name',
'google_user',
'google_pwd',
'name_of_google_account'
)->first();
$getsitedetails = json_decode(json_encode($getsitedetails), true);
$response ="";
$response .= '<form action="'.url('/citation-password').'" method="post">
<div class="modal-body">';
if (!empty($getsitedetails['directory_username'])) {
$response .= '<div class="form-group">
<label for="recipient-name" class="col-form-label">Default login credentials for this site:</label>
<p>Username: '.$getsitedetails['directory_username'].'
<br />Password: '.$getsitedetails['directory_password'].'
<br />Email account: '.$getsitedetails['email_account'].'
<br />Email password: '.$getsitedetails['email_account_password'].'
<br />Name on email account: '.$getsitedetails['email_account_name'].'
<br />Default security questions: '.$getsitedetails['security_questions'].'</p>
<p>Gmail account: '.$getsitedetails['google_user'].'
<br />Gmail password: '.$getsitedetails['google_pwd'].'
<br />Name on Gmail account: '.$getsitedetails['name_of_google_account'].'</p>
</div>';
}
$response .= '
<input type="hidden" name="_token" value="'.csrf_token() .'" />
<input type="hidden" name="citation_id" value="'.$data['citationid'].'" />
<input type="hidden" name="loopback" value="'.$loopback.'" />
<div class="form-group">
<label for="recipient-name" class="col-form-label">Username:</label>
<input type="text" class="form-control" name="username" value="'.$getcitationdetails['username'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Password:</label>
<input type="text" class="form-control" name="password" value="'.$getcitationdetails['password'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Login email used:</label>
<input type="text" class="form-control" name="login_email" value="'.$getcitationdetails['login_email'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Login notes:</label>
<textarea class="form-control" style="height:130px;" name="login_notes">'.$getcitationdetails['login_notes'].'</textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-success" id="success">Save</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</form>';
return $response;
} else {
// The popup modal has posted back here; process the data
$data = Request::all();
// Handle & translate loopback; returning user to the page where they came from
$loopback = 'citations';
if ($data['loopback']) {
$loopback = $data['loopback'];
// Translate pages it came from
$trackLoopback = new trackLoopback();
$loopback = $trackLoopback->translate($loopback);
}
$updatecitation = Citation::find($data['citation_id']);
$updatecitation->username = $data['username'];
$updatecitation->password = $data['password'];
$updatecitation->save();
return redirect($loopback)
->with('flash-success', 'Login credentials have been updated successfully!');
}
}
为了隔离错误,我什至简化了控制器中的表单,如下所示:
public function citationpassword()
{
if (Request::ajax()) {
return '<p>This is the modal form!</p>';
} else {
// The popup modal has posted back here; process the data
$data = Request::all();
// Handle & translate loopback; returning user to the page where they came from
$loopback = 'citations';
if ($data['loopback']) {
$loopback = $data['loopback'];
// Translate pages it came from
$trackLoopback = new trackLoopback();
$loopback = $trackLoopback->translate($loopback);
}
$updatecitation = Citation::find($data['citation_id']);
$updatecitation->username = $data['username'];
$updatecitation->password = $data['password'];
$updatecitation->save();
return redirect($loopback)
->with('flash-success', 'Login credentials have been updated successfully!');
}
}
并且还简化了这条路线:
Route::get('/citation-password', 'CitationsController@citationpassword');
但是当我点击 link 时我得到的只是一个弹出通知,"Error."
我对 AJAX 没有经验。如何让表单显示在 Laravel 5.3 中?
And/or,如何更改 JavaScript 函数,使其显示实际错误而不是 "Error" 通知? (我尝试了在 Whosebug 上找到的多种方法来显示错误,但所有这些方法都不会导致错误通知;只是一个空白页面。而且,我也没有成功让我的 Firefox 调试器显示错误。)
谢谢!
调试 JavaScript 的正确方法是 post 这样的错误:
<script type="text/javascript">
$(document).on('click','.getCitationdetails',function(){
var citationid = $(this).data('citationid');
var loopback = $(this).data('loopback');
$.ajax({
url : '/citation-password',
type:'post',
data : {citationid :citationid, loopback :loopback},
success:function(resp){
$('#AppendLoginDetails').html(resp);
$('#LoginCredentialsModal').modal('show');
$('.loadingDiv').hide();
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
}
})
})
执行此操作后,您会发现该错误与缺少表单的 CsrfToken 有关。 [实际的错误消息来自 Laravel 框架:Illuminate\Session\TokenMismatchException: 在文件 /home/reviewsites/moxy53/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php 的第 6 行] 因为 get 和 post 动词都使用同样的路线,Laravel 需要 CsrfToken before 生成带有 Csrf 字段的表单。
可以(但 不 推荐!)通过编辑 App\Http\Middleware\VerifyCsrfToken.php 从 CSRF 保护中排除此路由,但有以下例外情况:
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/citation-password',
];
但是,更好的方法是添加令牌。正确的是,由于您使用 post 方法将数据值发送到控制器,因此您不能使用控制器在表单中生成令牌字段。因此,解决方案是将 html 从控制器中取出并放入 blade 中。这些行:
$response .= '<form action="'.url('/citation-password').'" method="post">
<div class="modal-body">';
...
</div>
</form>';
不应该在控制器生成的 $response 中,而应该在 blade 本身的模态 div 中。 THEN,可以在blade中添加CSRF字段,这样:
<form action="{{url('/citation-password')}}" method="post">
{{ csrf_field() }}
<div class="modal-body" id="AppendLoginDetails">
</div>
</form>
我已将我的应用程序从 Laravel 4.2 升级到 Laravel 5.3。在列出引文的索引页上,我有一个 AJAX 模态表单来编辑或查看引文的登录凭据。这在 Laravel 4.2 中运行良好,但我无法在 5.3 中正常运行。在谷歌搜索和尝试不同的东西大约 5 小时后,我想我会 post 在这里,这样比我更有经验的人可以给我指明正确的方向。
这是索引页上的link:
<a style="cursor: pointer; " title= "Login Credentials" data-loopback="cit-pg-1" data-citationid="1079" class="getCitationdetails"><span class="glyphicon glyphicon-lock " title="Login Credentials"></span></a>
这是 JavaScript:
<script type="text/javascript">
$(document).on('click','.getCitationdetails',function(){
var citationid = $(this).data('citationid');
var loopback = $(this).data('loopback');
$.ajax({
url : '/citation-password',
type:'post',
data : {citationid :citationid, loopback :loopback},
success:function(resp){
$('#AppendLoginDetails').html(resp);
$('#LoginCredentialsModal').modal('show');
$('.loadingDiv').hide();
},
error:function(){
alert('Error');
}
})
})
这是我的路线:
Route::match(['get', 'post'], '/citation-password', 'CitationsController@citationpassword');
这里是在 get 上生成表单并在 post 上保存数据的 Controller 方法:
public function citationpassword()
{
if (Request::ajax()) {
$data = Request::all();
if (!$data['citationid']) {
return redirect('/citations')
->with('flash-danger', 'Missing citation id for Login credentials form!!');
}
// Save loopback variable if we have it in order to return user to the page where they came from; default return location is citations
$loopback = 'citations';
if (array_key_exists("loopback", $data)) {
$loopback = $data['loopback'];
}
$getcitationdetails = Citation::where('id', $data['citationid'])->select('id', 'site_id', 'username', 'password', 'login_email', 'login_notes')->first();
$getcitationdetails = json_decode(json_encode($getcitationdetails), true);
$getsitedetails = Site::where('id', $getcitationdetails['site_id'])->select(
'id',
'directory_username',
'directory_password',
'security_questions',
'email_account',
'email_account_password',
'email_account_name',
'google_user',
'google_pwd',
'name_of_google_account'
)->first();
$getsitedetails = json_decode(json_encode($getsitedetails), true);
$response ="";
$response .= '<form action="'.url('/citation-password').'" method="post">
<div class="modal-body">';
if (!empty($getsitedetails['directory_username'])) {
$response .= '<div class="form-group">
<label for="recipient-name" class="col-form-label">Default login credentials for this site:</label>
<p>Username: '.$getsitedetails['directory_username'].'
<br />Password: '.$getsitedetails['directory_password'].'
<br />Email account: '.$getsitedetails['email_account'].'
<br />Email password: '.$getsitedetails['email_account_password'].'
<br />Name on email account: '.$getsitedetails['email_account_name'].'
<br />Default security questions: '.$getsitedetails['security_questions'].'</p>
<p>Gmail account: '.$getsitedetails['google_user'].'
<br />Gmail password: '.$getsitedetails['google_pwd'].'
<br />Name on Gmail account: '.$getsitedetails['name_of_google_account'].'</p>
</div>';
}
$response .= '
<input type="hidden" name="_token" value="'.csrf_token() .'" />
<input type="hidden" name="citation_id" value="'.$data['citationid'].'" />
<input type="hidden" name="loopback" value="'.$loopback.'" />
<div class="form-group">
<label for="recipient-name" class="col-form-label">Username:</label>
<input type="text" class="form-control" name="username" value="'.$getcitationdetails['username'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Password:</label>
<input type="text" class="form-control" name="password" value="'.$getcitationdetails['password'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Login email used:</label>
<input type="text" class="form-control" name="login_email" value="'.$getcitationdetails['login_email'].'" autocomplete="off">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Login notes:</label>
<textarea class="form-control" style="height:130px;" name="login_notes">'.$getcitationdetails['login_notes'].'</textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-success" id="success">Save</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</form>';
return $response;
} else {
// The popup modal has posted back here; process the data
$data = Request::all();
// Handle & translate loopback; returning user to the page where they came from
$loopback = 'citations';
if ($data['loopback']) {
$loopback = $data['loopback'];
// Translate pages it came from
$trackLoopback = new trackLoopback();
$loopback = $trackLoopback->translate($loopback);
}
$updatecitation = Citation::find($data['citation_id']);
$updatecitation->username = $data['username'];
$updatecitation->password = $data['password'];
$updatecitation->save();
return redirect($loopback)
->with('flash-success', 'Login credentials have been updated successfully!');
}
}
为了隔离错误,我什至简化了控制器中的表单,如下所示:
public function citationpassword()
{
if (Request::ajax()) {
return '<p>This is the modal form!</p>';
} else {
// The popup modal has posted back here; process the data
$data = Request::all();
// Handle & translate loopback; returning user to the page where they came from
$loopback = 'citations';
if ($data['loopback']) {
$loopback = $data['loopback'];
// Translate pages it came from
$trackLoopback = new trackLoopback();
$loopback = $trackLoopback->translate($loopback);
}
$updatecitation = Citation::find($data['citation_id']);
$updatecitation->username = $data['username'];
$updatecitation->password = $data['password'];
$updatecitation->save();
return redirect($loopback)
->with('flash-success', 'Login credentials have been updated successfully!');
}
}
并且还简化了这条路线:
Route::get('/citation-password', 'CitationsController@citationpassword');
但是当我点击 link 时我得到的只是一个弹出通知,"Error."
我对 AJAX 没有经验。如何让表单显示在 Laravel 5.3 中?
And/or,如何更改 JavaScript 函数,使其显示实际错误而不是 "Error" 通知? (我尝试了在 Whosebug 上找到的多种方法来显示错误,但所有这些方法都不会导致错误通知;只是一个空白页面。而且,我也没有成功让我的 Firefox 调试器显示错误。)
谢谢!
调试 JavaScript 的正确方法是 post 这样的错误:
<script type="text/javascript">
$(document).on('click','.getCitationdetails',function(){
var citationid = $(this).data('citationid');
var loopback = $(this).data('loopback');
$.ajax({
url : '/citation-password',
type:'post',
data : {citationid :citationid, loopback :loopback},
success:function(resp){
$('#AppendLoginDetails').html(resp);
$('#LoginCredentialsModal').modal('show');
$('.loadingDiv').hide();
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
}
})
})
执行此操作后,您会发现该错误与缺少表单的 CsrfToken 有关。 [实际的错误消息来自 Laravel 框架:Illuminate\Session\TokenMismatchException: 在文件 /home/reviewsites/moxy53/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php 的第 6 行] 因为 get 和 post 动词都使用同样的路线,Laravel 需要 CsrfToken before 生成带有 Csrf 字段的表单。
可以(但 不 推荐!)通过编辑 App\Http\Middleware\VerifyCsrfToken.php 从 CSRF 保护中排除此路由,但有以下例外情况:
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/citation-password',
];
但是,更好的方法是添加令牌。正确的是,由于您使用 post 方法将数据值发送到控制器,因此您不能使用控制器在表单中生成令牌字段。因此,解决方案是将 html 从控制器中取出并放入 blade 中。这些行:
$response .= '<form action="'.url('/citation-password').'" method="post">
<div class="modal-body">';
...
</div>
</form>';
不应该在控制器生成的 $response 中,而应该在 blade 本身的模态 div 中。 THEN,可以在blade中添加CSRF字段,这样:
<form action="{{url('/citation-password')}}" method="post">
{{ csrf_field() }}
<div class="modal-body" id="AppendLoginDetails">
</div>
</form>