使用Yii2编程:使用Ajax

最终产品图片
您将要创造的

如果您问“什么是Yii?”,请查看 Yii Framework简介 ,其中 介绍了Yii 的优点,并包括2014年10月发布的Yii 2.0概述。

在本使用Yii2编程系列中 ,我指导读者使用PHP的Yii2框架。 在本教程中,我们将探索使用Ajax实现交互式页面的方法。 具体来说,我要强调在会议计划应用的两个领域,其中我写了使用Ajax 构建您启动一系列平行的。

首先,我们将回顾如何根据用户输入的特定位置在页面上加载Google地图。 如下所示,在我进入Plum Bistro并单击return之后,右边的地图会动态加载,而不会刷新页面。

Yii Ajax-Google Maps UX示例

其次,我将向您展示如何在计划阶段记录用户对会议所做的更改。 Meeting Planner使参与者可以轻松地确定自己的首选地点和日期时间,然后最终选择最终的地点和日期。

Yii Ajax-Meeting Planner UX示例

Ajax使此过程变得更加轻松和快捷,使人们可以滑动许多开关控件来指示自己的偏好,而无需刷新页面。

提醒一下,我确实参与了下面的评论主题。 如果您有不同的方法,其他想法或想为将来的教程提供建议,我特别感兴趣。 如果您有任何问题或建议,请在下面发布。 您也可以直接通过Twitter @reifman与联系

在Yii中使用Ajax

Yii Ajax-Wikipedia Ajax流程与HTTP
作者: DanielSHaischt,通过Wikimedia Commons ,CC BY-SA 3.0

如果您只是刚开始使用Ajax并想起步较慢,那么Yii Playground有两个简单的Ajax示例,它们可能对您有所帮助。 一个通过Ajax更改页面上的文本,另一个通过同一页面将响应加载到表单上,而无需刷新,每个都包含详细的代码示例。

Yii Ajax-Yii Playground AJAX示例

让我们深入研究两个主要示例。 您可以在GitHubMeeting Planner代码存储库中找到这些示例的所有源代码

交互式显示Google地图

建立输入表格

最初加载“ 创建地方”表单 (/frontend/views/place/create_place_google.php)时,该表单包含Google地方信息实时搜索窗口小部件:

Yii Ajax-使用Google地方信息在Meeting Planner中创建地方

集成Google Places JavaScript API

该表单会加载Google Maps JavaScript库并将其连接到place-searchbox输入字段:

$gpJsLink= 'https://maps.googleapis.com/maps/api/js?' . http_build_query(array(
                          'key' => Yii::$app->params['google_maps_key'],
                          'libraries' => 'places',
                  ));
  echo $this->registerJsFile($gpJsLink);

  $options = '{"types":["establishment"],"componentRestrictions":{"country":"us"}}';
  echo $this->registerJs("(function(){
        var input = document.getElementById('place-searchbox');
        var options = $options;
        searchbox = new google.maps.places.Autocomplete(input, options);
        setupListeners('place');
})();" , \yii\web\View::POS_END );

_formPlaceGoogle.php部分表单包括一些隐藏字段,可以在提交整个页面之前在其中存储地图的结果,还包括一个隐藏的div以通过Ajax显示地图。

use frontend\assets\MapAsset;
MapAsset::register($this);
...
    <?= BaseHtml::activeHiddenInput($model, 'name'); ?>
    <?= BaseHtml::activeHiddenInput($model, 'google_place_id'); ?>
    <?= BaseHtml::activeHiddenInput($model, 'location'); ?>
    <?= BaseHtml::activeHiddenInput($model, 'website'); ?>
    <?= BaseHtml::activeHiddenInput($model, 'vicinity'); ?>
    <?= BaseHtml::activeHiddenInput($model, 'full_address'); ?>
...
<div class="col-md-6">
  <article></article>
</div> <!-- end col2 -->

Meeting Planner Place表存储Google名称,place_id,位置,网站,附近和full_address,以在整个应用程序中使用。

上面包含的MapAsset加载了我们的create_place.js文件,该文件在Google和我们的表单之间运行; 它基本上通过Ajax管理数据的传输和响应。

我们的Ajax管理JavaScript

我将逐步指导您完成create_place.js。 首先,有setupListeners() ,由父窗体调用:

