Yii CGridView Not Updating With JS Call - php

What I'm trying to accomplish with the following code is when the 'roleSelector' dropdown is changed, it fires a ajax request to the 'admin/permissions/assign' url which in turn, sets a state for the role selected. I need it as a state so I can use it in the CLinkColumn column within the CGridView. However, when the success javascript fires and the grid view reloads the content of the cgridview does not update, while the summary does (it shows the number of results that should be in the grid view).
I'm not sure why either but this seems to be the only CGridView that I've had to use the 'ajaxUrl' property in order for the $.fn.yiiGridView.update() call to work. If I omit the url property it returns an error stating it could not find the url which I don't recall having to set in the past.
The Action:
class AssignAction extends CAction {
// Used in the url to determine if we are assigning or revoking permissions
const FLAG_APPLY = 'apply';
const FLAG_REVOKE = 'revoke';
// Identifier to the user saved state of the role selected
const STATE_ROLE = 'roleSelected';
public function run($name='', $action='') {
// Get the role the user selected
if (isset($_POST['roleSelector'])) {
$roleSelected = $_POST['roleSelector'];
Yii::app()->user->setState(self::STATE_ROLE, $roleSelected);
Yii::app()->end();
}
// Get all of the roles from the system
$roleSelected = Yii::app()->user->getState(self::STATE_ROLE);
$roles = AuthItem::model()->byTypes(array(CAuthItem::TYPE_ROLE))->findAll();
$authItemProvider = new CActiveDataProvider('AuthItem', array(
'criteria' => array(
'condition' => (!$roleSelected) ? '1=0' : '',
),
'pagination' => array(
'pageSize' => 30,
)
));
$this->getController()->render('assign', array(
'roles' => $roles,
'roleSelected' => $roleSelected,
'authItemProvider' => $authItemProvider,
));
}
}
The View:
<div id="content-header">
<h1 class="p-mt10">Assign Permissions</h1>
<div class="p-fr p-pb10">
<?php
$roleList = CHtml::listData($roles, 'name', 'label');
echo CHtml::dropDownList('roleSelector', $roleSelected, $roleList, $htmlOptions=array(
'empty' => 'Select a Role',
'ajax' => array(
'type' => 'POST',
'url' => $this->createUrl('/admin/permissions/assign'),
'data' => array('roleSelector' => 'js: $(this).val()'),
'success' => 'js: function() { $.fn.yiiGridView.update("GridView-AuthItem") }',
),
));
?>
</div>
</div>
<div id="content-body">
<table>
<?php
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'GridView-AuthItem',
'dataProvider' => $authItemProvider,
'columns' => array(
'label:properCase',
'typeName:properCase',
'description',
'bizrule',
array(
'class' => 'CLinkColumn',
'label' => 'Assign',
'urlExpression' => 'array("/admin/permissions/assign",
"name" => $data->name,
"action" => (AuthItemChild::model()->byParentAndChild(Yii::app()->user->getState(AssignAction::STATE_ROLE), $data->name)->find()
? AssignAction::FLAG_REVOKE : AssignAction::FLAG_APPLY),
)',
'htmlOptions' => array(
'style' => 'text-align: center',
),
'linkHtmlOptions' => array(
'class' => 'button gray icon i_stm_edit',
),
),
),
));
?>
</table>
</div>

I forgot I left the table tags in there since it originally was a CListView. Removing those tags seems to have fixed my problem.

Related

Yii menu linkOptions not working with ajax

