Always show Pager on CGridView? - yii

I've build a CGridView menu, and I want to always display the pager
(even when it's showing all the data and the navigation is not needed)
This is the current code I have:
$this->widget('zii.widgets.grid.CGridView',
array('dataProvider'=>$search,
'columns' => $columns,
'itemsCssClass' => 'list_table',
'template' => '{pager}{summary}{items}',
'pager' => array(
'cssFile'=>false,
'class'=>'CLinkPager',
'firstPageLabel' => '<<',
'prevPageLabel' => '<',
'nextPageLabel' => '>',
'lastPageLabel' => '>>',
'header' => '',
'footer' => $footer_btns,
),
'pagerCssClass' => 'pagination',
));

You could do this by overriding the renderPager() method -- however, it seems that the pager gets put together in a few files so one way to do it by only overriding one class would be to:
override zii.widgets.grid.CGridView to add your custom renderPager() method with something like:
Yii::import('zii.widgets.grid.CGridView');
class MyGrid extends CGridView {
public function renderPager() { ... }
}
the default renderPager() function is here.
What you want to do is look for the line that tests for pager content:
if($pager['pages']->getPageCount()>1) {
and change the "else" statement to put in your default "empty" pager content, which could use the same <ul> structure. Since you are not providing any navigation for the blank view, you don't need to worry about that data if this is used in multiple places. That could look something like:
else {
echo '<div class="'.$this->pagerCssClass.'">';
## YOUR CUSTOM "EMPTY PAGER" HTML HERE ##
echo '</div>';
}
You might need to define a couple extra css classes as well. On pages where only part of the pagination is showing (e.g., the first and last page), you can use CSS to redefine the ".hidden" class(es).

Related

how to pass the id of the click CButtonColumn of CGridView going to the controller in Yii1.x?

I have a custom CButtonColumn within the CGridView.
one of the custom buttons is firing a CJuiDialog. now the problem is,
how to pass the id when clicked, so that the Controller will get the id, then I can do pass a model and renderPartial it inside the CJuiDialog?
here's what i have so far
'see' => array(
'label' => 'View',
'url' => 'Yii::app()->controller->createUrl("mycontrollerName/view,array("id" => "$data->id"))',
'click' => "function( e ){
e.preventDefault();
$( '#view-dialog' ).data('id',$(this).attr('id'))
.dialog( { title: 'View Details' } )
.dialog( 'open' ); }"
),
having given that code snippet.. in the controller action, I want to have the id ..is it $_GET['id'] ?, or $_POST['id'] ?..it doesn't matter for as long as I can get it so that I can use it to query in the model function
There are a few syntax errors in your code, but more importantly, you shouldn't wrap $data->id in any quotes.
'see' => array(
'label' => 'View',
'url' => 'Yii::app()->createUrl("mycontrollerName/view", array("id" => $data->id))',
'click' => "function( e ){
e.preventDefault();
$( '#view-dialog' ).data('id',$(this).attr('id'))
.dialog( { title: 'View Details' } )
.dialog( 'open' ); }",
),
So you are trying to pass the id value in the javascript code.
This is more of a jQuery issue rather than having much to do with Yii.
Run console.log($(this).attr('id')); you will probably see that you get an 'undefined' value. That is because the tag generated by Yii for the button does not contain an id parameter.
The easiest solution is to use jQuery to work with the url parameter.
e.g.
$( '#view-dialog' ).data('id',$(this).attr('href'))
if the entire URL is not needed, you could use a regex to parse only the numerical ID.
Alternatively you will have to pass the id in the buttons option parameter.
e.g.
'see' => array(
'label' => 'View',
'url' => 'Yii::app()->createUrl("mycontrollerName/view", array("id" => $data->id))',
'options' => array('id' => $data->id),
'click' => "function( e ){
...
However, please note that Yii will not render the value of $data->id in the 'option' parameter as this is not evaluated in CButtonColumn.
You will have to override Yii's CButtonColumn (see http://www.yiiframework.com/wiki/372/cbuttoncolumn-use-special-variable-data-for-the-id-in-the-options-of-a-button/)
Personally, if I were you, I'd implement some Javascript in some external code and have a regex to parse the id from the URL.

Filter empty values in DetailView

Is there an easy way to force DetailView in Yii2 to ignore these fields in its attributes list, that for particular model are empty?
Or the only way is to define every attribute on attributes list with own function and filter empty fields inside it (sound like a little bit of madness)?
Edit: I thought, that this is pretty self-explanatory, but it turned out, it isn't. So, basically, I want to force DetailView to ignore (not render) rows for these elements of attributes list, that have empty (null, empty string) values in corresponding model and thus would result in rendering empty table cell:
You can define template parameter of DetailView widget as a callback function with following signature function ($attribute, $index, $widget) and this callback will be called for each attribute, so you can define desired rendering for your rows:
DetailView::widget([
'model' => $model,
'template' => function($attribute, $index, $widget){
//your code for rendering here. e.g.
if($attribute['value'])
{
return "<tr><th>{$attribute['label']}</th><td>{$attribute['value']}</td></tr>";
}
},
//other parameters
]);
Would something like this work better? It preserves some of the niceties like: updated_at:datetime, which with one of the solutions above will just show the underlying value, not a converted value.
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
[
'attribute' => 'my_attribute',
'visible' => !empty($model->my_attribute)
],
]
]);