function setupListeners(model) {
    // searchbox is the var for the google places object created on the page
    google.maps.event.addListener(searchbox, 'place_changed', function() {
      var place = searchbox.getPlace();
      if (!place.geometry) {
        // Inform the user that a place was not found and return.
        return;
      }  else {
        // migrates JSON data from Google to hidden form fields
        populateResult(place,model);
      }
    });
    var place_input = document.getElementById(model+'-searchbox');
    google.maps.event.addDomListener(place_input, 'keydown', function(e) {
        if (e.keyCode == 13) {
            e.preventDefault();
        }
      });
}

当用户开始键入内容时,小部件会下拉现实世界位置的预输入选项,并且每次按键都会处理place_changed事件。 上面的keydown侦听器可防止返回键(对于十六进制用户来说为ASCII 13或0xD)提交表单。

这是您输入时的样子。 我正在为Plum Bistro输入Plum

Yii Ajax-Google地方下拉列表

收集结果图及其数据

如果此人在下拉菜单中选择了Enter或单击了某个位置,则将调用populateResult() ;否则, populateResult()调用populateResult() 。 如果没有,我们什么也不做。

function populateResult(place,model) {
  // moves JSON data retrieve from Google to hidden form fields
  // so Yii2 can post the data
    $('#'+model+'-location').val(JSON.stringify(place['geometry']['location']));
    $('#'+model+'-google_place_id').val(place['place_id']);
    $('#'+model+'-full_address').val(place['formatted_address']);
    $('#'+model+'-website').val(place['website']);
    $('#'+model+'-vicinity').val(place['vicinity']);
    $('#'+model+'-name').val(place['name']);
    loadMap(place['geometry']['location'],place['name']);
}

这会使用Google的数据填充所有隐藏的字段,并调用loadMap()来显示地图:

Yii Ajax-通过Ajax加载Google地方信息地图

loadMap()函数专用于Google的Place API,并在右侧显示您在上方看到的地图:

function loadMap(gps,name) {
  var gps_parse = gps.toString().replace("(", "").replace(")", "").split(", ");
  var gps_lat = parseFloat(gps_parse[0]);
  var gps_lng = parseFloat(gps_parse[1]);

  if (document.querySelector('article').children.length==0) {
    var mapcanvas = document.createElement('div');
    mapcanvas.id = 'mapcanvas';
    mapcanvas.style.height = '300px';
    mapcanvas.style.width = '300px';
    mapcanvas.style.border = '1px solid black';
    document.querySelector('article').appendChild(mapcanvas);
  }
  var latlng = new google.maps.LatLng(gps_lat,gps_lng); // gps['k'], gps['D']);

  var myOptions = {
    zoom: 16,
    center: latlng,
    mapTypeControl: false,
    navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  var map = new google.maps.Map(document.getElementById("mapcanvas"), myOptions);
  var marker = new google.maps.Marker({
      position: latlng,
      map: map,
      title:name
  });
}

用户体验快速而令人印象深刻。 试试吧

动态记录会议更改

接下来,让我们看看我们如何实时记录会议计划的更改。 这里没有Google API; 在Yii框架中更像是普通的AJAX。

当人们在会议计划中添加日期,时间和地点时,您会看到如下页面:

Yii Ajax-会议计划者与滑块的计划视图

您”和“ 他们”列显示每个参与者对地点和日期时间的偏好。 较大的“选择”滑块使人员可以对会议地点和时间做出最终决定。

人们需要收集大量数据,我们不想每次更改都需要刷新页面。 Ajax是解决此问题的理想解决方案。

我将遍历上面“会议场所”面板的代码。 上面的“会议时间”面板的工作原理类似。

遵守守则

由于MVC框架以及我希望重用代码部分的原因,此处的流程可能很难遵循。 PHP辅助函数和JavaScript有时必须放置在父文件中,而不是它们最密切相关的部分。 我将首先为您提供概述。 我鼓励您通过阅读以完全理解它。 同样,您可以通过GitHub浏览代码

提示:请记住,部分文件名通常以下划线开头。

  1. 会议计划程序页面位于/frontend/views/meeting/view.php。 此文件还包括帮助程序按钮的状态的辅助JavaScript函数,例如“ 发送”和“ 完成” (即,更改之后,用户现在可以发送此邀请吗?)使用Meeting Planner,通常必须先选择一个位置和一个时间,然后才能发送邀请),并显示视觉通知,通知用户完成后会将更改通过电子邮件发送给其他参与者。
  2. 显示场所的“位置面板时,它将加载/frontend/views/meeting-place/_panel.php。 该文件包括辅助PHP函数showOwnerStatus()showParticipantStatus() ,它们的子级_list.php将重用它们。 但是,最重要的是,_panel.php包含用于Bootstrap滑块switchChange事件JavaScript方法。
  3. _panel.php文件使用_list.php来显示每个位置的每一行。 该文件将通过调用_panel.php函数showOwnerStatus()showParticipantStatus()来呈现Bootstrap滑块。
  4. switchChange函数将对MeetingPlaceChoiceController.php进行Ajax调用。
  5. 最后,MeetingPlaceChoiceController.php调用MeetingPlaceChoice.php模型以记录数据库中的更改。

