() translation by (you can also view the original English article)



Si vous le demandez, "ce qui est Yii ?", consultez Introduction au cadre Yii, qui passe en revue les avantages de Yii et comprend un aperçu des Yii 2.0, sorti en octobre 2014.
Dans cette série de programmation avec Yii2, je suis guider les lecteurs dans l’utilisation du cadre Yii2 pour PHP. Dans ce tutoriel, nous allons explorer la mise en œuvre des pages interactives en utilisant Ajax. Plus précisément, je vais mettre en évidence l’utilisation d’Ajax dans deux domaines d’application Meeting Planner, dont j’ai écris la série Building Your Startup sur en parallèle.
Tout d’abord, nous allons revoir comment nous charger une carte Google sur la page en réponse à l’utilisateur d’entrer dans un lieu déterminé. Comme indiqué ci-dessous, après que j’ai entrer Plum Bistro et cliquez sur retour, la carte aux droite de charge dynamiquement sans une actualisation de la page.



Deuxièmement, je vais vous montrer comment on enregistre les modifications un utilisateur apporte à une réunion au cours de la phase de planification. Planificateur de réunion le rend facile pour les participants à identifier leurs endroits préférés et jour fois et puis finalement choisissez celui final.



Ajax rend le processus beaucoup plus facile et plus rapide, permettant aux gens de faire glisser un certain nombre de commandes pour indiquer leurs préférences sans aucun rafraîchissement de page.
Juste un rappel, j’y participent les threads commentaire ci-dessous. Je suis particulièrement intéressé si vous avez des approches différentes, des idées supplémentaires ou souhaitez suggérer des sujets pour prochains tutoriels. Si vous avez une question ou une suggestion de rubrique, merci de poster ci-dessous. Vous pouvez également me rejoindre sur Twitter @reifman directement.
Utilisation d’Ajax avec Yii



Si vous êtes seulement commencer avec Ajax et voulez commencer lentement, la Cour de récréation Yii a deux exemples simples d’Ajax qui peut être utile pour vous de revoir. On change le texte sur une page via Ajax et une autre charge la réponse à un formulaire sur la même page, tous deux sans actualiser et chacun comprend des exemples de code détaillé.



Nous allons plonger dans nos deux principaux exemples. Vous pouvez trouver toutes la données source pour ces exemples dans le référentiel de code Meeting Planner sur GitHub.
Affichage interactif Google Maps
Le formulaire de saisie de la construction
Lorsque la créer une forme de lieu (/ frontend/views/place/create_place_google.php) se charge initialement, il inclut le widget de recherche en direct de Google adresses :



Intégration de l’API JavaScript de Google Places
La forme charge la bibliothèque JavaScript de Google Maps et le relie à la zone de saisie lieu-searchbox :
1 |
$gpJsLink= 'https://maps.googleapis.com/maps/api/js?' . http_build_query(array( |
2 |
'key' => Yii::$app->params['google_maps_key'], |
3 |
'libraries' => 'places', |
4 |
));
|
5 |
echo $this->registerJsFile($gpJsLink); |
6 |
|
7 |
$options = '{"types":["establishment"],"componentRestrictions":{"country":"us"}}'; |
8 |
echo $this->registerJs("(function(){ |
9 |
var input = document.getElementById('place-searchbox');
|
10 |
var options = $options;
|
11 |
searchbox = new google.maps.places.Autocomplete(input, options);
|
12 |
setupListeners('place');
|
13 |
})();" , \yii\web\View::POS_END ); |
La forme partielle _formPlaceGoogle.php inclut des champs masqués dans lequel les résultats de la carte peuvent être stockés avant que la page entière est soumise, ainsi que d’un div cachée à visualiser sur la carte via Ajax.
1 |
use frontend\assets\MapAsset; |
2 |
MapAsset::register($this); |
3 |
... |
4 |
<?= BaseHtml::activeHiddenInput($model, 'name'); ?> |
5 |
<?= BaseHtml::activeHiddenInput($model, 'google_place_id'); ?> |
6 |
<?= BaseHtml::activeHiddenInput($model, 'location'); ?> |
7 |
<?= BaseHtml::activeHiddenInput($model, 'website'); ?> |
8 |
<?= BaseHtml::activeHiddenInput($model, 'vicinity'); ?> |
9 |
<?= BaseHtml::activeHiddenInput($model, 'full_address'); ?> |
10 |
... |
11 |
<div class="col-md-6"> |
12 |
<article></article> |
13 |
</div> <!-- end col2 --> |
La table de Meeting Planner Place stocke le Google nom, place_id, lieu, site Web, proximité et full_address pour utilisation dans toute l’application.
Le MapAsset inclus ci-dessus charges notre fichier create_place.js qui opère entre Google et notre formulaire ; Fondamentalement, il gère la transmission et la réponse de données via Ajax.
Notre JavaScript Ajax de gestion
Je vais vous guider dans la create_place.js en morceaux. Tout d’abord, il n’y a setupListeners()
, appelée par le formulaire parent :
1 |
function setupListeners(model) { |
2 |
// searchbox is the var for the google places object created on the page
|
3 |
google.maps.event.addListener(searchbox, 'place_changed', function() { |
4 |
var place = searchbox.getPlace(); |
5 |
if (!place.geometry) { |
6 |
// Inform the user that a place was not found and return.
|
7 |
return; |
8 |
} else { |
9 |
// migrates JSON data from Google to hidden form fields
|
10 |
populateResult(place,model); |
11 |
}
|
12 |
});
|
13 |
var place_input = document.getElementById(model+'-searchbox'); |
14 |
google.maps.event.addDomListener(place_input, 'keydown', function(e) { |
15 |
if (e.keyCode == 13) { |
16 |
e.preventDefault(); |
17 |
}
|
18 |
});
|
19 |
}
|
Comme l’utilisateur commence à taper, le widget descende typeahead options pour des lieux réels, et l’événement place_changed est traité avec chaque pression de touche. L’auditeur keydown
ci-dessus empêche l’envoi du formulaire la touche retour (ASCII 13 ou 0xD vous geeks de sortilège).
Voici ce qu’il ressemble à mesure que vous tapez. Je suis entrer dans prune
pour Plum Bistro :