Creating Prestashop back-office module with settings page

I'm creating a back-office module for Prestashop and have figured out everything except the best way to display the admin page. Currently I'm using the renderView() method to display the content of view.tpl.
I would like to display a table with values and an option to add a new row. Should I just create it in the view.tpl or is there a better way? I've seen the renderForm() method but haven't figured out how it works yet.
The biggest question I have is, how do I submit content back to my controller into a specific method?
ModuleAdminController is meant for managing some kind of records, which are ObjectModels. Defauly page for this controller is a list, then you can edit each record individually or view it's full data (view).
If you want to have a settings page, the best way is to create a getContent() function for your module. Besides that HelperOptions is better than HelperForm for this module configuration page because it automatically laods values. Define the form in this function and above it add one if (Tools::isSubmit('submit'.$this->name)) - Submit button name, then save your values into configuration table. Configuration::set(...).
Of course it is possible to create some sort of settings page in AdminController, but its not meant for that. If you really want to: got to HookCore.php and find exec method. Then add error_log($hook_name) and you will all hooks that are executed when you open/save/close a page/form. Maybe you'll find your hook this way. Bettter way would be to inspect the parent class AdminControllerCore or even ControllerCore. They often have specific function ready to be overriden, where you should save your stuff. They are already a part of execution process, but empty.
Edit: You should take a look at other AdminController classes, they are wuite simple; You only need to define some properties in order for it to work:
public function __construct()
{
// Define associated model
$this->table = 'eqa_category';
$this->className = 'EQACategory';
// Add some record actions
$this->addRowAction('edit');
$this->addRowAction('delete');
// define list columns
$this->fields_list = array(
'id_eqa_category' => array(
'title' => $this->l('ID'),
'align' => 'center',
),
'title' => array(
'title' => $this->l('Title'),
),
);
// Define fields for edit form
$this->fields_form = array(
'input' => array(
array(
'name' => 'title',
'type' => 'text',
'label' => $this->l('Title'),
'desc' => $this->l('Category title.'),
'required' => true,
'lang' => true
),
'submit' => array(
'title' => $this->l('Save'),
)
);
// Call parent constructor
parent::__construct();
}
Other people like to move list and form definitions to actual functions which render them:
public function renderForm()
{
$this->fields_form = array(...);
return parent::renderForm();
}
You don't actually need to do anything else, the controller matches fields to your models, loads them, saves them etc.
Again, the best way to learn about these controller is to look at other AdminControllers.

I've to show menu bar with stats like count of messages and updates, also other counts like gifts and messages count

I want to show a menu bar with stats like count of messages and updates, also other counts like gifts, new friend request and messages count.
This menu will be displayed on the all the pages.
How can I write a single method to get all the stats and render partial into the layout and forget about it?
And in other action just concentrate on the main functionality of the page. Without bothering about the menu.
How can I achieve this in Yii?
You're probably looking for a widget. You could for example extend CMenu and do the queries in init() there:
<?php
Yii::import('zii.widgets.CMenu')
class MainMenu extends CMenu
{
public function init()
{
// Do some count queries here. This is just an example,
// your implementation will differ, of course:
$newMessages = Messages::model()->new()->count();
// Now add the menu items:
$this->items = array(
array(
'label' => "$newMessages New messages",
'url' => array('messages/list'),
),
// ...
);
parent::init();
}
}
You then can use this widget in your views/layouts/main.php:
<?php $this->widget('MainMenu'); ?>
You can use beforeAction to achieve this.
As the docs say "This method is invoked right before an action is to be executed (after all possible filters.) You may override this method to do last-minute preparation for the action."
Also you can define public variables in you main controller (Components/Controller.php) so every other controller has access to these. You can then use them in your layout using $this-variable...
Hope this helps :)
You need to create a class that extends CMenu in /protected/components/extendingclassname
<?php
Yii::import('zii.widgets.CMenu');
class Notifications extends CMenu
{
public function init()
{
//query
$requestor=Yii::app()->user->name;
$count = Requests::model()->count( 'requestor=:requestor', array('requestor' => $requestor));
// Now add the menu items:
$this->items = array(
array(
'label' => "$count New messages",
'url' => array('user/notifications'),
),
// ...
);
parent::init();
}
}
?>
Then include the following line within your /layouts.main.php.Hope this helps a beginner who is not sure where to use the class.That's something Michael Härtl forgot to mention.

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.