抱歉,相关代码的放置很复杂且分散。

现在,我将逐步指导您完成关键组件。

Ajax代码逐步

这是Meeting / view.php渲染的Meeting-Place / _panel.php。 这将显示可能的地方行和参与者的选择的部分内容:

<?php
          // where
          if (!($model->meeting_type == \frontend\models\Meeting::TYPE_PHONE || $model->meeting_type == \frontend\models\Meeting::TYPE_VIDEO)) {
            echo $this->render('../meeting-place/_panel', [
              'model'=>$model,
              'placeProvider' => $placeProvider,
              'isOwner' => $isOwner,
              'viewer' => $viewer,
          ]);
          }
           ?>

下面是与响应Ajax结果但不是Ajax直接需要的操作有关JavaScript。 您无需了解这些功能如何理解此Ajax示例,但由于它们是为响应Ajax事件而调用的,因此我将它们包括在内。

<?php
$script = <<< JS
var notifierOkay; // meeting sent already and no page change session flash

if  ($('#notifierOkay').val() == 'on') {
  notifierOkay = true;
} else {
  notifierOkay = false;
}

function displayNotifier(mode) {
  if (notifierOkay) {
    if (mode == 'time') {
      $('#notifierTime').show();
    } else if (mode == 'place') {
       $('#notifierPlace').show();
    } else {
      alert("We\'ll automatically notify the organizer when you're done making changes.");
    }
    notifierOkay=false;
  }
}

function refreshSend() {
  $.ajax({
     url: '$urlPrefix/meeting/cansend',
     data: {id: $model->id, 'viewer_id': $viewer},
     success: function(data) {
       if (data)
         $('#actionSend').removeClass("disabled");
        else
        $('#actionSend').addClass("disabled");
       return true;
     }
  });
}

function refreshFinalize() {
  $.ajax({
     url: '$urlPrefix/meeting/canfinalize',
     data: {id: $model->id, 'viewer_id': $viewer},
     success: function(data) {
       if (data)
         $('#actionFinalize').removeClass("disabled");
        else
        $('#actionFinalize').addClass("disabled");
       return true;
     }
  });
}

JS;
$position = \yii\web\View::POS_READY;
$this->registerJs($script, $position);
?>

在Meeting-Place / _panel.php中,调用_list.php创建了显示位置和选择的表格:

<table class="table">
     <thead>
     <tr class="small-header">
       <td></td>
       <td ><?=Yii::t('frontend','You') ?></td>
       <td ><?=Yii::t('frontend','Them') ?></td>
        <td >
          <?php
           if ($placeProvider->count>1 && ($isOwner || $model->meetingSettings['participant_choose_place'])) echo Yii::t('frontend','Choose');
          ?></td>
    </tr>
    </thead>
    <?= ListView::widget([
           'dataProvider' => $placeProvider,
           'itemOptions' => ['class' => 'item'],
           'layout' => '{items}',
           'itemView' => '_list',
           'viewParams' => ['placeCount'=>$placeProvider->count,'isOwner'=>$isOwner,'participant_choose_place'=>$model->meetingSettings['participant_choose_place']],
       ]) ?>
  </table>
  <?php else: ?>
  <?php endif; ?>

更重要的是,它还包含下面JavaScript,当用户移动开关并更改其状态时,我们将使用它们进行Ajax调用。 选择器功能对应于较大的蓝色选择滑块,而选择功能对应于首选项滑块。

