How to pass literal JavaScript code to Yii framework methods? - php

I am generating a checkbox using the corresponding method of CHtml, and I want to run some JavaScript code before and after the AJAX request. Here is the code:
echo CHtml::checkBox('markComplete', FALSE,
array(
'class' => 'markComplete',
'ajax' => array(
'type' => 'POST',
'url' => $this->createUrl('/events/events/MarkComplete'),
'data' => 'event_status='.$events['id'],
'beforeSend' => 'function(){ $(this).parent("TR").hide(); }',
'success' => 'function(resp) { $("#right").append(resp); }'
),
)
);
How can I tell Yii that beforeSend and success are JavaScript code and not plain strings?

Better option available starting from Yii 1.1.11
All framework classes now support custom JavaScript snippets through CJavaScriptExpression. Use it like this:
'ajax' => array(
'beforeSend' => new CJavaScriptExpression(
'function(){ $(this).parent("TR").hide(); }'
),
// ...
)
The option of prefixing strings with js: is still available by default, but it can now be disabled as required using an optional parameter on CJavaScript::encode.
Original answer
If you want to include literal JavaScript code as part of options, the convention in Yii is to prefix the code with js:. So you would write it like this:
'ajax' => array(
'type'=>'POST',
'url'=>$this->createUrl('/events/events/MarkComplete'),
'data'=>'event_status='.$events['id'],
'beforeSend' => 'js:function(){
$(this).parent("TR").hide();
}',
'success'=>'js:function(resp) {
$("#right").append(resp);
}'
),
)
Unfortunately this is not well documented, which is why people run into exactly this problem every now and then.

Related

is there any Replacement of inputDefaults(CakePHP) in CakePHP3?

In CakePHP2 we use FormHelper's inputDefault options to set default values for all input within form
For Example :
echo $this->Form->create('User', array(
'inputDefaults' => array(
'required' => false,
'error' => false,
'div' => 'form-group',
'label' => false
)
));
But i am not finding any option in CakePHP3 helper like this, they haven't mentioned removed it or not?
Is anybody there, who know about this....
Thanks
According to migration guide inputDefaults option was removed.
The inputDefaults option has been removed from create().
FormHelper::inputDefaults() has been removed. You can use templates() to define/augment the templates FormHelper uses.
templates() method of FormHelper documentation you can find here.

Select2 ajax option using YII Framework

I am using Yii framework on a project and i am using an extension which uses select2 jquery. I am unable to grasp how the implementation for ajax works with this extension or the select2.
My ajax call returns the following json.
[
{"id":"1", "text" : "Option one"},
{"id":"1", "text" : "Option one"},
{"id":"1", "text" : "Option one"}
]
The yii extension enfolds the select2 extension as below
$this->widget('ext.select2.ESelect2', array(
'name' => 'selectInput',
'ajax' => array(
'url'=>Yii::app()->createUrl('controller/ajaxAction'),
'dataType' => 'json',
'type' => 'GET',
'results' => 'js:function(data,page) {
var more = (page * 10) < data.total; return {results: data, more:more };
}',
'formatResult' => 'js:function(data){
return data.name;
}',
'formatSelection' => 'js: function(data) {
return data.name;
}',
),
));
I found a related question from this Question! The link to the extension am using is YII select2 Extention!
So a week later i merged with the answer to this question.
First let me highlight how the select2 ajax or in my case the Yii ESelect Extension.
The ajax options for jquery are the same as for the Eselect Extention i.e. url,type and datatype altho there is a slight difference on the format returned after successfully querying.
As for the result set for Eselect/select2 expects two parameters to be returned. that is
id : data.myOptionsValue;
text : data.myOptionText;
Reference :: https://select2.github.io/options.html#ajax
if we want to customize the format for the result set that is retured we can go a head and extend the plugin by using
'formatResult' => 'js:function(data){
return data.name;
}',
'formatSelection' => 'js: function(data) {
return data.name;
}',
I also had an issue getting my head around how the extention was quering. A look around and i realised that we have two datatype jsonp and json these two datatypes will handle data differently.
Jsonp (json padding) allows sending query parameters when querying. As for my case i am not passing any other parameters e.g an authkey e.t.c. In my case i changed the datatype to json and returning a json with id and text as results. See below my working snippet.
echo CHtml::textField('myElementName', '', array('class' => 'form-control col-lg-12'));
$this->widget('ext.select2.ESelect2', array(
'selector' => '#myElementName',
'options' => array(
'placeholder' => 'Search ..',
'ajax' => array(
'url' => Yii::app()->createUrl('controller/ajaxAction'),
'dataType' => 'json',
'delay' => 250,
'data' => 'js: function(term) {
return {
q: term,
};
}',
'results' => 'js: function(data){
return {results: data }
}',
),
),
));

