Yii2 attributeLabels - wrap part of the label in a tag - yii

Inside User model, I am using attributeLabels method to create text for the field:
public function attributeLabels()
{
return [
'terms' => 'I accept the Terms and Coditions'
];
}
And in the view I am using standard $form->field method to show the input field:
<?php $form->field($model, 'terms')->checkbox() ?>
I need to wrap Terms and Coditions inside a tag with a link. How can I do this?

The checkbox() method takes an options array where you can override the default label:
$form->field($model, 'terms')->checkbox([
'label' => 'I accept the Terms and Conditions'
]);
Detailed Checkbox Options are in the API Documentation at http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#checkbox()-detail

Related

Laravel6 multi dimensional array validation

I am creating a recipe posting application with Laravel6.
I have implemented a mechanism to dynamically add an image submission form in JavaScript.
I set the validation in FormRequest, but the mandatory input validation for dynamically added form fields does not work.
blade
<input type="file" name="upload_image[cooking_image][]" class="howto-image" style="display:none" accept="image/*">
FormRequest
public function rules(Request $request)
{
return [
'upload_image.cooking_image.*' => 'required|image|mimes:jpeg,png,jpg',
];
}
But the following works.
FormRequest
public function rules(Request $request)
{
return [
'upload_image.cooking_image.0' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.1' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.2' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.3' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.4' => 'required|image|mimes:jpeg,png,jpg',
];
}
I want to make mandatory input validation work for all dynamically added form input fields.
I think it sometimes not really possible to make it easily dynamic. Personally, in those case, I update my rules array on the fly.
I think this should help you : How to use required_if on file array fields with an array for first argument?
Good luck!

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)
],
]
]);

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.

Always show Pager on CGridView?

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).