Yii - Design question - Keeping dialoges separate from the main view file and accessing them - yii

I have a case where on my view file there are 6 links and clicking on them opens CJuiDialog boxes . I am keeping all the 6 dialog boxes code in the same view file along with links and that is causing the file to be big and loading them all together once .The ideal scenario is the dialog boxes should get loaded only when the use clicks on the links .
So is there any way we can keep only the links code in the main view file and keeping all the dialogue boxes in separate files and loading them only when the user clicks on the links
I mean
index.php ( view containing only links)
_dialog1 ( containing code for first dialog )
_dialog2 ( containing code for second dialog )
_dialog3 ( containing code for third dialog )
_dialog4 ( containing code for fourth dialog )
_dialog5 ( containing code for fifth dialog )
_dialog6 ( containing code for sixth dialog )
Sample Code
//First Dialog code
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog1',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>false,
'modal'=>true,
),
));
echo 'First dialog content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
echo CHtml::link('open dialog', '#', array(
'onclick'=>'$("#mydialog1").dialog("open"); return false;',
));
//2nd dialog code
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog2',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>false,
'modal'=>true,
),
));
echo 'dialog2 content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
echo CHtml::link('open dialog', '#', array(
'onclick'=>'$("#mydialog2").dialog("open"); return false;',
));
Solution I came with
//In controller
public function actionOpenDialog1()
{
$data = array();
$this->renderPartial('_dialogContent1', $data, false, true);
}
public function actionOpenDialog2()
{
$data = array();
$this->renderPartial('_dialogContent2', $data, false, true);
}
//In index.view
<div id="data">
</div>
<?php
echo CHtml::ajaxButton ("Open first dialog", CController::createUrl('dialogTesting/openDialog1'),array('update' => '#data'));
echo CHtml::ajaxButton ("Open second dialog", CController::createUrl('dialogTesting/openDialog2'),array('update' => '#data'));
?>
//_dialogContent1.php
<?php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog1',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>true,
'modal'=>true,
),
));
echo 'first dialog content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
?>
//_dialogContent2.php
<?php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog1',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>true,
'modal'=>true,
),
));
echo 'first dialog content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
?>
Thanks a lot for your help
Regards
Kiran

Naming files
The convention in Yii is to name the view files:
index.php: a full view
_dialog1.php: a partial view (included from another view)
Sub views
Then you can include partial views with CController::renderPartial():
$this->beginWidget(...);
$this->renderPartial('_dialog1', array('var1' => 23, 'var2' => "var"));
$this->endWidget(...);
Factorizing code
This should make your source node much lighter. But I suggest you go farther and avoid duplicating all those widget calls. To do this, you should define a structure for your dialog parameters and loop over it. Something like:
$dialogs = array(
'mydialog1' => array(
'file' => '_dialog1',
'options' => array('title' => "My title 1",),
),
'mydialog2' => array(
'file' => '_dialog12,
'options' => array('title' => "My title 2",),
),
);
$defaultOptions = array(
'autoOpen' => false,
'modal' => true,
);
foreach ($dialogs as $id => $dialog) {
$this->beginWidget(
'zii.widgets.jui.CJuiDialog',
array(
'id' => $id,
'options' => CMap::mergeArray($defaultOptions, $dialog['options']),
)
);
// ... include partial view ...
This factorization will make your code more compact, but it will above simplify the future changes. Using data structures to avoid code duplication is a well-known practice.
AJAX
Lastly, if you really want the partial views to be loaded dynamically, that means you have to use AJAX. Be careful, because your page may be less reactive from a user point of view. If all your forms amount to a few Kb of HTML, then there's no nedd for AJAX. But if you go this way, then you'll need to:
Add an CJuiDialog containing just <div id="dialog-ajax"></div>.
Create another action that will apply renderPartial() on the dialog views.
Replace the content of the previous foreach loop with code that writes JS like function dialog1() {jQuery("#dialog-ajax").load(...);}. You'll need to hack if you want to change dynamically the widget title.
Bind some events (clicks) to these JS functions.
Another way would be to make your aJAX action render a full CJuiDialog, it might be simpler and avoid JS hacks. Anyway, I'm not sure you really need AJAX.

My answer
//In controller
public function actionOpenDialog1()
{
$data = array();
$this->renderPartial('_dialogContent1', $data, false, true);
}
public function actionOpenDialog2()
{
$data = array();
$this->renderPartial('_dialogContent2', $data, false, true);
}
//In index.view
'#data'));
echo CHtml::ajaxButton ("Open second dialog", CController::createUrl('dialogTesting/openDialog2'),array('update' => '#data'));
?>
//_dialogContent1.php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog1',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>true,
'modal'=>true,
),
));
echo 'first dialog content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
?>
//_dialogContent2.php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog1',
'options'=>array(
'title'=>'Dialog box 1',
'autoOpen'=>true,
'modal'=>true,
),
));
echo 'first dialog content here';
$this->endWidget('zii.widgets.jui.CJuiDialog');
?>