Collecte de ses données et la carte obtenue
Si la personne a choisi entrer ou cliqué sur une place dans la liste déroulante, puis populateResult()
est appelée ; Si ce n’est pas le cas, nous ne faisons rien.
1 |
function populateResult(place,model) { |
2 |
// moves JSON data retrieve from Google to hidden form fields
|
3 |
// so Yii2 can post the data
|
4 |
$('#'+model+'-location').val(JSON.stringify(place['geometry']['location'])); |
5 |
$('#'+model+'-google_place_id').val(place['place_id']); |
6 |
$('#'+model+'-full_address').val(place['formatted_address']); |
7 |
$('#'+model+'-website').val(place['website']); |
8 |
$('#'+model+'-vicinity').val(place['vicinity']); |
9 |
$('#'+model+'-name').val(place['name']); |
10 |
loadMap(place['geometry']['location'],place['name']); |
11 |
}
|
Cela remplit tous les champs cachés avec les données de Google et appelle loadMap()
pour visualiser sur la carte :



La fonction loadMap()
est très spécifique à l’API de Google Place et affiche la carte que vous voyez ci-dessus à droite :
1 |
function loadMap(gps,name) { |
2 |
var gps_parse = gps.toString().replace("(", "").replace(")", "").split(", "); |
3 |
var gps_lat = parseFloat(gps_parse[0]); |
4 |
var gps_lng = parseFloat(gps_parse[1]); |
5 |
|
6 |
if (document.querySelector('article').children.length==0) { |
7 |
var mapcanvas = document.createElement('div'); |
8 |
mapcanvas.id = 'mapcanvas'; |
9 |
mapcanvas.style.height = '300px'; |
10 |
mapcanvas.style.width = '300px'; |
11 |
mapcanvas.style.border = '1px solid black'; |
12 |
document.querySelector('article').appendChild(mapcanvas); |
13 |
}
|
14 |
var latlng = new google.maps.LatLng(gps_lat,gps_lng); // gps['k'], gps['D']); |
15 |
|
16 |
var myOptions = { |
17 |
zoom: 16, |
18 |
center: latlng, |
19 |
mapTypeControl: false, |
20 |
navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL}, |
21 |
mapTypeId: google.maps.MapTypeId.ROADMAP |
22 |
};
|
23 |
|
24 |
var map = new google.maps.Map(document.getElementById("mapcanvas"), myOptions); |
25 |
var marker = new google.maps.Marker({ |
26 |
position: latlng, |
27 |
map: map, |
28 |
title:name |
29 |
});
|
30 |
}
|
L’expérience utilisateur est rapide et impressionnante. Essaie !
Changements dynamiquement enregistrement de réunion
Ensuite, nous allons étudier comment nous enregistrer des modifications apportées aux plans en temps réel de la réunion. Il n’y a aucune API Google ici ; Il est plus vanille AJAX dans le cadre de Yii.
Comme les gens ajoutent des dates, heures et lieux à leurs plans de réunion, vous verrez une page comme celle-ci :



