After enabling Ajax Validation:
'enableAjaxValidation'=>false,
Generally Yii validate after focus out. Is there any way that we can apply validation to an input field while pressing key or typing the text.
For now, you disabled ajax validation by this code. Change it to true to enable it.
To use other validation triggers, there's some properties in clientOptions, like:
validationDelay - integer, the number of milliseconds that an AJAX validation should be delayed after an input is changed
validateOnSubmit - boolean, whether to perform AJAX validation when the form is being submitted
validateOnChange - boolean, whether to trigger an AJAX validation each time when an input's value is changed
validateOnType - boolean, whether to trigger an AJAX validation each time when the user presses a key
validateOnType is what youre looking for, but remember to set proper validationDelay.
Sample:
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'user-form',
'enableAjaxValidation' => true,
'enableClientValidation' => true,
'clientOptions' => array(
'validateOnType' => true,
)
)); ?>
Related
What is the right way to have variable pagination in Yii2?
I mean by this, that I want the user to be able to give the number of items in a page while sending an API request.
I know about setting the pageSize in the dataProvider.
$dataProvider = new SqlDataProvider([
'sql' => 'SELECT * FROM user WHERE status=:status',
'params' => [':status' => 1],
'pagination' => [
'pageSize' => 20,
],
]);
But my question is about anything that is built in that allows the user to send the pageSize through the request? Is there anything built-in to perform this function?
Leave empty the pagination field in the dataProvider and just add the per-page GET parameter in your calls:
http://your_url/controlller/action?per-page=20
More info here.
I have a custom keyboard but to process the answer i need a force reply so i get the question back in the next message. I have done this:
var opts = {
reply_markup: JSON.stringify({
keyboard: [['OK','Cancel']],
one_time_keyboard: true,
resize_keyboard: true,
force_reply: true
})
};
The keyboard works but not the force_reply.
Force reply on its own works? Can i not use it in combination with a custom keyboard?
It may be late to help you, but here it goes.
Currently only one reply_markup field is allow and this field must contain only one of the following types: ReplyKeyboardMarkup or ReplyKeyboardHide or ForceReply (see docs)
In any case, you can use ReplyKeyboardMarkup that will pop up a custom keyboard in the user app directly and code your bot so it only accept one of the answer in your own custom keyboards.
Furthermore, if you really want to force that the user reply, you can keep sending the same ReplyKeyboardMarkup after each user's invalid answer.
You need to specify your markup like this :
$replyMarkup = array(
'force_reply' => true,
'selective' => true
);
If you need to have custom keyboard you can follow this :
$keyboradsValue = array(
array("button 1","button 2"),
array("button 3","button 4"),
);
$replyMarkup = array(
'keyboard' => $keyboradsValue,
'force_reply' => true,
'selective' => true
);
After that you need to encode your object using json_encode
$encodedMarkup = json_encode($replyMarkup, true);
Finally you just put above code at your query string at the rest of sendMessage.
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'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.
I have problems regarding with pagination and Ajax form.
Here is my code for Controller:
$dataProvider = new CActiveDataProvider('User', array(
'pagination'=>array(
'pageSize'=>10,
),
));
$this->render('users',array(
'dataProvider'=>$dataProvider,
));
For view -> users:
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_user',
);
For render _users:
echo CHtml::ajaxLink($text, $this->createUrl('admin/deleteuser',array('id'=>$data->iduser)), array('success'=>"js:function(html){ alert('remove') }"), array('confirm'=>_t('Are you sure you want to delete this user?'), 'class'=>'delete-icon','id'=>'x'.$viewid));
if i have 15 rows in a database it will only show 10 and will generate a pagination (ajaxUpdate = true) for next 5. The first 10 rows has no problem with the ajaxLink because the clientscript was generated but problem is the when I move to the next page, the ajaxLink is not working because its not generated by the pagination .
any idea? thanks
An alternate method, check this post in the yii forum. So your code will become like this:
echo CHtml::link($text,
$this->createUrl('admin/deleteuser',array('id'=>$data->iduser)),
array(// for htmlOptions
'onclick'=>' {'.CHtml::ajax( array(
'beforeSend'=>'js:function(){if(confirm("Are you sure you want to delete?"))return true;else return false;}',
'success'=>"js:function(html){ alert('removed'); }")).
'return false;}',// returning false prevents the default navigation to another url on a new page
'class'=>'delete-icon',
'id'=>'x'.$viewid)
);
Your confirm is moved to jquery's ajax function's beforeSend callback. If we return false from beforeSend, the ajax call doesn't occur.
Another suggestion, you should use post variables instead of get, and also if you can, move the ajax call to a function in the index view, and just include calls to the function from the all links' onclick event.
Hope this helps.
Not fully sure, but given past experiences I think the problem is in the listview widget itself.
If the owner of the widget is a Controller, it uses renderPartial to render the item view.
Renderpartial has, as you may or may not know, a "processOutput" parameter which needs to be set to TRUE for most of the AJAX magic (its FALSE by default).
So perhaps you can try to just derive a class of the listview and add a copy in there of "renderItems()". There you would have to change it so that it calls renderPartial with the correct parameters.
In the widget Clistview, I added afterAjaxUpdate
$jsfunction = <<< EOS
js:function(){
$('.delete-icon').live('click',function(){
if(confirm('Are you sure you want to delete?'))
{
deleteUrl = $(this).attr('data-href');
jQuery.ajax({'success':function(html){ },'url':deleteUrl,'cache':false});
return false;
}
else
return false;
});
}
EOS;
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'id'=>'subscriptionDiv',
'itemView'=>'_subscription',
'afterAjaxUpdate'=>$jsfunction,
'viewData'=>array('is_user'=>$is_user,'all'=>$all),
'htmlOptions'=>($dataProvider->getData()) ? array('class'=>'table') : array('class'=>'table center'),
)
);
and in the _user just added attribute data-href
<?php echo CHtml::ajaxLink($text, $this->createUrl('admin/deletesubscription',array('id'=>$data->idsubscription)),
array('success'=>"js:function(html){ $('#tr{$viewid}').remove(); }"),
array('confirm'=>_t('Are you sure you want to unsubscribe?'),
'class'=>'delete-icon',
'id'=>'x'.$viewid,
'data-href'=>$this->createUrl('admin/deletesubscription',array('id'=>$data->idsubscription))
)); ?>
try
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_user',
'enablePagination' => true,
);
if this doesn't solve, try including the total number of records in the data provider options as -
'itemCount' => .....,