You can simply include one empty CJuiDialog in your page, and when it needs to be displayed load the contents with jQuery AJAX (load is the simplest, and probably enough) that returns a render of the appropriate view before opening the dialog.

Related

: yii ajaxSubmitButton won't recognize my action url

I have an update form, and within that form there is a table where I want to populate using ajax after filling in a couple of fields. I have tried using ajaxSubmitButton but somehow it just doesn't trigger the action that I want.
Here is my view:
<?php
echo CHtml::ajaxSubmitButton('Insert', array('myController/insertProgress'), array(
'type' => 'POST',
'success' => 'function(){
alert("success");
}',
'data' => array(
'progress' => 'js:$("#progress").val()',
),
)
);
?>
myController:
public function actionInsertProgress() {
$data = $_POST['progress'];
//do stuff here, including echoing the table row
}
When I click the submit button, it doesn't trigger the insertProgress action, but instead the main form action which is actionEdit. It's as if the URL that I provided is being ignored.
The url for this form goes something like this:
(sitename)/(modulename)/myController/edit/id/57
Thank you.
EDIT: I do have another submit button to update the whole form, which triggers the actionEdit action.
EDIT2: this is what the widget produces:
<script type="text/javascript">
/*<![CDATA[*/
jQuery(function($) {
jQuery('body').on('click','#yt0',function(){jQuery.ajax({'type':'POST','data':{'progress':$("#progress").val()},'url':'http://inarac.id/adm/topikkajian/insertProgress','cache':false});return false;});
});
/*]]>*/
</script>
If you are using module you should add the modele path to your link
$myLink = Yii::app()->getBaseUrl(true) .
'/index.php/moduleName/myController/insertProgress';
<?php
echo CHtml::ajaxSubmitButton('Insert',
$myLink, array(
'type' => 'POST',
'success' => 'js:function(){
alert("success");
}',
'data' => array(
'progress' => 'js:$("#progress").val()',
),
)
);
?>

Yii widgets.TbThumbnails Pagination

I am using this 'widgets.TbThumbnails' from bootstrap to show the list of items as thumbnails. It shows first 10 items in one page and another 10 items on the other page. further it shows page navigator button at the bottom of the page. I tried to show all the items in a single page, but couldn't. If anyone know please help me to fix this. here is my code for thumbnail view
<?php $dataProvider = new CActiveDataProvider('Symptoms');
$this->widget('ext.bootstrap.widgets.TbThumbnails',
array(
'dataProvider' => $dataProvider,
//'template' => "{items}\n{pager}",
'itemView' => '_thumb',
//'htmlOptions' => array('style' => 'width:975px;','height:1020px'),
)
);
?>
Well that is due to the fact that dataProvider uses default settings for pagination.
Cpagination has a property named pageSize which refers to the the number of items per page. By default this is set to 10 thats why you can see 10 items per page.
Here is Official documentation.
You can do like this:
<?php
$dataProvider = new CActiveDataProvider('Symptoms', array(
'pagination'=>false
));
$this->widget('ext.bootstrap.widgets.TbThumbnails', array(
'dataProvider' => $dataProvider,
'itemView' => '_thumb',
)
);
?>