$script = <<< JS
placeCount = $placeProvider->count;
// allows user to set the final place
$('input[name="place-chooser"]').on('switchChange.bootstrapSwitch', function(e, s) {
  // console.log(e.target.value); // true | false
  // turn on mpc for user
  $.ajax({
     url: '$urlPrefix/meeting-place/choose',
     data: {id: $model->id, 'val': e.target.value},
     // e.target.value is selected MeetingPlaceChoice model
     success: function(data) {
       displayNotifier('place');
       refreshSend();
       refreshFinalize();
       return true;
     }
  });
});

// users can say if a place is an option for them
$('input[name="meeting-place-choice"]').on('switchChange.bootstrapSwitch', function(e, s) {
  //console.log(e.target.id,s); // true | false
  // set intval to pass via AJAX from boolean state
  if (s)
    state = 1;
  else
    state =0;
  $.ajax({
     url: '$urlPrefix/meeting-place-choice/set',
     data: {id: e.target.id, 'state': state},
     success: function(data) {
       displayNotifier('place');
       refreshSend();
       refreshFinalize();
       return true;
     }
  });
});

JS;
$position = \yii\web\View::POS_READY;
$this->registerJs($script, $position);
?>

上面的函数在MeetingPlaceChoiceController调用actionSet()以使用Ajax请求来响应切换更改:

public function actionSet($id,$state)
    {
      Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
      // caution - incoming AJAX type issues with val
      $id=str_replace('mpc-','',$id);
      //if (Yii::$app->user->getId()!=$mpc->user_id) return false;
      if (intval($state) == 0 or $state=='false')
        $status = MeetingPlaceChoice::STATUS_NO;
      else
        $status = MeetingPlaceChoice::STATUS_YES;
      //$mpc->save();
      MeetingPlaceChoice::set($id,$status,Yii::$app->user->getId());
      return $id;
    }

通过Ajax响应的控制器动作需要具有JSON响应格式(通过这种方式,Yii知道它们并不旨在提供HTML):

Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

这是MeetingPlaceChoice::set()方法,该方法在数据库中记录用户的操作,并创建一个MeetingLog条目,该条目监视计划期间的所有更改。

public static function set($id,$status,$user_id = 0,$bulkMode=false)
    {
      $mpc = MeetingPlaceChoice::findOne($id);
      if ($mpc->user_id==$user_id) {
        $mpc->status = $status;
        $mpc->save();
        if (!$bulkMode) {
          // log only when not in bulk mode i.e. accept all
          // see setAll for more details
          if ($status==MeetingPlaceChoice::STATUS_YES) {
            $command = MeetingLog::ACTION_ACCEPT_PLACE;
          } else {
            $command = MeetingLog::ACTION_REJECT_PLACE;
          }
          MeetingLog::add($mpc->meetingPlace->meeting_id,$command,$mpc->user_id,$mpc->meeting_place_id);
        }
        return $mpc->id;
      } else {
        return false;
      }
    }

与会议变更相关的功能

在Meeting Planner中,我记录了每个更改。 这使我可以知道某个人的上一次更改后何时过去了几分钟,并通知其他与会人员。 我正在尝试使用此服务进行实验,而不是要求参与者每次想要进行更改时都点击提交。

但是,这需要培训他们以了解可以更改并保留它,即关闭浏览器窗口。 因此, displayNotifier()函数显示一些闪光警报以帮助解决此问题-我最终将逐步完善它们,并为有经验的用户删除它们。

MeetingLog还允许我生成会议计划历史的文本摘要。 如果您想了解更多有关此的知识,我已经在《 建立您的初创企业:通知人们有关会议变更传递通知》一书中对此进行了介绍。

下一步是什么?

我希望这些示例可以帮助您了解Yii中的Ajax基础。 如果您对更高级的Ajax感兴趣,我计划在Meeting Planner系列中包括Ajax加载的表单。 而且,诚然,Ajax是Yii社区尚未分享很多示例的领域。 通常,Ajax在Yii中的工作方式与在PHP和其他框架中的类似,因此您可以从其他框架社区的示例中学习。

在继续研究框架的不同方面时,请观看我们的《 使用Yii2编程》系列中即将发布的教程。 您可能还需要查看我们的“ 使用PHP构建启动”系列 ,该系列在构建实际应用程序时使用了Yii2的高级模板。

如果您想知道下一个Yii2教程何时到达, 在Twitter上关注我@reifman查看我的讲师页面 。 发布后,我的讲师页面将包含本系列中的所有文章。

相关链接

翻译自: https://code.tutsplus.com/tutorials/programming-with-yii2-using-ajax--cms-26663

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值