How do I retain query params in the pagination URLs in ZF2?

I am using Zend\Paginator to construct a paginated result set. This works fine, however, after adding a search form, I cannot get the two to play nicely together.
The URL produced by the search form on the page is:
user/index/?searchTerm=hello
How do I amend the Zend paginator configuration so that it retains the searchTerm in the URLs produced?
I was hoping for something like:
user/index/page/4/?searchTerm=hello
What am I missing?
The module config route is defined as follows:
'user' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/user[/[:action[/]]][[id/:id]][/[page/:page]]',
'defaults' => array(
'controller' => 'Application\Controller\User',
'action' => 'index',
'id' => null,
),
// the below was added to try and get the searchTerm query to be retained
'may_terminate' => true,
'child_routes' => array(
'searchTerm' => array(
'type' => 'Query',
),
),
),
),
The pagination is constructed using this in the view:
echo $this->paginationControl(
$this->users, 'sliding', array('paginator', 'User'), array('route' => 'user', 'action' => 'index')
);
Pagination template snippet:
<li>
<a href="<?php echo $this->url($this->route, array('action' => $this->action, 'page' => $this->next), true); ?>">
Next ยป
</a>
</li>
(I was under the impression that passing true as the third parameter to url() would retain the query params.)
I now see what that third parameter to url() is doing. I can simplify the pagination links and remove the 'action' key as follows:
<a href="<?php echo $this->url($this->route, array('page' => $this->next), true); ?>">
The page's action was matched as part of the URL (due to that third param being true) which is why that works. By the same token I can change the route to this:
'route' => '/user[/[:action[/]]][[id/:id]][/[page/:page]][/[search/:search]]',
And then the search will be retained in the pagination links.
If I amend the search form to submit via JavaScript, I can construct the search URL and direct the user to it.
Simple jQuery example for that approach:
$(".search-form").submit(function() {
var baseUrl = $(this).attr('action'),
search = $(this).find('.search').val();
window.location = baseUrl + '/search/' + search;
return false;
});
Another option would be to redirect to the current/route/search/term route in the controller if it receives a searchTerm query.
I'm posting this as an answer but I am open to better solutions.

Send model attributes to Yii controller using ajax

I'm currently using the following code to send an Ajax get request to my controller:
echo CHtml::ajaxLink('clickMe', array('ajax'), array('update'=>'#results'));
This works fine, the controller receives the request and updates the view accordingly.
Now, I want to send in this request attributes of the model, i.e. from model->getAttributes();
How should I do this? Create a JSON object of the attributes and send that with the request?
Just pass 'data' attribute and 'type' if needed:
echo CHtml::ajaxLink('clickMe', array('ajax'), array(
'update' => '#results'
'data' => CJSON::encode($model->attributes),
'type' => 'post',
));
This code just replaces #results contents with json. If you need something different, use 'success' instead of 'update' like this:
echo CHtml::ajaxLink('clickMe', array('ajax'), array(
'success' => 'function (response) {
// do everything you need
}',
'data' => CJSON::encode($model->attributes),
'type' => 'post',
));
Take a look at jquery ajax options for more information.

Retain Checkbox values in Yii gridview pagination