I am trying to display a CGridView in a CJuiDialog but facing some problems.
In my view, I create a menu item as follow :
$this->menu = array(
array('label' => Yii::t('app', 'Afficher les participants ayant fourni cette information'),
'url' => array('Participant/ShowParticipantInfo', 'id' => $model->id_info),
'linkOptions' => array(
//'onclick' => "{viewP(); $('#dialogViewP').dialog('open'); return false}",
'ajax' => array(
'type' => 'POST',
'url' =>"js:$(this).attr('href')", //array('Participant/ShowParticipantInfo', 'id' => $model->id_info),
'update' => '#divForForm2',
),
),
);
Then I've created the dialog :
<?php $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
'id' => 'dialogViewP',
'options' => array(
'title' => 'Liste des participants ayant fourni cette information',
'autoOpen' => false,
'modal' => true,
'width' => 500,
'height' => 300,
),
));
?>
<div id="divForForm2"></div>
<?php $this->endWidget('dialogViewP'); ?>
And my controller looks like this one :
public function actionShowParticipantInfo($id){
$rows = Participant::findParticipantInfo($id);
$result = array();
foreach ($rows AS $key => $val){
$result[] = array('id' => $key +1, 'value' => $val['NomComplet']);
}
$arrayDataProvider = new CArrayDataProvider($result, array(
'id' => 'id',
'pagination' => array(
'pageSize' => 10,
),
));
if(Yii::app()->request->isAjaxRequest){
$this->renderPartial('_showparticipant', array(
'arrayDataProvider' => $arrayDataProvider,
), false, true);
echo CHtml::script('$("#dialogViewP").dialog("open")');
Yii::app()->end();
}
}
But but clicking on the menu item, there is any dialog diplayed. I cannot know why. Can somebody help me ?
I think there should not be both 'url' and 'linkOption' attributes in an menu item. Either one.
Thru web dev tools you need to check if you have ajax XHR upon menu item click.
I'd recommend you this extention if you want to realize an ajax manu.
Even if you initiate ajax request the response cannot activate hidden dialog because on success you ONLY update certain div #divForForm2 but the dialog window is still closed: 'autoOpen' => false. I'd recommend incorporate opening dialog upon ajax success.
'ajax' => array(
'type' => 'POST',
'url' => array('Participant/ShowParticipantInfo', 'id' => $model->id_info),
'success' =>'js:{function(data){$("#divForForm2").html(data); $("#dialogViewP").dialog("open");}'
),

Add a dynamic grid as input in custom extension Admin HTML from phtml file.

