在 yii2 接口中添加一个 loader/spinner
Adding a loader/spinner to yii2 interface
我有一个视图,其中有两个按钮。单击两个按钮中的任何一个时,都会发出特定请求。
查看
<?php Pjax::begin(); ?>
<?=Html::beginForm(['process'],'post');?>
<?=Html::submitButton('Disconnect', ['id'=>'d','name'=>'dco','class' => 'btn btn-primary']);?>
<?=Html::submitButton('Connect', ['id'=>'r','name'=>'rco','class' => 'btn btn-info']);?>
<br><br>
<div class="pre-scrollable">
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d) {
return ['value' => $d['msn']];
}],
'customer_id',
// 'dept_code:ntext',
'dept_name:ntext',
'sub_div_name',
[
'label' => 'Sub Division Name',
'value' => function ($d) {
return $d->subdiv->name;
},
'filter' => Html::activeDropDownList($searchModel, 'sub_div_code', \common\models\SurveyHescoSubdivision::toArrayList(), ['prompt' => "Sub-Div", 'class' => 'form-control']),
],
'division_name',
'allowed_units',
'msn',
'units_consumed',
[
'label' => 'Disconnected',
'attribute' => 'disconnected',
'format'=>'raw',
'contentOptions' => ['style'=>'text-align:center'],
'value' => function($model){
return $model->disconnected == 1 ? '<span class="glyphicon glyphicon-ok text-success"></span>' : '<span class="glyphicon glyphicon-remove text-danger"></span>';
},
'filter' => Html::activeDropDownList($searchModel, 'disconnected', [''=>'All','1'=>'Yes','0'=>'No'], ['class' => 'form-control']),
],
'active_energy_total_m',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
<?= Html::endForm();?>
<?php Pjax::end(); ?>
控制器
public function actionProcess()
{
$soapUrl = "http://ip:port/HES/services/Request";
$userName = "user";
$password = "123456";
if (isset($_POST['dco']))
{
if(Yii::$app->request->isPost)
{
$data = Yii::$app->request->post('selection'); //checkbox (array)
foreach($data as $value)
{
$msn = $value;
$xml_post_string = /** @lang text */
'//soap request';
$headers = array(
"Content-type: text/xml;charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"Content-length: ".strlen($xml_post_string),
); //SOAPAction: your op URL
$url = $soapUrl;
// PHP cURL for https connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); // the SOAP request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// converting
$response = curl_exec($ch);
curl_close($ch);
$domd=new DOMDocument();
var_dump($response);
if(!$domd->loadXML($response)){
throw new \RuntimeException("failed to parse XML!");
}
$inner_xml=$domd->getElementsByTagName("return")->item(0)->textContent;
if(!($domd2=@DOMDocument::loadXML($inner_xml))){
throw new \RuntimeException("failed to parse inner_xml!");
}
$AsyncReplyFlag=$domd2->getElementsByTagName("AsyncReplyFlag")->item(0)->textContent;
if ($AsyncReplyFlag =='true')
{
$ds = 1;
$disconnected_at = date('Y-m-d H:i:s');
try {
Yii::$app->db->createCommand(/** @lang text */
"update
`accurate_mam`.`daily_log`
set
`disconnected` = '$ds',
`diconnected_at` = '$disconnected_at',
`reconnected_at` = NULL
where `msn` = '$msn' ;
")->execute(); //update master table
Yii::$app->db->createCommand(/** @lang text */
"update
`accurate_mam`.`log_disconnected`
set
`disconnected_at` = '$disconnected_at'
where `msn` = '$msn'")->execute();// update log disconnected table
} catch (Exception $e) {
} // updating the master table
}
}
}
}
}
我想做什么?
单击按钮时,我想显示一个 spinner/loader,它将在发出请求时开始并在请求完成时停止。
备注
我不想为 spinner/loader 添加默认时间。它应该在发送请求时开始并在完成时停止,即当过程完成时
我搜索了很多文章,但找不到完整的实现细节。
更新 1
我找到了一个解决方案 here 并尝试通过执行以下操作来实现它
<style>
#loader {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
background: rgba(0, 0, 0, 0.05) url("<?php \yii\helpers\Url::to('@web/images/25.png', true); ?>") no-repeat center center;
z-index: 10000;
}
</style>
JS
$(document).ready(function () {
$('form').submit(function(e) {
e.preventDefault();
spinner.show();
$.ajax({
url:'$url',
data: $(this).serialize()
type: 'POST',
dataType: 'JSON'
}).done(function(resp) {
spinner.hide();
//alert(resp.status);
});
});
});
面临的问题
现在我可以看到微调器,但过程尚未完成。进一步调试后,我观察到我在提交请求时在 var_dump(isset($_POST['dco']));
die();
中得到 bool(false)
更新 2
我又找到了一个 并尝试做同样的事情
更新两个按钮
<?= Html::submitButton(Yii::t('app', '<i class="fa fa-times"></i> Disconnect'), ['class' => 'btn red', 'name' => 'dco', 'value' => '0']) ?>
<?= Html::submitButton(Yii::t('app', '<i class="fa fa-check"></i> Connect'), ['class' => 'btn blue', 'name' => 'rco', 'value' => '1']) ?>
JS
$('form').submit(function(e) {
e.preventDefault();
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!=="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
spinner.show();
$.ajax({
url:'$url',
data: {data :strValue},
type: 'POST',
dataType: 'JSON'
}).done(function(resp) {
spinner.hide();
//alert(resp.status);
});
});
控制器
if (Yii::$app->request->post()) {
if (Yii::$app->request->post('dco') == 0) {
//Code for value 0
}
if (Yii::$app->request->post('rco') == 1) {
//Code for value 1
}
}
面临的问题
当我点击这两个按钮中的任何一个时,它总是点击 dco
检查,即 if (Yii::$app->request->post('dco') == 0)
它没有点击 rco
条件
一定是我遗漏了什么。
非常感谢任何帮助。
<?php
$this->registerJs(<<<JS
$(document).on('pjax:send', function() {
$('#loading').show();
});
$(document).on('pjax:complete', function() {
$('#loading').hide();
});
JS
);
?>
示例:fontawesome(或者可以使用图片....)
<i id='loading' class='fa fa-spinner fa-pulse' style='display:none;'></i>
您也可以通过变量(在控制器中)执行此操作。
我的理解
查看您当前的实现,您使用的是普通表单提交,尽管包装在 Pjax
容器内,但您尚未通过 Pjax
为您的表单启用表单提交,并希望显示微调器或加载程序将显示,直到您向某些 API 发送 curl
请求的操作的请求完成。
限制
您需要了解的一点是,如果您进行正常的表单提交并尝试显示您在内部执行的某个过程的微调器,您的 controller/action
将无法工作,因为视图尚未呈现并且您的微调器相关的任何 javascript
或 CSS
尚未在浏览器中呈现,也不会显示。
解决方案
另一方面,如果您使用 ajax
或 pjax
提交表单,因为您已经将表单包装在 Pjax
容器中,您可以使用 Pjax
启用 AdminBSBTheme 微调器的事件,它使用 CSS 仅显示微调器。
这不仅适用于您的 ajax 表单,而且您可以在整个网站上使用它进行正常的页面加载,从而产生不错的效果。一旦 DOM
准备就绪,它会自动隐藏,如果互联网连接速度较慢,它会让事情看起来更一致。
在表单上启用 Pjax
您必须在表单标签中添加 data-pjax="1"
属性以启用 Pjax
表单提交默认情况下它不会工作,因此请继续并更改以下行以启用 Pjax
提交表单。
<?php echo Html::beginForm(['process'],'post', ['data' => ['pjax' => 1]);?>
为 Pjax 启用超时
然后你需要指定 timeout
参数 属性 如果你的 curl
请求需要一点时间最好为 timeout
添加高值 属性 这样它就不会抛出 loading request failed
或 timeout
错误并等待响应。让我们给它 10 seconds
所以如果请求需要 10 secs
才能完成,它应该继续等待,否则如果收到响应则继续
<?php Pjax::begin(['timeout'=>10000]); ?>
微调器集成
现在是旋转器集成的部分,您可以在下面的演示中看到它 运行 它是纯粹基于 CSS 的。
在 views\layouts\main.php
文件中复制下面演示中的 Html
$this->beginBody()
和
在 site.css
文件中添加 css
,或者创建一个单独的文件并包含在 AppAssets.php
文件中。
/ Page Loader ================================= /
.page-loader-wrapper {
z-index: 99999999;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background: #eee;
overflow: hidden;
text-align: center;
}
.page-loader-wrapper p {
font-size: 13px;
margin-top: 10px;
font-weight: bold;
color: #444;
}
.page-loader-wrapper .loader {
position: relative;
top: calc(50% - 30px);
}
/ Preloaders ================================== /
.md-preloader .pl-red {
stroke: #F44336;
}
.md-preloader .pl-pink {
stroke: #E91E63;
}
.md-preloader .pl-purple {
stroke: #9C27B0;
}
.md-preloader .pl-deep-purple {
stroke: #673AB7;
}
.md-preloader .pl-indigo {
stroke: #3F51B5;
}
.md-preloader .pl-blue {
stroke: #2196F3;
}
.md-preloader .pl-light-blue {
stroke: #03A9F4;
}
.md-preloader .pl-cyan {
stroke: #00BCD4;
}
.md-preloader .pl-teal {
stroke: #009688;
}
.md-preloader .pl-green {
stroke: #4CAF50;
}
.md-preloader .pl-light-green {
stroke: #8BC34A;
}
.md-preloader .pl-lime {
stroke: #CDDC39;
}
.md-preloader .pl-yellow {
stroke: #ffe821;
}
.md-preloader .pl-amber {
stroke: #FFC107;
}
.md-preloader .pl-orange {
stroke: #FF9800;
}
.md-preloader .pl-deep-orange {
stroke: #FF5722;
}
.md-preloader .pl-brown {
stroke: #795548;
}
.md-preloader .pl-grey {
stroke: #9E9E9E;
}
.md-preloader .pl-blue-grey {
stroke: #607D8B;
}
.md-preloader .pl-black {
stroke: #000000;
}
.md-preloader .pl-white {
stroke: #ffffff;
}
.preloader {
display: inline-block;
position: relative;
width: 50px;
height: 50px;
-webkit-animation: container-rotate 1568ms linear infinite;
-moz-animation: container-rotate 1568ms linear infinite;
-o-animation: container-rotate 1568ms linear infinite;
animation: container-rotate 1568ms linear infinite;
}
.preloader.pl-size-xl {
width: 75px;
height: 75px;
}
.preloader.pl-size-l {
width: 60px;
height: 60px;
}
.preloader.pl-size-md {
width: 50px;
height: 50px;
}
.preloader.pl-size-sm {
width: 40px;
height: 40px;
}
.preloader.pl-size-xs {
width: 25px;
height: 25px;
}
.spinner-layer {
position: absolute;
width: 100%;
height: 100%;
border-color: #F44336;
-ms-opacity: 1;
opacity: 1;
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
.spinner-layer.pl-red {
border-color: #F44336;
}
.spinner-layer.pl-pink {
border-color: #E91E63;
}
.spinner-layer.pl-purple {
border-color: #9C27B0;
}
.spinner-layer.pl-deep-purple {
border-color: #673AB7;
}
.spinner-layer.pl-indigo {
border-color: #3F51B5;
}
.spinner-layer.pl-blue {
border-color: #2196F3;
}
.spinner-layer.pl-light-blue {
border-color: #03A9F4;
}
.spinner-layer.pl-cyan {
border-color: #00BCD4;
}
.spinner-layer.pl-teal {
border-color: #009688;
}
.spinner-layer.pl-green {
border-color: #4CAF50;
}
.spinner-layer.pl-light-green {
border-color: #8BC34A;
}
.spinner-layer.pl-lime {
border-color: #CDDC39;
}
.spinner-layer.pl-yellow {
border-color: #ffe821;
}
.spinner-layer.pl-amber {
border-color: #FFC107;
}
.spinner-layer.pl-orange {
border-color: #FF9800;
}
.spinner-layer.pl-deep-orange {
border-color: #FF5722;
}
.spinner-layer.pl-brown {
border-color: #795548;
}
.spinner-layer.pl-grey {
border-color: #9E9E9E;
}
.spinner-layer.pl-blue-grey {
border-color: #607D8B;
}
.spinner-layer.pl-black {
border-color: #000000;
}
.spinner-layer.pl-white {
border-color: #ffffff;
}
.right {
float: right !important;
}
.gap-patch {
position: absolute;
top: 0;
left: 45%;
width: 10%;
height: 100%;
overflow: hidden;
border-color: inherit;
}
.gap-patch.circle {
width: 1000%;
left: -450%;
}
.circle-clipper {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
overflow: hidden;
border-color: inherit;
}
.circle-clipper .circle {
width: 200%;
height: 100%;
border-width: 3px;
border-style: solid;
border-color: inherit;
border-bottom-color: transparent !important;
-ms-border-radius: 50%;
border-radius: 50%;
-webkit-animation: none;
animation: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
}
.circle-clipper.left .circle {
left: 0;
border-right-color: transparent !important;
-webkit-transform: rotate(129deg);
-moz-transform: rotate(129deg);
-ms-transform: rotate(129deg);
-o-transform: rotate(129deg);
transform: rotate(129deg);
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
.circle-clipper.right .circle {
left: -100%;
border-left-color: transparent !important;
-webkit-transform: rotate(-129deg);
-moz-transform: rotate(-129deg);
-ms-transform: rotate(-129deg);
-o-transform: rotate(-129deg);
transform: rotate(-129deg);
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
@-webkit-keyframes container-rotate {
to {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes container-rotate {
to {
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-webkit-keyframes fill-unfill-rotate {
12.5% {
-webkit-transform: rotate(135deg);
transform: rotate(135deg);
}
25% {
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
}
37.5% {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
50% {
-webkit-transform: rotate(540deg);
transform: rotate(540deg);
}
62.5% {
-webkit-transform: rotate(675deg);
transform: rotate(675deg);
}
75% {
-webkit-transform: rotate(810deg);
transform: rotate(810deg);
}
87.5% {
-webkit-transform: rotate(945deg);
transform: rotate(945deg);
}
to {
-webkit-transform: rotate(1080deg);
transform: rotate(1080deg);
}
}
@keyframes fill-unfill-rotate {
12.5% {
transform: rotate(135deg);
}
25% {
transform: rotate(270deg);
}
37.5% {
transform: rotate(405deg);
}
50% {
transform: rotate(540deg);
}
62.5% {
transform: rotate(675deg);
}
75% {
transform: rotate(810deg);
}
87.5% {
transform: rotate(945deg);
}
to {
transform: rotate(1080deg);
}
}
@-webkit-keyframes left-spin {
from {
-webkit-transform: rotate(130deg);
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
transform: rotate(130deg);
}
50% {
-webkit-transform: rotate(-5deg);
-moz-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
-o-transform: rotate(-5deg);
transform: rotate(-5deg);
}
to {
-webkit-transform: rotate(130deg);
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
transform: rotate(130deg);
}
}
@keyframes left-spin {
from {
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
-webkit-transform: rotate(130deg);
transform: rotate(130deg);
}
50% {
-moz-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
-o-transform: rotate(-5deg);
-webkit-transform: rotate(-5deg);
transform: rotate(-5deg);
}
to {
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
-webkit-transform: rotate(130deg);
transform: rotate(130deg);
}
}
@-webkit-keyframes right-spin {
from {
-webkit-transform: rotate(-130deg);
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-webkit-transform: rotate(5deg);
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-webkit-transform: rotate(-130deg);
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
@-moz-keyframes right-spin {
from {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
@keyframes right-spin {
from {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
<!-- Page Loader -->
<div class="page-loader-wrapper">
<div class="loader">
<div class="preloader">
<div class="spinner-layer pl-red">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
<p>Please wait...</p>
</div>
</div>
<!-- #END# Page Loader -->
然后在 views\layouts\main.php
文件的顶部添加以下内容
$js = <<<JS
setTimeout(function () {
$('.page-loader-wrapper').fadeOut();
}, 50);
JS;
$this->registerJs($js, \yii\web\View::POS_READY);
注意:理想情况下,您可以将与微调器相关的所有内容包装在一个单独的资产文件中,并在主布局中调用它,但我会把那部分留给您。
到此为止,如果您尝试单击应用程序上的任何链接,您将看到微调器为正常页面加载工作,例如主页或任何其他页面。
启用 Pjax 请求
我们也需要为 Pjax
启用它,所以转到您的 view
文件并在顶部添加以下 javascript 片段,它使用 pjax:beforeSend
显示微调器的事件
$js = <<<JS
$(document).on("pjax:beforeSend",function(){
$('.page-loader-wrapper').fadeIn();
});
JS;
$this->registerJs($js, \yii\web\View::POS_READY);
您无需担心关闭微调器,一旦通过我们的主要布局代码在 curl 响应后加载页面,它就会关闭。
更新
使用 pjax 时提交按钮值未提交的原因是一个已知问题,请参阅 here。您可以做的是为 2 个提交按钮添加 2 个隐藏字段,并在单击时更新与按钮关联的相应隐藏字段的值,并将它们与表单一起提交并检查这些新隐藏输入的值,所以您可以识别单击了哪个按钮。
所以,首先我们将添加隐藏输入,注意用于原始 submitButton
rco 和 dco 的选项,id 应该在那里。
<?php echo Html::beginForm(['about'], 'post', ['data' => ['pjax' => 1]]); ?>
<?php echo Html::submitButton('Disconnect', ['class' => 'btn btn-success', 'id' => 'dco']) ?>
<?php echo Html::submitButton('Connect', ['class' => 'btn btn-info', 'id' => 'rco']) ?>
<?php echo Html::hiddenInput('dco', '', ['id' => 'dco_input']); ?>
<?php echo Html::hiddenInput('rco', '', ['id' => 'rco_input']); ?>
现在我们将用以下
替换我们之前在视图中添加的javascript
$js = <<<JS
function loader(){
$('.page-loader-wrapper').fadeOut();
//reset the input values
$("#dco_input,#rco_input").val('');
//assign respective values to the associated hidden fields
$("#rco,#dco").on('click',function(e){
var buttonId = $(this).attr('id');
$("#"+buttonId+"_input").val(1);
});
}
$(document).on("pjax:beforeSend",function(e){
$('.page-loader-wrapper').fadeIn();
}).on("pjax:end",function(){
loader();
});
loader();
JS;
$this->registerJs($js, View::POS_READY);
?>
现在,每当我们单击 dco
提交按钮时,隐藏的输入 dco_input
将填充 1
,当单击 rco
提交按钮时 rco_input
将在提交 for 之前更新为值 1
,您将收到两个按钮的 post 中的值。
您需要更改的最后一件事是 controller/action process()
中的检查,这些检查正在检查 isset($_POST['dco'])
和 isset($_POST['rco'])
,它们将不起作用,需要已更新
if(isset($_POST['dco']))
和
if(isset($_POST["dco"]) && $_POST['dco']==1)
和
if(isset($_POST['rco']))
和
if(isset($_POST['rco']) && $_POST['rco']==1)
我有一个视图,其中有两个按钮。单击两个按钮中的任何一个时,都会发出特定请求。
查看
<?php Pjax::begin(); ?>
<?=Html::beginForm(['process'],'post');?>
<?=Html::submitButton('Disconnect', ['id'=>'d','name'=>'dco','class' => 'btn btn-primary']);?>
<?=Html::submitButton('Connect', ['id'=>'r','name'=>'rco','class' => 'btn btn-info']);?>
<br><br>
<div class="pre-scrollable">
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\CheckboxColumn', 'checkboxOptions' => function($d) {
return ['value' => $d['msn']];
}],
'customer_id',
// 'dept_code:ntext',
'dept_name:ntext',
'sub_div_name',
[
'label' => 'Sub Division Name',
'value' => function ($d) {
return $d->subdiv->name;
},
'filter' => Html::activeDropDownList($searchModel, 'sub_div_code', \common\models\SurveyHescoSubdivision::toArrayList(), ['prompt' => "Sub-Div", 'class' => 'form-control']),
],
'division_name',
'allowed_units',
'msn',
'units_consumed',
[
'label' => 'Disconnected',
'attribute' => 'disconnected',
'format'=>'raw',
'contentOptions' => ['style'=>'text-align:center'],
'value' => function($model){
return $model->disconnected == 1 ? '<span class="glyphicon glyphicon-ok text-success"></span>' : '<span class="glyphicon glyphicon-remove text-danger"></span>';
},
'filter' => Html::activeDropDownList($searchModel, 'disconnected', [''=>'All','1'=>'Yes','0'=>'No'], ['class' => 'form-control']),
],
'active_energy_total_m',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
<?= Html::endForm();?>
<?php Pjax::end(); ?>
控制器
public function actionProcess()
{
$soapUrl = "http://ip:port/HES/services/Request";
$userName = "user";
$password = "123456";
if (isset($_POST['dco']))
{
if(Yii::$app->request->isPost)
{
$data = Yii::$app->request->post('selection'); //checkbox (array)
foreach($data as $value)
{
$msn = $value;
$xml_post_string = /** @lang text */
'//soap request';
$headers = array(
"Content-type: text/xml;charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"Content-length: ".strlen($xml_post_string),
); //SOAPAction: your op URL
$url = $soapUrl;
// PHP cURL for https connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); // the SOAP request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// converting
$response = curl_exec($ch);
curl_close($ch);
$domd=new DOMDocument();
var_dump($response);
if(!$domd->loadXML($response)){
throw new \RuntimeException("failed to parse XML!");
}
$inner_xml=$domd->getElementsByTagName("return")->item(0)->textContent;
if(!($domd2=@DOMDocument::loadXML($inner_xml))){
throw new \RuntimeException("failed to parse inner_xml!");
}
$AsyncReplyFlag=$domd2->getElementsByTagName("AsyncReplyFlag")->item(0)->textContent;
if ($AsyncReplyFlag =='true')
{
$ds = 1;
$disconnected_at = date('Y-m-d H:i:s');
try {
Yii::$app->db->createCommand(/** @lang text */
"update
`accurate_mam`.`daily_log`
set
`disconnected` = '$ds',
`diconnected_at` = '$disconnected_at',
`reconnected_at` = NULL
where `msn` = '$msn' ;
")->execute(); //update master table
Yii::$app->db->createCommand(/** @lang text */
"update
`accurate_mam`.`log_disconnected`
set
`disconnected_at` = '$disconnected_at'
where `msn` = '$msn'")->execute();// update log disconnected table
} catch (Exception $e) {
} // updating the master table
}
}
}
}
}
我想做什么?
单击按钮时,我想显示一个 spinner/loader,它将在发出请求时开始并在请求完成时停止。
备注
我不想为 spinner/loader 添加默认时间。它应该在发送请求时开始并在完成时停止,即当过程完成时
我搜索了很多文章,但找不到完整的实现细节。
更新 1
我找到了一个解决方案 here 并尝试通过执行以下操作来实现它
<style>
#loader {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
background: rgba(0, 0, 0, 0.05) url("<?php \yii\helpers\Url::to('@web/images/25.png', true); ?>") no-repeat center center;
z-index: 10000;
}
</style>
JS
$(document).ready(function () {
$('form').submit(function(e) {
e.preventDefault();
spinner.show();
$.ajax({
url:'$url',
data: $(this).serialize()
type: 'POST',
dataType: 'JSON'
}).done(function(resp) {
spinner.hide();
//alert(resp.status);
});
});
});
面临的问题
现在我可以看到微调器,但过程尚未完成。进一步调试后,我观察到我在提交请求时在 var_dump(isset($_POST['dco']));
die();
中得到 bool(false)
更新 2
我又找到了一个
更新两个按钮
<?= Html::submitButton(Yii::t('app', '<i class="fa fa-times"></i> Disconnect'), ['class' => 'btn red', 'name' => 'dco', 'value' => '0']) ?> <?= Html::submitButton(Yii::t('app', '<i class="fa fa-check"></i> Connect'), ['class' => 'btn blue', 'name' => 'rco', 'value' => '1']) ?>
JS
$('form').submit(function(e) {
e.preventDefault();
var strValue = "";
$('input[name="selection[]"]:checked').each(function() {
if(strValue!=="")
{
strValue = strValue + " , " + this.value;
}
else
strValue = this.value;
});
spinner.show();
$.ajax({
url:'$url',
data: {data :strValue},
type: 'POST',
dataType: 'JSON'
}).done(function(resp) {
spinner.hide();
//alert(resp.status);
});
});
控制器
if (Yii::$app->request->post()) {
if (Yii::$app->request->post('dco') == 0) {
//Code for value 0
}
if (Yii::$app->request->post('rco') == 1) {
//Code for value 1
}
}
面临的问题
当我点击这两个按钮中的任何一个时,它总是点击 dco
检查,即 if (Yii::$app->request->post('dco') == 0)
它没有点击 rco
条件
一定是我遗漏了什么。
非常感谢任何帮助。
<?php
$this->registerJs(<<<JS
$(document).on('pjax:send', function() {
$('#loading').show();
});
$(document).on('pjax:complete', function() {
$('#loading').hide();
});
JS
);
?>
示例:fontawesome(或者可以使用图片....)
<i id='loading' class='fa fa-spinner fa-pulse' style='display:none;'></i>
您也可以通过变量(在控制器中)执行此操作。
我的理解
查看您当前的实现,您使用的是普通表单提交,尽管包装在 Pjax
容器内,但您尚未通过 Pjax
为您的表单启用表单提交,并希望显示微调器或加载程序将显示,直到您向某些 API 发送 curl
请求的操作的请求完成。
限制
您需要了解的一点是,如果您进行正常的表单提交并尝试显示您在内部执行的某个过程的微调器,您的 controller/action
将无法工作,因为视图尚未呈现并且您的微调器相关的任何 javascript
或 CSS
尚未在浏览器中呈现,也不会显示。
解决方案
另一方面,如果您使用 ajax
或 pjax
提交表单,因为您已经将表单包装在 Pjax
容器中,您可以使用 Pjax
启用 AdminBSBTheme 微调器的事件,它使用 CSS 仅显示微调器。
这不仅适用于您的 ajax 表单,而且您可以在整个网站上使用它进行正常的页面加载,从而产生不错的效果。一旦 DOM
准备就绪,它会自动隐藏,如果互联网连接速度较慢,它会让事情看起来更一致。
在表单上启用 Pjax
您必须在表单标签中添加 data-pjax="1"
属性以启用 Pjax
表单提交默认情况下它不会工作,因此请继续并更改以下行以启用 Pjax
提交表单。
<?php echo Html::beginForm(['process'],'post', ['data' => ['pjax' => 1]);?>
为 Pjax 启用超时
然后你需要指定 timeout
参数 属性 如果你的 curl
请求需要一点时间最好为 timeout
添加高值 属性 这样它就不会抛出 loading request failed
或 timeout
错误并等待响应。让我们给它 10 seconds
所以如果请求需要 10 secs
才能完成,它应该继续等待,否则如果收到响应则继续
<?php Pjax::begin(['timeout'=>10000]); ?>
微调器集成
现在是旋转器集成的部分,您可以在下面的演示中看到它 运行 它是纯粹基于 CSS 的。
在 views\layouts\main.php
文件中复制下面演示中的 Html
$this->beginBody()
和
在 site.css
文件中添加 css
,或者创建一个单独的文件并包含在 AppAssets.php
文件中。
/ Page Loader ================================= /
.page-loader-wrapper {
z-index: 99999999;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background: #eee;
overflow: hidden;
text-align: center;
}
.page-loader-wrapper p {
font-size: 13px;
margin-top: 10px;
font-weight: bold;
color: #444;
}
.page-loader-wrapper .loader {
position: relative;
top: calc(50% - 30px);
}
/ Preloaders ================================== /
.md-preloader .pl-red {
stroke: #F44336;
}
.md-preloader .pl-pink {
stroke: #E91E63;
}
.md-preloader .pl-purple {
stroke: #9C27B0;
}
.md-preloader .pl-deep-purple {
stroke: #673AB7;
}
.md-preloader .pl-indigo {
stroke: #3F51B5;
}
.md-preloader .pl-blue {
stroke: #2196F3;
}
.md-preloader .pl-light-blue {
stroke: #03A9F4;
}
.md-preloader .pl-cyan {
stroke: #00BCD4;
}
.md-preloader .pl-teal {
stroke: #009688;
}
.md-preloader .pl-green {
stroke: #4CAF50;
}
.md-preloader .pl-light-green {
stroke: #8BC34A;
}
.md-preloader .pl-lime {
stroke: #CDDC39;
}
.md-preloader .pl-yellow {
stroke: #ffe821;
}
.md-preloader .pl-amber {
stroke: #FFC107;
}
.md-preloader .pl-orange {
stroke: #FF9800;
}
.md-preloader .pl-deep-orange {
stroke: #FF5722;
}
.md-preloader .pl-brown {
stroke: #795548;
}
.md-preloader .pl-grey {
stroke: #9E9E9E;
}
.md-preloader .pl-blue-grey {
stroke: #607D8B;
}
.md-preloader .pl-black {
stroke: #000000;
}
.md-preloader .pl-white {
stroke: #ffffff;
}
.preloader {
display: inline-block;
position: relative;
width: 50px;
height: 50px;
-webkit-animation: container-rotate 1568ms linear infinite;
-moz-animation: container-rotate 1568ms linear infinite;
-o-animation: container-rotate 1568ms linear infinite;
animation: container-rotate 1568ms linear infinite;
}
.preloader.pl-size-xl {
width: 75px;
height: 75px;
}
.preloader.pl-size-l {
width: 60px;
height: 60px;
}
.preloader.pl-size-md {
width: 50px;
height: 50px;
}
.preloader.pl-size-sm {
width: 40px;
height: 40px;
}
.preloader.pl-size-xs {
width: 25px;
height: 25px;
}
.spinner-layer {
position: absolute;
width: 100%;
height: 100%;
border-color: #F44336;
-ms-opacity: 1;
opacity: 1;
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
.spinner-layer.pl-red {
border-color: #F44336;
}
.spinner-layer.pl-pink {
border-color: #E91E63;
}
.spinner-layer.pl-purple {
border-color: #9C27B0;
}
.spinner-layer.pl-deep-purple {
border-color: #673AB7;
}
.spinner-layer.pl-indigo {
border-color: #3F51B5;
}
.spinner-layer.pl-blue {
border-color: #2196F3;
}
.spinner-layer.pl-light-blue {
border-color: #03A9F4;
}
.spinner-layer.pl-cyan {
border-color: #00BCD4;
}
.spinner-layer.pl-teal {
border-color: #009688;
}
.spinner-layer.pl-green {
border-color: #4CAF50;
}
.spinner-layer.pl-light-green {
border-color: #8BC34A;
}
.spinner-layer.pl-lime {
border-color: #CDDC39;
}
.spinner-layer.pl-yellow {
border-color: #ffe821;
}
.spinner-layer.pl-amber {
border-color: #FFC107;
}
.spinner-layer.pl-orange {
border-color: #FF9800;
}
.spinner-layer.pl-deep-orange {
border-color: #FF5722;
}
.spinner-layer.pl-brown {
border-color: #795548;
}
.spinner-layer.pl-grey {
border-color: #9E9E9E;
}
.spinner-layer.pl-blue-grey {
border-color: #607D8B;
}
.spinner-layer.pl-black {
border-color: #000000;
}
.spinner-layer.pl-white {
border-color: #ffffff;
}
.right {
float: right !important;
}
.gap-patch {
position: absolute;
top: 0;
left: 45%;
width: 10%;
height: 100%;
overflow: hidden;
border-color: inherit;
}
.gap-patch.circle {
width: 1000%;
left: -450%;
}
.circle-clipper {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
overflow: hidden;
border-color: inherit;
}
.circle-clipper .circle {
width: 200%;
height: 100%;
border-width: 3px;
border-style: solid;
border-color: inherit;
border-bottom-color: transparent !important;
-ms-border-radius: 50%;
border-radius: 50%;
-webkit-animation: none;
animation: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
}
.circle-clipper.left .circle {
left: 0;
border-right-color: transparent !important;
-webkit-transform: rotate(129deg);
-moz-transform: rotate(129deg);
-ms-transform: rotate(129deg);
-o-transform: rotate(129deg);
transform: rotate(129deg);
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
.circle-clipper.right .circle {
left: -100%;
border-left-color: transparent !important;
-webkit-transform: rotate(-129deg);
-moz-transform: rotate(-129deg);
-ms-transform: rotate(-129deg);
-o-transform: rotate(-129deg);
transform: rotate(-129deg);
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-moz-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-o-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
@-webkit-keyframes container-rotate {
to {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes container-rotate {
to {
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-webkit-keyframes fill-unfill-rotate {
12.5% {
-webkit-transform: rotate(135deg);
transform: rotate(135deg);
}
25% {
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
}
37.5% {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
50% {
-webkit-transform: rotate(540deg);
transform: rotate(540deg);
}
62.5% {
-webkit-transform: rotate(675deg);
transform: rotate(675deg);
}
75% {
-webkit-transform: rotate(810deg);
transform: rotate(810deg);
}
87.5% {
-webkit-transform: rotate(945deg);
transform: rotate(945deg);
}
to {
-webkit-transform: rotate(1080deg);
transform: rotate(1080deg);
}
}
@keyframes fill-unfill-rotate {
12.5% {
transform: rotate(135deg);
}
25% {
transform: rotate(270deg);
}
37.5% {
transform: rotate(405deg);
}
50% {
transform: rotate(540deg);
}
62.5% {
transform: rotate(675deg);
}
75% {
transform: rotate(810deg);
}
87.5% {
transform: rotate(945deg);
}
to {
transform: rotate(1080deg);
}
}
@-webkit-keyframes left-spin {
from {
-webkit-transform: rotate(130deg);
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
transform: rotate(130deg);
}
50% {
-webkit-transform: rotate(-5deg);
-moz-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
-o-transform: rotate(-5deg);
transform: rotate(-5deg);
}
to {
-webkit-transform: rotate(130deg);
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
transform: rotate(130deg);
}
}
@keyframes left-spin {
from {
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
-webkit-transform: rotate(130deg);
transform: rotate(130deg);
}
50% {
-moz-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
-o-transform: rotate(-5deg);
-webkit-transform: rotate(-5deg);
transform: rotate(-5deg);
}
to {
-moz-transform: rotate(130deg);
-ms-transform: rotate(130deg);
-o-transform: rotate(130deg);
-webkit-transform: rotate(130deg);
transform: rotate(130deg);
}
}
@-webkit-keyframes right-spin {
from {
-webkit-transform: rotate(-130deg);
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-webkit-transform: rotate(5deg);
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-webkit-transform: rotate(-130deg);
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
@-moz-keyframes right-spin {
from {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
@keyframes right-spin {
from {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
50% {
-moz-transform: rotate(5deg);
-ms-transform: rotate(5deg);
-o-transform: rotate(5deg);
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
to {
-moz-transform: rotate(-130deg);
-ms-transform: rotate(-130deg);
-o-transform: rotate(-130deg);
-webkit-transform: rotate(-130deg);
transform: rotate(-130deg);
}
}
<!-- Page Loader -->
<div class="page-loader-wrapper">
<div class="loader">
<div class="preloader">
<div class="spinner-layer pl-red">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
<p>Please wait...</p>
</div>
</div>
<!-- #END# Page Loader -->
然后在 views\layouts\main.php
文件的顶部添加以下内容
$js = <<<JS
setTimeout(function () {
$('.page-loader-wrapper').fadeOut();
}, 50);
JS;
$this->registerJs($js, \yii\web\View::POS_READY);
注意:理想情况下,您可以将与微调器相关的所有内容包装在一个单独的资产文件中,并在主布局中调用它,但我会把那部分留给您。
到此为止,如果您尝试单击应用程序上的任何链接,您将看到微调器为正常页面加载工作,例如主页或任何其他页面。
启用 Pjax 请求
我们也需要为 Pjax
启用它,所以转到您的 view
文件并在顶部添加以下 javascript 片段,它使用 pjax:beforeSend
显示微调器的事件
$js = <<<JS
$(document).on("pjax:beforeSend",function(){
$('.page-loader-wrapper').fadeIn();
});
JS;
$this->registerJs($js, \yii\web\View::POS_READY);
您无需担心关闭微调器,一旦通过我们的主要布局代码在 curl 响应后加载页面,它就会关闭。
更新
使用 pjax 时提交按钮值未提交的原因是一个已知问题,请参阅 here。您可以做的是为 2 个提交按钮添加 2 个隐藏字段,并在单击时更新与按钮关联的相应隐藏字段的值,并将它们与表单一起提交并检查这些新隐藏输入的值,所以您可以识别单击了哪个按钮。
所以,首先我们将添加隐藏输入,注意用于原始 submitButton
rco 和 dco 的选项,id 应该在那里。
<?php echo Html::beginForm(['about'], 'post', ['data' => ['pjax' => 1]]); ?>
<?php echo Html::submitButton('Disconnect', ['class' => 'btn btn-success', 'id' => 'dco']) ?>
<?php echo Html::submitButton('Connect', ['class' => 'btn btn-info', 'id' => 'rco']) ?>
<?php echo Html::hiddenInput('dco', '', ['id' => 'dco_input']); ?>
<?php echo Html::hiddenInput('rco', '', ['id' => 'rco_input']); ?>
现在我们将用以下
替换我们之前在视图中添加的javascript$js = <<<JS
function loader(){
$('.page-loader-wrapper').fadeOut();
//reset the input values
$("#dco_input,#rco_input").val('');
//assign respective values to the associated hidden fields
$("#rco,#dco").on('click',function(e){
var buttonId = $(this).attr('id');
$("#"+buttonId+"_input").val(1);
});
}
$(document).on("pjax:beforeSend",function(e){
$('.page-loader-wrapper').fadeIn();
}).on("pjax:end",function(){
loader();
});
loader();
JS;
$this->registerJs($js, View::POS_READY);
?>
现在,每当我们单击 dco
提交按钮时,隐藏的输入 dco_input
将填充 1
,当单击 rco
提交按钮时 rco_input
将在提交 for 之前更新为值 1
,您将收到两个按钮的 post 中的值。
您需要更改的最后一件事是 controller/action process()
中的检查,这些检查正在检查 isset($_POST['dco'])
和 isset($_POST['rco'])
,它们将不起作用,需要已更新
if(isset($_POST['dco']))
和
if(isset($_POST["dco"]) && $_POST['dco']==1)
和
if(isset($_POST['rco']))
和
if(isset($_POST['rco']) && $_POST['rco']==1)