Les colonnes vous et eux voir la favorabilité de chaque participant vers les lieux et dates heures. Le curseur de choix plus grand permet à la personne à prendre la décision finale sur le lieu de rencontre et le temps.
Il y a beaucoup de données à collecter des gens, et nous ne voulons pas besoin d’un rafraîchissement de page à chaque changement. Ajax est la solution idéale pour ce problème.
Je vais parcourir le code pour le panneau de lieu de rencontre qui précède. Le Comité de la réunion-temps ci-dessus fonctionne de manière similaire.
Le Code suivant
En raison de l’infrastructure MVC et mon désir de réutiliser des parties de code, le flux ici peut-être se sentir difficile à suivre. Fonctions d’assistance PHP et JavaScript parfois devaient être placées dans les fichiers de parent, pas partiels qu’ils étaient plus proches de. Je vais essayer de vous donner un aperçu en premier. Je vous encourage à faire quelques passes lire du pour comprendre pleinement. Et encore une fois, vous pouvez parcourir le code via GitHub.
Astuce : N’oubliez pas que les noms de fichiers pour les partiels commencent habituellement par un trait de soulignement.
- Chargement de la page de planificateur de réunion à /frontend/views/meeting/view.php. Ce fichier comprend également des fonctions JavaScript d’assistance pour gérer l’état des boutons envoyer et Finalize (c'est-à-dire après ce changement, peut l’utilisateur maintenant envoyer cette invitation ? Avec le planificateur de réunions, un seul endroit et une fois en général doivent être sélectionnés avant qu’il peut être envoyé) et l’affichage des notifications visuelles que les changements seront envoyés aux autres participants lorsque l’utilisateur termine.
- Quand afficher l’où les panneau pour les places, il charge /frontend/views/meeting-place/_panel.php. Ce fichier contient d’assistance PHP fonctions
showOwnerStatus()
etshowParticipantStatus()
, qui seront réutilisées par son enfant, _list.php. Mais, surtout, _panel.php inclut des méthodes JavaScript pour l’événementswitchChange
de curseur Bootstrap. - Le fichier _panel.php utilise _list.php pour afficher chaque ligne individuelle pour chaque place. Ce fichier sera rendu les curseurs Bootstrap en appelant
showParticipantStatus()
et _panel.php des fonctionsshowOwnerStatus()
. - Les fonctions de
switchChange
feront appels Ajax à MeetingPlaceChoiceController.php. - Et enfin, MeetingPlaceChoiceController.php appelle le modèle MeetingPlaceChoice.php pour enregistrer les modifications dans la base de données.
Je suis désolé le placement du code correspondant est compliqué et étaler.
Maintenant, je vais vous guider dans les composantes clés étape par étape.
Code Ajax étape par étape
Voici Meeting/view.php rendu réunion-Place/_panel.php. Cela permet d’afficher la partielle pour les lignes des endroits possibles et les choix des participants :
1 |
<?php |
2 |
// where |
3 |
if (!($model->meeting_type == \frontend\models\Meeting::TYPE_PHONE || $model->meeting_type == \frontend\models\Meeting::TYPE_VIDEO)) { |
4 |
echo $this->render('../meeting-place/_panel', [ |
5 |
'model'=>$model, |
6 |
'placeProvider' => $placeProvider, |
7 |
'isOwner' => $isOwner, |
8 |
'viewer' => $viewer, |
9 |
]); |
10 |
} |
11 |
?> |
Ci-dessous qui est que JavaScript lié à des actions qui répondent aux résultats d’Ajax, mais ne sont pas directement nécessaires pour l’Ajax. Vous n’avez pas besoin de comprendre ce que ces fonctions font pour comprendre cet exemple Ajax, mais j’ai inclus les car ils sont appelés en réponse aux événements de l’Ajax.
1 |
<?php
|
2 |
$script = <<< JS |
3 |
var notifierOkay; // meeting sent already and no page change session flash |
4 |
|
5 |
if ($('#notifierOkay').val() == 'on') { |
6 |
notifierOkay = true; |
7 |
} else { |
8 |
notifierOkay = false; |
9 |
}
|
10 |
|
11 |
function displayNotifier(mode) { |
12 |
if (notifierOkay) { |
13 |
if (mode == 'time') { |
14 |
$('#notifierTime').show(); |
15 |
} else if (mode == 'place') { |
16 |
$('#notifierPlace').show(); |
17 |
} else { |
18 |
alert("We\'ll automatically notify the organizer when you're done making changes."); |
19 |
}
|
20 |
notifierOkay=false; |
21 |
}
|
22 |
}
|
23 |
|
24 |
function refreshSend() { |
25 |
$.ajax({ |
26 |
url: '$urlPrefix/meeting/cansend', |
27 |
data: {id: $model->id, 'viewer_id': $viewer}, |
28 |
success: function(data) { |
29 |
if (data) |
30 |
$('#actionSend').removeClass("disabled"); |
31 |
else
|
32 |
$('#actionSend').addClass("disabled"); |
33 |
return true; |
34 |
}
|
35 |
});
|
36 |
}
|
37 |
|
38 |
function refreshFinalize() { |
39 |
$.ajax({ |
40 |
url: '$urlPrefix/meeting/canfinalize', |
41 |
data: {id: $model->id, 'viewer_id': $viewer}, |
42 |
success: function(data) { |
43 |
if (data) |
44 |
$('#actionFinalize').removeClass("disabled"); |
45 |
else
|
46 |
$('#actionFinalize').addClass("disabled"); |
47 |
return true; |
48 |
}
|
49 |
});
|
50 |
}
|
51 |
|
52 |
JS; |
53 |
$position = \yii\web\View::POS_READY; |
54 |
$this->registerJs($script, $position); |
55 |
?>
|
Ici à la réunion-Place/_panel.php, le tableau indiquant les lieux et les sélections est créé, invoquant _list.php :
1 |
<table class="table"> |
2 |
<thead>
|
3 |
<tr class="small-header"> |
4 |
<td></td>
|
5 |
<td ><?=Yii::t('frontend','You') ?></td> |
6 |
<td ><?=Yii::t('frontend','Them') ?></td> |
7 |
<td > |
8 |
<?php
|
9 |
if ($placeProvider->count>1 && ($isOwner || $model->meetingSettings['participant_choose_place'])) echo Yii::t('frontend','Choose'); |
10 |
?></td> |
11 |
</tr>
|
12 |
</thead>
|
13 |
<?= ListView::widget([ |
14 |
'dataProvider' => $placeProvider, |
15 |
'itemOptions' => ['class' => 'item'], |
16 |
'layout' => '{items}', |
17 |
'itemView' => '_list', |
18 |
'viewParams' => ['placeCount'=>$placeProvider->count,'isOwner'=>$isOwner,'participant_choose_place'=>$model->meetingSettings['participant_choose_place']], |
19 |
]) ?> |
20 |
</table>
|
21 |
<?php else: ?> |
22 |
<?php endif; ?> |
Plus important encore, il inclut également le code JavaScript ci-dessous, qui nous permet de faire des appels Ajax lorsque l’utilisateur déplace un commutateur de changement de son état. Les fonctions de sélecteur correspondant au curseur bleu choix plus grand, tandis que les fonctions de choix correspondent à des curseurs de préférence.
1 |
$script = <<< JS |
2 |
placeCount = $placeProvider->count; |
3 |
// allows user to set the final place
|
4 |
$('input[name="place-chooser"]').on('switchChange.bootstrapSwitch', function(e, s) { |
5 |
// console.log(e.target.value); // true | false
|
6 |
// turn on mpc for user
|
7 |
$.ajax({ |
8 |
url: '$urlPrefix/meeting-place/choose', |
9 |
data: {id: $model->id, 'val': e.target.value}, |
10 |
// e.target.value is selected MeetingPlaceChoice model
|
11 |
success: function(data) { |
12 |
displayNotifier('place'); |
13 |
refreshSend(); |
14 |
refreshFinalize(); |
15 |
return true; |
16 |
}
|
17 |
});
|
18 |
});
|
19 |
|
20 |
// users can say if a place is an option for them
|
21 |
$('input[name="meeting-place-choice"]').on('switchChange.bootstrapSwitch', function(e, s) { |
22 |
//console.log(e.target.id,s); // true | false
|
23 |
// set intval to pass via AJAX from boolean state
|
24 |
if (s) |
25 |
state = 1; |
26 |
else
|
27 |
state =0; |
28 |
$.ajax({ |
29 |
url: '$urlPrefix/meeting-place-choice/set', |
30 |
data: {id: e.target.id, 'state': state}, |
31 |
success: function(data) { |
32 |
displayNotifier('place'); |
33 |
refreshSend(); |
34 |
refreshFinalize(); |
35 |
return true; |
36 |
}
|
37 |
});
|
38 |
});
|
39 |
|
40 |
JS; |
41 |
$position = \yii\web\View::POS_READY; |
42 |
$this->registerJs($script, $position); |
43 |
?>
|
Les fonctions ci-dessus faites l’appel à actionSet()
à MeetingPlaceChoiceController
de répondre au changement interrupteur à l’aide de requêtes Ajax :
1 |
public function actionSet($id,$state) |
2 |
{
|
3 |
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; |
4 |
// caution - incoming AJAX type issues with val
|
5 |
$id=str_replace('mpc-','',$id); |
6 |
//if (Yii::$app->user->getId()!=$mpc->user_id) return false;
|
7 |
if (intval($state) == 0 or $state=='false') |
8 |
$status = MeetingPlaceChoice::STATUS_NO; |
9 |
else
|
10 |
$status = MeetingPlaceChoice::STATUS_YES; |
11 |
//$mpc->save();
|
12 |
MeetingPlaceChoice::set($id,$status,Yii::$app->user->getId()); |
13 |
return $id; |
14 |
}
|
Actions du contrôleur qui répondent via Ajax ont besoin d’avoir un format JSON de la réponse (de cette façon Yii sait qu'ils ne sont pas destinés à livrer HTML) :
1 |
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; |
Voici la méthode MeetingPlaceChoice::set()
, qui enregistre les actions de l’utilisateur dans la base de données et crée une entrée de MeetingLog, qui regarde toutes les modifications lors de la planification.
1 |
public static function set($id,$status,$user_id = 0,$bulkMode=false) |
2 |
{
|
3 |
$mpc = MeetingPlaceChoice::findOne($id); |
4 |
if ($mpc->user_id==$user_id) { |
5 |
$mpc->status = $status; |
6 |
$mpc->save(); |
7 |
if (!$bulkMode) { |
8 |
// log only when not in bulk mode i.e. accept all
|
9 |
// see setAll for more details
|
10 |
if ($status==MeetingPlaceChoice::STATUS_YES) { |
11 |
$command = MeetingLog::ACTION_ACCEPT_PLACE; |
12 |
} else { |
13 |
$command = MeetingLog::ACTION_REJECT_PLACE; |
14 |
}
|
15 |
MeetingLog::add($mpc->meetingPlace->meeting_id,$command,$mpc->user_id,$mpc->meeting_place_id); |
16 |
}
|
17 |
return $mpc->id; |
18 |
} else { |
19 |
return false; |
20 |
}
|
21 |
}
|
Caractéristiques liées à l’évolution de la réunion
En Meeting Planner, j’ai garder un journal de chaque modification unique. Cela me permet de savoir quand quelques minutes se sont écoulées depuis le dernier changement de la personne et de notifier les autres participants à la réunion. C’est une expérience que j’essaie avec ce service, au lieu de demander qui a frappé les participants soumettre chaque fois qu’ils veulent faire des changements.
Cependant, cette technique nécessite formation à comprendre c’est OK changer et laissez-le, c'est-à-dire de fermer la fenêtre du navigateur. Ainsi les fonctions de displayNotifier()
montrer certaines alertes flash pour aider à cela, je vais finalement polonais de ceux-ci au fil du temps et retirez-les pour les utilisateurs expérimentés.
Le MeetingLog me permet aussi de générer un résumé du texte de l’histoire de planification de la réunion. Si vous êtes intéressé à en apprendre plus à ce sujet, j’ai écrit à ce sujet dans Building Your Startup : notification personnes sur réunion changements et fournir des Notifications.
Ce qui est prévu ?
J’espère que ces exemples vous aident à comprendre les bases d’Ajax dans Yii. Si vous êtes intéressé par Ajax plus avancé, j’ai l’intention d’inclure des formulaires Ajax chargé dans la série de Meeting Planner. Et, certes, Ajax est un domaine où la communauté Yii n’a pas partagé beaucoup d’exemples. En règle générale, Ajax fonctionne de manière similaire dans Yii comme elle le fait en PHP et d’autres cadres, vous pouvez apprendre des exemples d’autres communautés de cadre.
Surveillez les prochains tutoriels dans notre série de programmation avec Yii2 alors que nous continuons à plonger dans les différents aspects du cadre. Vous pouvez également consultez notre série de bâtiment votre démarrage avec PHP, qui utilise le modèle de pointe de Yii2 que nous créons une application réelle.
Si vous souhaitez savoir quand le prochain tutoriel de Yii2 arrive, me suivre @reifman sur Twitter ou voir ma page de l’instructeur. Ma page instructeur comprendra tous les articles de cette série dès qu’elles sont publiées.
Liens connexes
- Ajax (Wikipedia)
- Mise en route - Ajax (réseau de développeurs Mozilla)
- Yii2 Developer Exchange, mon site de ressources Yii2