I've got this problem that I can't solve. Partly because I can't explain it with the right terms. I'm new to this so sorry for this clumsy question.
Below you can see an overview of my goal.
I'm using Magento CE1.7.0.2
you can see here i want to get like this in my custom module
Here is my Form.php
<?php
class Company_Web_Block_Adminhtml_Web_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset('web_form', array('legend'=>Mage::helper('web')->__('Item information')));
$fieldset->addField('title', 'text', array(
'label' => Mage::helper('web')->__('Title'),
'class' => 'required-entry',
'required' => true,
'name' => 'title',
));
$fieldset->addField('filename', 'file', array(
'label' => Mage::helper('web')->__('File'),
'required' => false,
'name' => 'filename',
));
$fieldset->addField('status', 'select', array(
'label' => Mage::helper('web')->__('Status'),
'name' => 'status',
'values' => array(
array(
'value' => 1,
'label' => Mage::helper('web')->__('Enabled'),
),
array(
'value' => 2,
'label' => Mage::helper('web')->__('Disabled'),
),
),
));
$fieldset->addField('content', 'editor', array(
'name' => 'content',
'label' => Mage::helper('web')->__('Content'),
'title' => Mage::helper('web')->__('Content'),
'style' => 'width:700px; height:500px;',
'wysiwyg' => false,
'required' => true,
));
if ( Mage::getSingleton('adminhtml/session')->getWebData() )
{
$form->setValues(Mage::getSingleton('adminhtml/session')->getWebData());
Mage::getSingleton('adminhtml/session')->setWebData(null);
} elseif ( Mage::registry('web_data') ) {
$form->setValues(Mage::registry('web_data')->getData());
}
return parent::_prepareForm();
}
}
How do i get this ?
Any ideas ?
Create a Renderer file like below
NameSpace\ModuleName\Block\Adminhtml\ModuleName\Edit\Renderer\Display.php
The file relates to below code adminhtml_modulename_edit_renderer_display
Try adding below fieldset in your Form.php
<?php
// This code is being used to sort the renderer display in form using element of your own
$fieldset->addType('modulename', Mage::getConfig()->getBlockClassName('modulename/adminhtml_modulename_edit_renderer_display'));
$fieldset->addField('yourdbfield_name', 'modulename', array(
'name' => 'yourdbfield_name',
'label' => Mage::helper('modulename')->__('Title you want to show'),
'required' => true,
));
// This code is being used to sort the renderer display in form using element of your own
?>
You can also add renderer like this
'renderer' => 'modulename/adminhtml_modulename_edit_renderer_display',
Now in your display.php add below HTML code along with the JS code.
<table id="modulename_tbl_data" cellspacing="0">
<button id="add_your_component" class="add" type="button" title="Add"><span><span><span>Add</span></span></span></button>
</table>
jQuery Code
jQee('#add_your_component').click(function() {
var jQee = jQuery.noConflict();
jQee(document).ready(function(){
var i = jQee('input').size() + 1;
jQee('#add').click(function() {
var one = '<input id="yourID" name="yourName[]" value="" class="required-entry validate-number input-text required-entry"/>';
var remove = '<button onclick="javascript:jQuery(this).parent().parent().remove();" class="delete" type="button" title="Remove"><span><span><span>Remove</span></span></span></button>';
var tr = '<tr class="div_class"><td style="padding:0px 10px;">'+one+'</td><td style="padding:0px 10px;">'+remove+'</td></tr>';
jQuery('#modulename_tbl_data').append(tr);
i++;
});
});
This will allow you add options and remove them just like Magento.
Note: This is a just a demo and not complete code. You can alter it according to your needs.

Yii passing data back into a model

I have been working with Yii for the past few months, but I hit a bit of a block:
In my base controller I have a property public $currentUserOrganisations = NULL; which on load populates it with all the logged in users organizations.
Now I have a page where I get all of the organizations and the user can connect to them, but the ones I already have must say "Connected" rather then have the ability to add. I am using the bootstrap TbGridView widget and in my Organisation model created a function getConnectionAction which either returns the anchor OR a label depending if the organization is already connected to the user.
Here is my problem: I can't find a way to access the already loaded user organizations in the Organisation model, because it is a property on my model class.
See below for code:
Action in controller
public function actionNew()
{
$connectionModel = Connection::model();
$organizationModel = Organisation::model();
$this->selectedSubnav = "Add";
$this->render('new', array("connectionModel" => $connectionModel, "organizationModel" => $organizationModel));
}
Here is the TbGridView in the view:
<?php
$this->widget(
'bootstrap.widgets.TbGridView',
array(
'type'=>'striped',
'enableSorting'=>true,
'id' => 'connection-rest-data',
'dataProvider' => $organizationModel->getConnectionsByOrganization($this->currentOrganisation->id),
'ajaxUpdate' => true,
'template'=>"{pager}<br>\n{items}\n{pager}",
'rowHtmlOptionsExpression' => '',
'emptyText' => Yii::t("site", "no_restults_found") . '.',
"itemsCssClass" => "table table-first-column-number data-table display full dataTable transaction_tbl",
'columns' => array(
array(
'header' => Yii::t("site", "id"),
'value' => '$data->id',
'type' => 'raw',
'name' => 'id'
),
array(
'header' => Yii::t("site", "from_unit"),
'type' => 'raw',
'value' => '$data->fromUnit["name"]',
'name' => 'fromUnit'
),
array(
'header' => Yii::t("site", "to_unit"),
'type' => 'raw',
'value' => '$data->toUnit["name"]',
'name' => 'type'
),
array(
'header' => Yii::t("site", "connection_type"),
'type' => 'raw',
'value' => '$data->type["name"]',
'name' => 'type'
),
array(
'header' => Yii::t("site", "ended"),
'type' => 'raw',
'value' => '$data->ended',
'name' => 'ended'
),
array(
'header' => Yii::t("site", "fees"),
'type' => 'raw',
'value' => 'empty($data->fees) ? "none" : $data->fees["fee"]',
'name' => 'fees'
),
array(
'header' => Yii::t("site", "actions"),
'type' => 'raw',
'value' => 'Organisation::model()->getConnectionAction($data->id, \'' . serialize($this->currentUserOrganisations) . '\'")',
'name' => 'fees'
)
),
)
);
?>
And here is the function in the Organisations Model:
public function getConnectionAction ($connectionId)
{
$currentOrganizations = null; //This I need to get the public $currentUserOrganisations = NULL; value
foreach ($currentOrganizations as $org)
{
if($org->id == $connectionId)
{
return CHtml::label(Yii::t("site", "connected"), "", array("style" => "color:green;"));
}
}
return CHtml::link("Add", "/connection/manage/addConnection?id=$connectionId");
}
Much appreciated guys and give me a shout if anything is unclear!
Ok so I managed a work around which is very close to what Martin said.
In the view for the specific field I do:
'value' => 'Organisation::model()->getConnectionAction($data->id, ' . $this->currentOrganisation->id . ')',
The id is the id of the listed organization and the currentOrganization->id is the id of the users current organization.
Then in my model I get all the organizations for the user:
$currentOrganizations = $this->findAllForUserByOrganizationId($currentOrgId);
Foreach through them and check if they match, full function below.
public function getConnectionAction ($organizationId, $currentOrgId)
{
$currentOrganizations = $this->findAllForUserByOrganizationId($currentOrgId);
foreach ($currentOrganizations as $org)
{
if(in_array($organizationId, array($org->fromUnit['id'], $org->toUnit['id'])))
{
return CHtml::label(Yii::t("site", "connected"), "", array("style" => "color:green;"));
}
}
return CHtml::link(Yii::t("site", "add_connection"), "/connection/manage/addConnection?id=$connectionId", array("class" => "createConnection"));
}
I think you are going to want to avoid Active Record for this one. You can use a CSqlDataProvider to load your TbGridView. Use SQL that looks something like this
select
org.organization_name,
user.name
from organization org
left outer join connection x on org.id = x.organization_id
join user on user.id = x.user_id
where user.id = ? or user.id is null
That ? is a parameter marker to allow you to pass in a user_id in a parameter array rather than just concatenating it. Concatenation provides an opening for SQL injection.
Then in your column list for the gid view test the user.name for null and if null display the add button. If not null, display connected.

Associating an item to multiple other items (of a different class) using Prestashop's backoffice

Having just arrived at Prestashop 1.5, I am making a very simple module: a video of the week, associated with multiple products that need to appear right next to it.
I decided to start from the Backoffice. Right now, I can view, add, edit and remove all the Video entries but I'm a bit lost on how to map the N-N association between a video and its related products... The lack of documentation isn't helping either.
Any ideas how to pull this off?
Here's a bit of my code, the Video class is defined by:
class Video extends ObjectModel {
public $id_video;
public $title;
public $url;
public $active;
public static $definition = array(
'table' => 'video',
'primary' => 'id_video',
'multilang' => false,
'fields' => array(
'id_video' => array(
'type' => ObjectModel :: TYPE_INT
),
'title' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'url' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'active' => array(
'type' => ObjectModel :: TYPE_BOOL,
'required' => true
)
),
);
(...)
and the AdminVideo class is here:
class AdminVideoController extends ModuleAdminController {
public function __construct()
{
$this->table = 'video';
$this->className = 'Video';
$this->lang = false;
$this->fields_list['id_video'] = array(
'title' => $this->l('ID'),
'align' => 'center',
);
$this->fields_list['title'] = array(
'title' => $this->l('Title'),
'width' => 'auto'
);
$this->fields_list['url'] = array(
'title' => $this->l('URL'),
'width' => 'auto'
);
$this->fields_list['active'] = array(
'title' => $this->l('Active'),
'width' => '70',
'align' => 'center',
'active' => 'status',
'type' => 'bool',
'orderby' => false
);
parent::__construct();
}
public function postProcess()
{
parent::postProcess();
}
public function renderList()
{
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowAction('details');
return parent::renderList();
}
public function renderForm()
{
if (!($obj = $this->loadObject(true)))
return;
$this->fields_form = array(
'legend' => array(
'title' => $this->l('This weeks video'),
'image' => '../img/admin/world.gif'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Nome'),
'name' => 'title',
'size' => 33,
'required' => true,
'desc' => $this->l('Title')
),
array(
'type' => 'text',
'label' => $this->l('URL'),
'name' => 'url',
'size' => 33,
'required' => true,
'desc' => $this->l('Video URL')
),
array(
'type' => 'radio',
'label' => $this->l('Active:'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
'desc' => $this->l('Only one video can be active at any given time')
),
)
);
if (Shop::isFeatureActive())
{
$this->fields_form['input'][] = array(
'type' => 'shop',
'label' => $this->l('Shop association:'),
'name' => 'checkBoxShopAsso',
);
}
$this->fields_form['submit'] = array(
'title' => $this->l(' Save '),
'class' => 'button'
);
if (!($obj = $this->loadObject(true)))
return;
return parent::renderForm();
}
}
One other thing: would it be possible to add a preview of the video inside the backoffice? I tried to echo YouTube's embed code, but it gets inserted even before the header. Is there a clean way of doing this or do I have to use some jQuery trickery? I was basically doing an echo of YT's embed code just before the end of postProcess().
Thanks in advance!
The simplest way to associate the videos to the products is by adding a "products" text field in your "video" table to store a comma separated list of the ids of the associated products (eg.: 1,10,27). Even if it's a bit rudimentary, it should work.
Alternatively, you could use a table like this:
create table video_product (
id_association int not null auto_increment,
id_video int,
id_product int,
primary key (id_association)
);
The problem with this solution is that the PrestaShop ObjectModel core does not provide any method to automatically update or delete the related tables (at least as far as I know), so you have to insert the code to manage the "video_product" table in your "Video" class.
If you want an example of how to do this, you should look at the classes/Product.php script, which manages the product table and all its related tables (categories, tags, features, attachments, etc.).
To have an idea of how the Prestashop database is structured, have a look at the docs/dbmodel.mwb file, which contains the schema of the database; this file can be viewed by using the MySQL Workbench application.

Access to the $data variable from buttons in cgridview

Is the any way, to access model located in $data variable from CButtonColumn?
Below code is not working.
array(
'class' => 'CButtonColumn',
'template' => '{test}',
'buttons' => array(
'test' => array(
'label' => 'Select',
'click' => 'js:function() { <b>alert($data->_id);</b> return false;}',
),
),
),
It is possible to access visible attributes from jquery:
'click'=>'js:function(){alert("first element in cgridview is"+$(this).parent().parent().children(":nth-child(1)").text());}'
The only field where $data is allowed in CButtonColumn class is url, imageUrl and visible. To pass id to the javascript click event you may place such id in the url and grab it from the DOM. This is very rude hack but easy implementation.
array(
'class' => 'CButtonColumn',
'template' => '{test}',
'buttons' => array(
'test' => array(
'label' => 'Select',
/* set id */
'url' => $data->id,
/* retrieve id from this DOM element (jQuery) */
'click' => 'function() { alert( $(this).attr("href"); return false;}',
),
),
),
If you are looking for a more clear coding you could work in CDataColumn class
It looks like _id is a private variable (according to Yii's coding "standards"). You can not access private variables (and methods) outside of an object. Create a getter-method like this in your model:
public function getId() {
return $this->_id;
}
and then change your code to:
array(
'class' => 'CButtonColumn',
'template' => '{test}',
'buttons' => array(
'test' => array(
'label' => 'Select',
'click' => 'js:function() { alert($data->id); return false;}',
),
),
),
You need to customize the CButtonColumn class. Have a look this post:
http://www.yiiframework.com/wiki/714/yii-1-1-cgridview-use-special-variable-data-in-the-options-of-a-button-i-e-evaluate-options-attribute/
You can do that by custom function, as we can derived a $data variable inside it so that we can utilize better php as well as yii itself.
Try like this :
'test' => array(
'label' => 'Select',
'click' => function($data) {
$id = $data->id;
return "js:function() { alert($id); return false;}";
},
),

Categories