Yii: AjaxLink and ajax loaded section`s ajaxlink have same id yt0

i have table with ajax link`s
<?php
$this->widget('bootstrap.widgets.TbGridView', array(
'dataProvider'=>$dataProvider,
'template'=>"{items}\n{pager}",
'id'=>'tasklist',
'columns'=> array(
array('header'=>'',
'type' => 'raw',
'name'=>'complete',
'value'=>'"<i class=\"type glyphicon glyphicon-".$data->type->class."\"></i>"',
//'value'=>'$data->type->name',
'htmlOptions'=>array('class'=>'tdleft'),
),
array('header'=>'Title',
'type' =>'raw',
'value'=>'CHtml::ajaxLink($data->title,array("task/show", "id"=>$data->id), array("replace"=>"#taskdesc"))',
),
array('header'=>'Project',
'type' =>'raw',
'value'=>'CHtml::link($data->project->title,array("#"), array("data-toggle"=>"tooltip", "data-placement"=>"top","title"=>$data->project->title))',
'htmlOptions'=>array('class'=>'tdpr'),
),
)
));
?>
And in same page , at right section have
<div id="taskdesc"></div>
So, when user click on "Title", in div rendered some view (via rederPartial in the Controller), here is my controller`s action
public function actionShow($id)
{
$this->renderPartial('_show',
array('model'=>$this->loadModel($id)), false, true);
}
in my _show view there are new ajaxLink and my problem is here, this ajaxlink NOT WORKing, because this one has same id attribute "yt0". if i add new id attribute, then i have just working link, not ajax. ajaxlink not working. There are conflict with ajaxlink with same id attributes
Please, how can i solve this problem.

Pass Radio Button Value Onchange

In Yii, the list view used as a search result.
Controller
public function actionSearch()
{
$key=$_GET['Text'];
$criteria = new CDbCriteria();
$criteria->addSearchCondition('username',$key,true,"OR");
$criteria->select = "`username`,`country`";
$data=new CActiveDataProvider('User',
array('criteria'=>$criteria,'pagination'=>array('pageSize'=>5),
));
$this->render('search', array(
'ModelInstance' => User::model()->findAll($criteria),
'dataProvider'=>$data,
));
}
search.php
<?php
//THE WIDGET WITH ID AND DYNAMICALLY MADE SORTABLEATTRIBUTES PROPERTY
$this->widget('zii.widgets.CListView', array(
'id'=>'user-list',
'dataProvider'=>$dataProvider,
'itemView'=>'results',
'template' => '{sorter}{items}{pager}',
));
?>
<?php echo CHtml::radioButtonList('type','',array(
'1'=>'Personal',
'2'=>'Organization'),array('id'=>'type'),array( 'separator' => "<br/>",'style'=>'display:inline')
);
?>
result.php
<?php echo $data->username."<br>"; ?>
<?php echo $data->country; ?>
The user model fields are id, name , country, type, The search result shows the name and country. Now want to filter the results based on the radio button onchange (personal/organisation).
You could try to use $.fn.yiiListView.update method passing list view's id (user-list in your case) and ajax settings as arguments. data property of ajax settings is what can be used to specify GET-parameters that will be passed to your actionSearch to update the list view. So you have to analyze these parameters in the action and alter CDbCriteria instance depending on them.
The following script to bind onchange handler to your radio button list is to be registered in the view:
Yii::app()->clientScript->registerScript("init-search-radio-button-list", "
$('input[name=\"type\"]').change(function(event) {
var data = {
// your GET-parameters here
}
$.fn.yiiListView.update('user-list', {
'data': data
// another ajax settings if desired
})
});
", CClientScript::POS_READY);
You also may consider the following code as an example based on common technique of filtering CGridView results.
By the way, for performance reasons you can render your view partially in the case of ajax update:
$view = 'search';
$params = array(
'ModelInstance' => User::model()->findAll($criteria),
'dataProvider' => $data
);
if (Yii::app()->request->isAjaxRequest)
$this->renderPartial($view, $params);
else
$this->render($view, $params);

Creating Lookup field for Yii

I'm trying to make a lookupfield-like in my application.
The intention is that the user click on a browse-button, and it pops-up a dialog(widget) with a grid(CGridView) inside. The user could select a row, and the 'Description' column is sent to a textField into my form.
I've already done this part by registering the following script in the form:
Yii::app()->clientScript->registerScript('scriptName', '
function onSelectionChange()
{
var keys = $("#CGridViewUsuario > div.keys > span");
$("#CGridViewUsuario > table > tbody > tr").each(function(i)
{
if($(this).hasClass("selected"))
{
$("#Funcionario_UsuarioId").val($(this).children(":nth-child(1)").text());
}
});
}
');
And my widget:
<?php $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog',
'options'=>array(
'title'=>'Usuário',
'width' => 'auto',
'autoOpen'=>false,
),
));
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => Usuario::model()->searchByLogin($model->UsuarioId),
'id' => 'CGridViewUsuario',
'filter' => Usuario::model(),
'columns' => array(
'Login',
'Nome',
),
'htmlOptions' => array(
'style'=>'cursor: pointer;'
),
'selectionChanged'=>'js:function(id){ onSelectionChange(); }',
));
$this->endWidget('zii.widgets.jui.CJuiDialog');
?>
Now there are two tasks for me to do:
When the user clicks the browse button, the CGridView should appear
with the filter already filled with the input he typed in the form.
Put the CGridView filters to work.
Not forgetting that, If all this runs successfully, when the user clicks on the save button, I'll have to save the corresponding ID of the lookupField in the model.
You can, simply provide a callback function for the dialog's open event, and in the callback function
use jquery selectors to select the input filters(of the gridview) you want to select, and populate its values from whichever field in the form you want:
$("#CGridViewUsuario .filters input[name='Userio[login]']").val($("#Funcionario_UsuarioId").val());
// replace the names/ids to whatever you are using,
// if you want to set multiple values, then you might have to run a loop or each() or something of that sort
then call the server to update the gridview according to the values you populated, using jquery.yiigridview.js' $.fn.yiiGridView.update function:
$.fn.yiiGridView.update("CGridViewUsuario", {
data: $("#CGridViewUsuario .filters input").serialize()
});
you can see the jquery.yiigridview.js file in the generated html, or in your assets folder, and within that you'll find the $.fn.yiiGridView.update function.
To subscribe to the dialog's open event you can pass the function name to the 'open' option of the dialog's 'options' field:
$this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id'=>'mydialog',
'options'=>array(
'title'=>'Usuário',
// other options
'open'=>'js:dialogOpenCallback'
),
));
And you can define the function in your registerScript() call itself:
<?php
Yii::app()->clientScript->registerScript('scriptName', '
function onSelectionChange()
{...}
function dialogOpenCallback(event,ui){
$("#CGridViewUsuario .filters input[name='Userio[login]']").val($("#Funcionario_UsuarioId").val());
// replace the names/ids to whatever you are using,
$.fn.yiiGridView.update("CGridViewUsuario", {
data: $("#CGridViewUsuario .filters input").serialize()
});
}
');
Further you can change how you are calling your onSelectionChange() function:
'selectionChanged'=>'js:onSelectionChange'//'js:function(id){ onSelectionChange(); }',
and change your function signature: function onSelectionChange(id).
Almost forgot, change your dataprovider and filter of the gridview, to model instances, and not static instances.