I need to understand how to build Ajax request in Yii. I searched on the Yii website and found the following article :
http://www.yiiframework.com/wiki/24/
I wrote the code and I tested it on my localhost ? but for some reason it did not work.
For a first attempt I only wanted to do something simple. I wanted to print the result of another action on my page by using Ajax. The text that I want to be displayed is 'Hi'.
This is how mu code looks like for that action:
view/index
<?php
/* #var $this CurrentController */
$this->breadcrumbs=array(
'Current'=>array('/current'),
'index',
);
?>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'users-index-form',
'enableAjaxValidation'=>true,
)); ?>
<?php
echo CHtml::dropDownList('country_id','', array(1=>'USA',2=>'France',3=>'Japan'),
array(
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('currentController/dynamiccities'), //url to call.
//Style: CController::createUrl('currentController/methodToCall')
'update'=>'#city_id', //selector to update
//'data'=>'js:javascript statement'
//leave out the data key to pass all form values through
)));
//empty since it will be filled by the other dropdown
echo CHtml::dropDownList('city_id','', array());
?>
<?php $this->endWidget(); ?>
</div><!-- form -->
Controller
<?php
class CurrentController extends Controller
{
public function accessRules()
{
return array(
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update','dynamiccities'),
'users'=>array('#'),
),
);
}
public $country_id;
public function actionIndex()
{
$this->render('index');
}
public function actionDynamiccities() /// Called Ajax
{
echo CHtml::tag('option',
array('value'=>'2'),CHtml::encode('Text'),true);
}
}
Unfortunately I'm not getting the desired result. What I get is:
drowpdown list contains country array.
another drowpdown list but empty ?!
How should I fix my example code so it would work? Can anyone see what I am doing wrong?
echo CHtml::dropDownList('city_id','', array());
use id as
echo CHtml::dropDownList('city_id','', array('id'=>'city_id'));
Related
I have the following view named 'findreseller.php':
<?php
$countries = CHtml::listData(Country::model()->findAll(), 'id', 'name');
echo CHtml::dropdownlist('find_reseller', '', $countries,
array('ajax'=>array(
'type'=>'POST',
'url'=>Yii::app()->getController()->createAbsoluteUrl('/webcare/reseller/loadAjaxData'),
'update' =>'#data',
)
)
);
?>
<div id="data">
<?php $this->renderPartial('_ajaxContent', array('dataProvider'=>$dataProvider))?>
</div>
_ajaxContent just echoes the result, nothing special there...
The dropdown, as you can see is generated with CHtml because I dont't need a form. I just need an onChange event to do something...
As per the code that follows, in '/webcare/reseller/loadAjaxData' I have:
public function actionLoadAjaxData() {
$country = $_POST['find_reseller'];
//do something...
$dataProvider=new CArrayDataProvider($country_reseller);
$this->render('findreseller', array('dataProvider' => $dataProvider));
}
I can tell that I am missing something, but I am not sure what exactly.
Edit
Modified like this:
<?php
//CHtml::form();
$countries = CHtml::listData(Country::model()->findAll(), 'id', 'name');
echo CHtml::dropdownlist('find_reseller', '', $countries,
array(
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('/webcare/reseller/loadAjaxData'), //url to call.
//Style: CController::createUrl('currentController/methodToCall')
'update'=>'#city_id', //selector to update
'data'=>'js: $(this).val()',
//leave out the data key to pass all form values through
)
)
);
//empty since it will be filled by the other dropdown
echo CHtml::dropDownList('city_id','', array());
//CHtml::endForm();
?>
<div id="data">
<?php $this->renderPartial('_ajaxContent', array('dataProvider'=>$dataProvider))?>
</div>
And now I get:
http://prntscr.com/42wwx6
And I have the following controller action:
public function actionLoadAjaxData() {
$country = $_POST['country_id'];
...
$dataProvider=new CArrayDataProvider($country_reseller);
$data = User::model()->findAll('country_id=:country_id AND reseller=:reseller',
array(':country_id'=>(int) $_POST['country_id'], ':reseller'=>1));
$data=CHtml::listData($data,'city','city');
foreach($data as $value=>$name)
{
echo CHtml::tag('option',
array('value'=>$value),CHtml::encode($name),true);
}
$this->render('action_name', array('dataProvider' => $dataProvider));
}
Edit 2
If I write a die in actionLoadAjaxData(), right at the beginning, the method is loaded fine, the action is ok and the server answers 200.
I have this code Im trying to save the content and the title from a form I made..It has an id that autoincrement the id number adds in the database but the title and the content isn't/cant be save in the database. Can you please check my code if I've done something wrong? or what I'm lacking at.
Here is my model ContentForm.php
<?php
class ContentForm extends CActiveRecord{
public $content;
public $title;
public function tableName(){
return 'tbl_content';
}
public function attributeLabels()
{
return array(
'contentid' => 'contentid',
'content' => 'content',
'title' => 'title',
// 'email' => 'Email',
// 'usrtype' => 'Usrtype',
);
}
Here is my view content.php
<div>
<p>User: <a href="viewuserpost">
<?php
echo Yii::app()->session['nameuser'];
?>
</a>
</p>
</div>
<h1>Content</h1>
<?php
$form=$this->beginWidget('CActiveForm', array(
'id'=>'contact-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
));
?>
Title:
<div class="row">
<?php
echo $form->textfield($model,'title');
?>
</div>
</br>
Body:
<div class="row">
<?php
echo $form->textArea($model,'content',array('rows'=>16,'cols'=>110));
?>
</div>
<div class="row buttons">
<?php
echo CHtml::submitButton($model->isNewRecord? 'Create':'Save');
?>
</div>
<?php $this->endWidget(); ?>
and here is my content action in my sitecontroller.php
public function actionContent(){
$model=new ContentForm;
if(isset($_POST['ContentForm'])) {
$model->attributes=$_POST['ContentForm'];
if($model->save())
$this->redirect(array('content','contentid'=>$model->contentid));
$this->redirect(array('content','title'=>$model->title));
$this->redirect(array('content','content'=>$model->content));
}
$this->render('content',array('model'=>$model));
}
Please help.
Remove
public $content;
public $title;
from your class.
Yii uses PHP magic methods. And when you add attributes to your class, PHP doesn't call them but references to your explicitly written attributes.
Moreover, you should add some validation, if you use $model->attributes=$_POST['ContentForm'];. Another variant is to use unsecure $model->setAttributes($_POST[ContentForm], false) where false tells Yii to set all attributes, not only that are considered safe.
Note, that attributes is not real Model attribute, this is virtual attribute accessed through magic methods.
Also, you don't need three redirects. This is HTTP redirect to other page. This time, you just should just specify route to model view action and its parameter that is id, for example. Like this $this->redirect(array('content/view','id'=>$model->contentid));.
Of course, simplest way for you is to create new model and controller with actions using Gii.
you may missed rules , add this in your model ContentForm.php
public function rules()
{
return array(
array('content,title', 'safe'),
);
}
For more about model validation
http://www.yiiframework.com/wiki/56/reference-model-rules-validation/
I'm really new to Yii and as a starter, I want to know how to get the value from the textbox when the button is pressed.
<?php CHtml::textField($name,$value,array('submit'=>'')); ?>
<?php echo CHtml::submitButton('Greet!',array(
'submit' => 'message/goodbye')); ?>
Keep your view some thing like
<?php
$form = $this->beginWidget('CActiveForm', array(
'id' => 'aForm',
'htmlOptions' => array('onsubmit'=>"return false;"),
));
?>
<?php echo CHtml::textField('name', 'value'); ?>
<?php echo CHtml::submitButton('Greet!', array('onclick' => 'getValue()'));?>
<?php $this->endWidget(); ?>
And the Action Script for the onclick event is
<script type="text/javascript">
function getValue()
{
$text=$("#aForm").find('input[name="name"]').val();
alert($text);
//$formData=$("#aForm").serialize();
}
</script>
UNDERSTANDING THE BASIC CONCEPT
You have to remember that Yii is an MVC framework ( Model, View Controller ) and the best practice is to keep the entire structure like so. The best way to learn it is from the awesome forum that they have.
Hence, to define a scenario where you would like to save a data/textbox from the form, you would be following the following workflow :
A BASIC WORKFLOW
Assuming that you don't want to save the data in the Database. :
I would be assuming that a basic knowledge of the how the framework works is known. You can check out the guide and the other tutorials if not.
This is a basic workflow in which the data would be taken from the form and validated in the model.
Create a model file in your protected/models folder
Example : Lets name this file as FormData.php
<?php
class FormData extends CFormModel{
public $name;
public $email;
public function rules()
{
return array(
array('name , email','required'), // This rule would make it compulsory for the data to be added.
array('email','email'), // This will check if the email matches the email criteria.
);
}
public function attributeLabels()
{
return array(
'name' => 'Enter your name',
'email' => 'Enter your email',
);
}
}
?>
2. After this , in your protected/FormController.php
Add this :
<?php
class Formdata extends CController{
public function actionCoolForm()
{
$model = new FormData();
if(isset($_POST['FormData'])){
$model->attributes = $_POST['FormData'];
if($model->validate()){
// Do whatever you want to do here.
}
}
$this->render('someview',array('model'=>$model));
}
}
?>
3. Now to add the form in your page is easy :
<?php echo CHtml::form('formdata/coolform','post'); ?>
<?php
echo CHtml::activeTextField($model,'name');
echo CHtml::activeTextField($model,'email');
?>
<?php echo CHtml::endForm(); ?>
Now to add it in the database
The best and the easiest method of adding it in the database is to use the Gii.
But the code is nearly identical, except that the model extends CModel.
I hope that I was able to help.
I am still very new to this Yii framework, and I would like assistance with this code. I currently manage to get a dropdownlist dependent on another dropdownlist but I can't seem to get the dropdownlist to effect what gets displayed in the ClistView.
profile Controller
/* add a team message submitted by the coach of the team */
public function actionAddTeamMessage($id)
{
/* check if team and message aren't null */
if(isset($_POST['teamId']['addTeamMessage']))
{
try
{
/* creates a new message */
$teamModel = new TeamMessage;
$teamModel->teamId = $_POST['teamId'];
$teamModel->content = $_POST['addTeamMessage'];
$teamModel->sendTime = new CDbExpression('NOW()');
$teamModel->save();
}
catch(Exception $e)
{
echo "Unable to save.";
}
}
/* render the profile page for the current user */
$user=User::model()->findByPk($id);
$this->render('profile', array(
'model' => $user));
}
/* will handle functionality for the user dropdownlist ajax
* under contructions
*/
public function actionDisplayMessage()
{
$data = TeamMessage::model()->findAll('teamId=:teamId', array(
':teamId'=>(int) $_POST['teamId']
)
);
$data=CHtml::listData($data,'id', 'content');
echo "<option value=''>Select Message</option>";
foreach($data as $value=>$content)
echo CHtml::tag('option', array('value'=>$value),CHtml::encode($content),true);
//TODO still being tested.
/* for ClistView still debugging */
/*$dataProvider=new CActiveDataProvider('Player', array(
'criteria'=>array(
'condition'=>'teamId=:teamId',
)));*/
}
View Profile
<!-- Would allow user to access specific team messages and control how much gets display.
still under construction. -->
<div class="row">
<?php
echo CHtml::dropDownList("teamId", 'id', Chtml::listData($model->memberOfTeams, 'id', 'teamName'),array(
'empty'=>'Select Team',
'ajax'=>array(
'type'=>'POST', // request type
'url'=>CController::createUrl('DisplayMessage'),
'update'=>'#teamMessages', // selector to update
'data'=>array('teamId'=>'js:this.value'),
)
)
);
?>
<?php
echo CHtml::dropDownList('teamMessages','',array(),array('empty'=>'Select Message'));
/*$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_viewTeamMessage',
'id'=>'ajaxListView',
));*/
?>
</div>
As you can see in the cListView. I was debating on creating a _viewTeamMessage which will display the team message + sendtime. But I realize, I wouldn't be able to pass a dataprovider without re rendering the page, and i am trying to avoid heading into that direction.
You could pull your Team messges out into a partial view and then just use a render partial to render just the messages into your page usig Ajax. If the partial view is named _teamMessages.php it would look something like this (untested):
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_viewTeamMessage',
'id'=>'ajaxListView',
));
Then you modify your profile view to look like:
<!-- Would allow user to access specific team messages and control how much gets display.
still under construction. -->
<div class="row">
<?php
echo CHtml::dropDownList("teamId", 'id', Chtml::listData($model->memberOfTeams, 'id', 'teamName'),array(
'empty'=>'Select Team',
'ajax'=>array(
'type'=>'POST', // request type
'url'=>CController::createUrl('DisplayMessage'),
'update'=>'.team-messages', // selector to update
'data'=>array('teamId'=>'js:this.value'),
)
)
);
?>
<div class="team-messages">
<?php
$this->renderPartial('_teamMessages',
array('dataProvider'=>$dataProvider))
?>
</div>
</div>
Then finally you change your controller to something like this:
public function actionDisplayMessage()
{
/* REMOVE
$data = TeamMessage::model()->findAll('teamId=:teamId', array(
':teamId'=>(int) $_POST['teamId']
)
);
$data=CHtml::listData($data,'id', 'content');
echo "<option value=''>Select Message</option>";
foreach($data as $value=>$content)
echo CHtml::tag('option', array('value'=>$value),CHtml::encode($content),true);
*/
// still being tested.
$dataProvider=new CActiveDataProvider('Player', array(
'criteria'=>array(
'condition'=>'teamId=(int) $_POST['teamId']',
)));
$this->renderPartial('_teamMessages', array('dataProvider'=>$dataProvider);
}
this should just cause the message widget to be recreated instead of the whole page.
I'm using Yii framework to create a really simple 1 text-area field and 2 hidden inputs with predefined values sent from the server.
The way it should work is as expected, I mean, you write something on that text-area and you click on the send button. An ajax validation is made (only requisite for the text-area is that is shouldn't be empty) and if validated, save the data and redirect to some other page.
The problem is that it won't save any data if validation error was triggered.
I mean, if I go to the page, write something and hit on the send button, data will be saved and I'll be redirected correctly. But if I go to the page, hit the send button (without typing anything in the text-area), wait for the error to appear (note that this is done via ajax, so no page-reload here), write something and hit send again Yii is going to start making a request after a request in an infinite loop.
I already have checked the data being sent, and everything is fine (both data and action-url).
Here is my Controller code
public function actionView($id)
{
$user = Usuario::model()->findByAttributes(
array(
'nick'=>Yii::app()->user->getId()
)
);
$dataProvider=new CActiveDataProvider('Mensaje', array(
'criteria'=>array(
'with'=>array('usuario', 'usuario.detallesusuario'),
'condition'=>'Tema_idtema='.$id
),
'pagination'=>array(
'pageSize'=>1000,
),
));
$this->render('view',array(
'model'=>$this->loadModel($id),
'usuario_id'=>$user->idusuario,
'tema_id'=>$id,
'dataProvider'=>$dataProvider,
));
}
public function actionCreateMessage(){
$model=new Mensaje;
$this->performAjaxValidation($model);
if(isset($_POST['Mensaje']))
{
$model->attributes=$_POST['Mensaje'];
$model->fecha_hora=new CDbExpression('NOW()');
$model->save();
$this->redirect(array('view', 'id'=>$model->Tema_idtema));
}
}
And the code from the View
<?php
$model = new Mensaje();
echo $this->renderPartial('_mensaje_form', array(
'model'=>$model,
'usuario_id'=>$usuario_id,
'tema_id'=>$tema_id,
),
false, //return instead of echo
true //post-process
);
?>
Here is the "_mensaje_form" code
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'mensaje-form',
'action'=>CHtml::normalizeUrl(array('tema/createMessage')),
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
'validateOnChange'=>false,
'validateOnType'=>false,
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="row" style="margin:20px 5px 0 176px;">
<?php echo $form->labelEx($model,'mensaje'); ?>
<?php echo $form->textArea($model,'mensaje',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'mensaje'); ?>
<?php echo $form->hiddenField($model, 'Tema_idtema', array('value'=>$tema_id)); ?>
<?php echo $form->hiddenField($model, 'Usuario_idusuario', array('value'=>$usuario_id)); ?>
</div>
<div class="row buttons" style="margin:-3px 0 -8px 176px;">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Responder' : 'Guardar'); ?>
</div>
<?php $this->endWidget(); ?>
Any idea why I'm getting that loop?
This might help you,
http://www.yiiframework.com/forum/index.php/topic/10427-ajax-clientscript/
in your view, the last parameter "true" in renderPartial may be the problem.
My guess (a bit long shot) that form id in your preformAjaxValidation() might be wrong, so it causes the loop! since it won't get in the body of the if and hence executes Yii::app()->end(); !!
Check it in your controller:
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='exact-form-id')//should be mensaje-form
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}