I have a gridview which contains a checkbox column and also uses pagination. When I check some checkboxes in the first page and navigate to the second page and check another one in the second page, the options I checked in the first page is not retained there. Is it posssible to retain the checkbox values during pagination?
Code for Gridview is
$widget = $this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
//'filter' => $model,
'ajaxUpdate' => true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header' => 'Selected',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
array(
'name' => 'demo',
'type' => 'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
),
));
Edit:
Extension for remembering the selected options in gridview,check this link Selgridview
Thanks to bool.dev
You could use sessions/cookies to store the checked values. I'm not very sure how to make cookies work, so i'll tell you how to do it with sessions. Specifically the user session that yii creates.
Now to use sessions we need to pass the checked (and unchecked) ids to the controller, therefore we'll modify the data being sent to the controller on every ajax update(i.e between paginations), to do this we exploit the beforeAjaxUpdate option of CGridView.
I'm also using CCheckBoxColumn instead of the following in your code(of course you can modify the solution to suit your own needs):
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' => 'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
GridView Changes:
<?php $this->widget('zii.widgets.grid.CGridView', array(
// added id of grid-view for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'id'=>'first-grid',
'dataProvider'=>$model->search(),
'cssFile' => Yii::app()->baseUrl . '/media/js/admin/css/admingridview.css',
// added this piece of code
'beforeAjaxUpdate'=>'function(id,options){options.data={checkedIds:$.fn.yiiGridView.getChecked("first-grid","someChecks").toString(),
uncheckedIds:getUncheckeds()};
return true;}',
'ajaxUpdate'=>true,
'enablePagination' => true,
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'name' => 'fb_user_id',
'header' => 'FaceBook Id',
'value' => 'CHtml::encode($data->fb_user_id)',
),
array(
'name' => 'first_name',
'header' => 'Name',
'value' => 'CHtml::encode($data->first_name)',
),
array(
'name' => 'email_id',
'header' => 'Email',
'value' => 'CHtml::encode($data->email_id)',
),
/* replaced the following with CCheckBoxColumn
array(
'name' => 'demo',
'type'=>'raw',
'header' => "Select",
'value' =>'CHtml::checkBox("email[]","",array("class"=>"check","value"=>$data->email_id))',
),
*/
array(
'class' => 'CCheckBoxColumn',
'selectableRows' => '2',
'header'=>'Selected',
'id'=>'someChecks', // need this id for use with $.fn.yiiGridView.getChecked(containerID,columnID)
'checked'=>'Yii::app()->user->getState($data->email_id)', // we are using the user session variable to store the checked row values, also considering here that email_ids are unique for your app, it would be best to use any field that is unique in the table
),
),
));
?>
Pay special attention to the code for beforeAjaxUpdate and CCheckBoxColumn, in beforeAjaxUpdate we are passing checkedIds as a csv string of all the ids(in this case email_ids) that have been checked and uncheckedIds as a csv string of all the unchecked ids, we get the unchecked boxes by calling a function getUncheckeds(), which follows shortly. Please take note here, that when i was testing i had used an integer id field (of my table) as the unique field, and not an email field.
The getUncheckeds() function can be registered like this anywhere in the view file for gridview:
Yii::app()->clientScript->registerScript('getUnchecked', "
function getUncheckeds(){
var unch = [];
/*corrected typo: $('[name^=someChec]') => $('[name^=someChecks]') */
$('[name^=someChecks]').not(':checked,[name$=all]').each(function(){unch.push($(this).val());});
return unch.toString();
}
"
);
In the above function pay attention to the selectors and each and push function.
With that done, we need to modify the controller/action for this view.
public function actionShowGrid(){
// some code already existing
// additional code follows
if(isset($_GET['checkedIds'])){
$chkArray=explode(",", $_GET['checkedIds']);
foreach ($chkArray as $arow){
Yii::app()->user->setState($arow,1);
}
}
if(isset($_GET['uncheckedIds'])){
$unchkArray=explode(",", $_GET['uncheckedIds']);
foreach ($unchkArray as $arownon){
Yii::app()->user->setState($arownon,0);
}
}
// rest of the code namely render()
}
That's it, it should work now.
For developing that scheme you would need to know working of what happens when you navigate.
When ever you navigate to a pagination page ajax calls are made and new data is received and it is fetched from CActive Record or what ever the data source. New data is in accordance of database records or source records. when you come back to previous page again Ajax call is made and content is updated so same comes as it is in database.
what i feel is you should save data of checked items temporary and make it permanent if action is made.
You can do something like this
<script type="text/javascript">
$("input:checkbox").click(function () {
var thisCheck = $(this);
if (thisCheck.is (':checked')){
// do what you want here, the way to access the text is using the
// $(this) selector. The following code would output pop up message with
// the selected checkbox text
$(this).val());
}
});
</script>
you can save temporary storage somewhere
Also make this work on normal form submit:
I wanted to add this as a comment on bool.dev's answer, but I do not have enough reputation to do that yet. So I had to put it in a separate answer.
bool.dev, your answer is great and it works well, thanx.
However, as intended, it only works when ajax calls update the gridview. I have the gridview forming part of a form, so I wanted it to also work on normal submission of the form, otherwise the checkboxes are not loaded again when there are other validation errors on the form.
So, in ADDITION to what you did, I added hidden fields on my form e.g.:
<input type="hidden" name='checkedBox1' id='checkedBox1' value=''>
<input type="hidden" name='uncheckedBox1' id='uncheckedBox1' value=''>
Then, before submitting the form, my sumbit button runs your getChecked() and getUncheckeds() functions and store their results in the hidden fields:
if ($('#checkedBox1').length >0) {$('[name=checkedBox1]').val(getChecked());}
if ($('#uncheckedBox1').length >0) {$('[name=uncheckedBox1]').val(getUncheckeds());}
In the controller, besides from checking for $_GET['checkedIds'], you also check for $_POST['checkedBox1'] and store its values to session in the same way you do for $_GET['checkedIds'], using the same session variable.
Do the same with $_POST['uncheckedBox1'].
That should work.

Categories