Yii2 : Create custom menu - yii2

I had constructed a bootstrap menu and now I want to reproduce it with Yii2 Nav widget. So, here is the initial state:
<nav class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="true">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">BrandLogo</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" aria-expanded="true">
<ul class="nav navbar-nav">
<li>
simple menu
</li>
<li class="dropdown">
dropdown menu <b class="caret"></b>
<ul class="dropdown-menu">
<li>
Submenu#1
</li>
<li>
Submenu#2
</li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" action="/action_page.php">
<div class="form-group has-feedback search">
<input type="text" class="form-control" placeholder="Search" />
<i class="glyphicon glyphicon-search form-control-feedback"></i>
</div>
</form>
</div>
</div>
</nav>
And here is how it looks like:
Now I would like to do the same menu with Nav widget. Here is the code:
NavBar::begin([
'brandLabel' => 'BrandLogo',
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse',
],
]);
$menuItems = [
[
'label' => 'simple menu',
'url' => ['#1']
],
[
'label' => 'dropdown menu',
'url' => ['#4'],
'items' => [
[
'label' => 'Submenu#1',
'url' => ['#1'],
],
[
'label' => 'Submenu#2',
'url' => ['#2'],
],
]
],
[
'label' => '
<form class="navbar-form navbar-left" action="/action_page.php">
<div class="form-group has-feedback search">
<input type="text" class="form-control" placeholder="Search" />
<i class="glyphicon glyphicon-search form-control-feedback"></i>
</div>
</form>',
'encode' => false,
'url' => false,
],
];
if (count($menuItems)) {
echo Nav::widget([
'options' => ['class' => 'navbar-nav'],
'items' => $menuItems,
]);
}
NavBar::end();
The problem is that the results aren't equal. I found a few problems:
The widget generates dropdown link as <a class="dropdown-toggle" href="/main/#4" data-toggle="dropdown">dropdown menu <span class="caret"></span></a> How can I get rid of data-toggle="dropdown" and class="dropdown-toggle"?
The search form is wrapped into <a></a> tags. That is why the navbar is broken:
How can I get rid of the unnecessary tag?

That is because you are not following the actual HTML structure, and according to that you need to add the form after the ul not inside the li, but that form should be part of the NavBar and if you look into the defination
Any content enclosed between the \yii\bootstrap\begin() and
\yii\bootstrap\end() calls of NavBar is treated as the content of the
navbar. You may use widgets such as yii\bootstrap\Nav or
\yii\widgets\Menu to build up such content.
so just move your form outside the $items after you are calling the Nav::widget() and before you call the NavBar::end().
And you can use the linkOptions to customize or remove the class or any other attribute related to the link
<?php
NavBar::begin([
'brandLabel' => 'BrandLogo',
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse',
],
]);
$menuItems = [
[
'label' => 'simple menu',
'url' => ['#1']
],
[
'label' => 'dropdown menu',
'url' => ['#4'],
'linkOptions' => [
'class' => 'my-class',
'data' => [
'toggle' => ''
]
],
'items' => [
[
'label' => 'Submenu#1',
'url' => ['#1'],
],
[
'label' => 'Submenu#2',
'url' => ['#2'],
],
]
],
];
if( count($menuItems) ){
echo Nav::widget([
'options' => ['class' => 'navbar-nav'],
'items' => $menuItems,
]);
}
?>
<form class="navbar-form navbar-left" action="/action_page.php">
<div class="form-group has-feedback search">
<input type="text" class="form-control" placeholder="Search" />
<i class="glyphicon glyphicon-search form-control-feedback"></i>
</div>
</form>
<?php
NavBar::end();
EDIT
if you are looking to completly remove the class name dropdown-toggle then you might have to override the yii\bootstrap\Nav::renderItems() by extending the widget because it is added by default as the bootstrap class so you have to just copy the renderItems() to your extended class and comment out the line Html::addCssClass ( $linkOptions , [ 'widget' => 'dropdown-toggle' ] ); which adds the class there and then change the namespace where you are calling the Nav from yii\bootstrap\Nav::widget() to common\components\Nav::widget()
Add the following class in your common\components\ or if you plan to copy it somewhere else do update the namespace in the code
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace common\components;
use yii\bootstrap\Nav as BaseNav;
use yii\bootstrap\Html;
use yii\helpers\ArrayHelper;
use yii\base\InvalidConfigException;
class Nav extends BaseNav {
/**
* Renders a widget's item.
* #param string|array $item the item to render.
* #return string the rendering result.
* #throws InvalidConfigException
*/
public function renderItem($item) {
if( is_string($item) ){
return $item;
}
if( !isset($item['label']) ){
throw new InvalidConfigException("The 'label' option is required.");
}
$encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
$label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
$options = ArrayHelper::getValue($item, 'options', []);
$items = ArrayHelper::getValue($item, 'items');
$url = ArrayHelper::getValue($item, 'url', '#');
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
if( isset($item['active']) ){
$active = ArrayHelper::remove($item, 'active', false);
} else{
$active = $this->isItemActive($item);
}
if( empty($items) ){
$items = '';
} else{
$linkOptions['data-toggle'] = 'dropdown';
Html::addCssClass($options, ['widget' => 'dropdown']);
// Html::addCssClass ( $linkOptions , [ 'widget' => 'dropdown-toggle' ] );
if( $this->dropDownCaret !== '' ){
$label .= ' ' . $this->dropDownCaret;
}
if( is_array($items) ){
$items = $this->isChildActive($items, $active);
$items = $this->renderDropdown($items, $item);
}
}
if( $active ){
Html::addCssClass($options, 'active');
}
return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options);
}
}

Related

Yii2 Pjax delete action with modal

I'm trying to do a delete action with Pjax (without refreshing the page).
The register is deleted properly, page no reloads, BUT, if immediately I try to delete another record, don't load the modal.
So the delete button cannot call to modal for new delete.
I hope you can help me to resolve this. Thanks
Here is my code:
Step 1
file: index view
<?php Pjax::begin(['id' => 'pjax-container']); ?>
<?=
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
.....
'columns' => [
...others columns
[
'class' => 'yii\grid\ActionColumn',
'template' => '{view} {delete}',
'buttons' => [
'delete' => function ($url, $model, $key) {
return Html::a(
'<span class="material-icons">delete</span>',
'javascript:void(0)',
[
'data-ruta' => Url::toRoute(['delete', 'id' => $model->id]),
'id' => $model->id,
'class' => 'btn-eliminar-competencia option-danger',
'title' => __('GxP', 'commons.delete'),
'aria-label' => "Eliminar",
'data-pjax' => "0",
'data-method' => "post"
]
) . '</div>';
}
]
]
]
]);
?>
<?php Pjax::end(); ?>
Step 2
file index view
After clicking the delete button, go to open modal
<div class="modal bootstrap-dialog" role="dialog" aria-hidden="true" id="modal-eliminar-
competencia" aria-labelledby="w3_title" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title"><?= __('GxP', 'commons.delete') ?></h4>
</div>
<div class="modal-body text-center">
<div class="bootstrap-dialog-message"><?= __('GxP', 'dialogs.sure_delete_element') ?></div>
<div id="text-modal-competencia"></div>
</div>
<div class="modal-footer text-center">
<button class="btn btn-success" data-dismiss="modal">
<?= __('GxP', 'commons.cancel') ?>
</button>
<button class="btn btn-primary btn-modal-eliminar-competencia">
<?= __('GxP', 'commons.accept') ?>
</button>
</div>
</div>
</div>
</div>
Step 3
file: index.js
$(document).ready(function(){
var ruta
eliminar = 0
redirect = 0
modal = $('#modal-eliminar-competencia')
modal_competencia = $('#modal-competencia')
$('.div2').click(function(){
window.location = $('#tipos-competencias').attr('href')
})
$('.btn-eliminar-competencia').click(function(){
eliminar = $(this).attr('data-ruta')
$('#text-modal-competencia').html('')
id = $(this).attr('id')
$.ajax({
type:'post',
url:'/competences/competences-asociated',
data:{id:id},
dataType:'json'
})
.done(function(r){
console.log(r)
mensaje_text =
'<br>'+
'<p>'+__('commons.info')+':</p>'+
'<small>'+
r.positions+__('dialogs.associated_positions')+
'</small>'+
'<br>'+
'<small>'+
r.reagents+__('dialogs.associated_reagents')+
'</small>';
$('#text-modal-competencia').html(mensaje_text)
})
.fail(function(){
})
modal.modal({backdrop:'static',keyboard:true})
})
// here resolve the delete item and reload container with Pjax
$('.btn-modal-eliminar-competencia').click(function(){
$.ajax({
type:'post',
url:eliminar,
dataType:'json',
success:function(response){
if(response.code == 204){
redirect = response.redirect
$('.message-contenido .message-text').html(__('dialogs.success_delete'))
modal.modal('hide')
$('.capa').show()
$('.message-action').show()
ruta = false
$.pjax.reload({container:'#pjax-container'})
}
else{
modal_alert(__('dialogs.unespected_error'))
}
}
})
})
})

Yii2 Boostrap ActiveForm Horizontal Layout

Good afternoon,
I am new to programming and struggling to understand Yii2 layout with Bootstrap.
What I am after is really simple, so I thought, but I can't seem to get it to remotely work. I want to create a horizontal form with the labels in front of each input and be able to control to the width of each input.
In my current code, I have 2 simple fields, I want the first to span half of the form (col-md-6) and the second should span the totality of the form (col-md-12), but this just isn't working and I don't understand the why so I'm struggling to fix it.
Below is my view
<?php
use yii\helpers\Html;
use yii\helpers\ArrayHelper;;
use yii\bootstrap\ActiveForm; //used to enable bootstrap layout options
/* #var $this yii\web\View */
/* #var $model backend\models\Projects */
/* #var $form yii\widgets\ActiveForm */
?>
<div class="projects-form">
<?php
$form = ActiveForm::begin([
'id'=>$model->formName(),
'layout' => 'horizontal',
'class' => 'form-horizontal',
'fieldConfig' => [
'enableError' => true,
]
]);
?>
<h2>Project Information</h2>
<h3>General Information</h3>
<div class="form-group row">
<div class="col-md-6">
<?php
echo $form->field(
$model,
'ProjNo'
)->textInput(['maxlength' => true]);
?>
</div>
<div class="col-md-6">
</div>
</div>
<div class="form-group row">
<div class="col-md-12">
<?php
echo $form->field(
$model,
'ProjName'
)->textInput(['maxlength' => true]);
?>
</div>
</div>
<p></p>
<p></p>
<?php
ActiveForm::end();
?>
</div>
This is the _form view which is called within the create and update views.
What I don't quite get is why the label alignment isn't consistent because I specify a different width for the overall field and why even though I specified col-md-12, which should be full width from my understanding, it only seems to take about half of the available width.
Any help is greatly appreciated!
Thank you.
current example of what is generated
I just want the labels to line up and be able to have fields with different widths. In the above, when I change the class, the labels change alignment.
You can use the template option under the form's fieldConfig option like below to specify the order of the input, label, and error-block, and these settings would be applied throughout the form for all inputs, in below configurations I am placing the label after the input you can change that if you want.
$form = yii\bootstrap\ActiveForm::begin ( [ 'id' => $model->formName () ,
'layout' => 'horizontal' ,
'class' => 'form-horizontal' ,
'fieldConfig' => [
'enableError' => true ,
'template' => '{input}{error}{label}',
] ] );
you can wrap the {label} and {input} with div like
'template' => '<div class="col-sm-6">{input}{error}</div>
<div class="col-sm-3">{label}</div>',
and remove all the extra HTML from your view just wrap the $form->field() with row see below
$form = yii\bootstrap\ActiveForm::begin ( [ 'id' => $model->formName () ,
'layout' => 'horizontal' ,
'class' => 'form-horizontal' ,
'fieldConfig' => [
'enableError' => true ,
'template' => '<div class="col-sm-6">{input}{error}</div>{label}',
] ] );
?>
<h2>Project Information</h2>
<h3>General Information</h3>
<div class="row">
<?php
echo $form->field (
$model , 'ProjNo'
)->textInput ( [ 'maxlength' => true, ] );
?>
</div>
<div class="row">
<?php
echo $form->field (
$model , 'ProjName'
)->textInput ( [ 'maxlength' => true, ] );
?>
</div>
EDIT
as per discussion you do not want equally aligned labels and inputs but instead you want variable inputs and labels within each row and for doing so you need to configure the template part of the input fields separately and it can look like below if i understood correctly
you should configure your form options and field template options like below and remove the extra class applied on the label col-sm-3 by assigning it control-label class manually
$form = yii\bootstrap\ActiveForm::begin ( [ 'id' => $model->formName () ,
'layout' => 'horizontal' ,
'class' => 'form-horizontal' ,
'fieldConfig' => [
'enableError' => true ,
'options' => [
'class' => ''
]
] ] );
?>
<h2>Project Information</h2>
<h3>General Information</h3>
<div class="row">
<?php
echo $form->field (
$model , 'name' , [ 'template' => '<div class="col-sm-2">{label}</div><div class="col-sm-4">{input}{error}</div>' , ]
)->textInput ( [ 'maxlength' => true ] )->label ( null , [ 'class' => 'control-label' ] )
?>
<?php
echo $form->field (
$model , 'price' , [ 'template' => '<div class="col-sm-2">{label}</div><div class="col-sm-4">{input}{error}</div>' , ]
)->textInput ( [ 'maxlength' => true ] )->label ( null , [ 'class' => 'control-label' ] );
?>
</div>
<div class="row">
<?php
echo $form->field (
$model , 'product_subcategory' , [ 'template' => '<div class="col-sm-2">{label}</div><div class="col-sm-10">{input}{error}</div>' , ]
)->textInput ( [ 'maxlength' => true , ] )->label ( null , [ 'class' => 'control-label' ] );
?>
</div>
<?php
echo yii\bootstrap\Html::submitButton ( 'Submit' );
yii\bootstrap\ActiveForm::end ();
Hope this helps you out

Get data from textbox and pass to Controller in yii2

Itis the same question as Pass data from a form to a controller in yii2.
I want to get data from user in 3fields and pass it to a controller action.
I'm trying to do this by javascript but it seems that the javascript function is not being called.
Nothing happens when I click on the button. No error in the console as well.
I'm attaching the code of 3 fields,button and javascript below.
index2.php
<?php
use yii\helpers\Html;
//use yii\grid\GridView;
use kartik\grid\GridView;
use kartik\export\ExportMenu;
use frontend\modules\stock\models\Sellitem;
use dosamigos\datepicker\DatePicker;
use dosamigos\datepicker\DateRangePicker;
use kartik\form\ActiveForm;
/* #var $this yii\web\View */
/* #var $searchModel frontend\modules\stock\models\SellitemSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Stock';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="sellitem-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<div class="row">
<div class="form-group">
<div class="col-xs-4 col-sm-4 col-lg-4">
<label for="upc" class="control-label"><p class="text-info">Product Code <i class="icon-star"></i></p></label>
<input type="text" class="form-control" id="upc" class="span3">
</div>
<div class="col-xs-4 col-sm-4 col-lg-4">
<label for="upc" class="control-label"><p class="text-info">Start Date <i class="icon-star"></i></p></label>
<?= DatePicker::widget([
//'label' => 'Startdate',
'name' => 'startdate',
'id' => 'startdate',
//'value' => '02-16-2012',
'template' => '{addon}{input}',
'clientOptions' => [
'autoclose' => true,
'todayHighlight' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
</div>
<div class="col-xs-4 col-sm-4 col-lg-4">
<label for="upc" class="control-label"><p class="text-info">End Date <i class="icon-star"></i></p></label>
<?= DatePicker::widget([
//'label' => 'Startdate',
'name' => 'enddate',
'id' => 'enddate',
//'value' => '02-16-2012',
'template' => '{addon}{input}',
'clientOptions' => [
'autoclose' => true,
'todayHighlight' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
</div>
</div>
</div>
<p>
<div class="form-group pull-right">
<button class="btn btn-primary" onclick="getValue()">Seach</button>
</div>
</p>
</div>
<?php
/* start getting the itemid */
$this->registerJs('
function getValue()
{
var uPc = $(".upc").val();
var startDate = $(".startdate").val();
var endDate = $(".enddate").val();
alert(uPc);
}
');
/* end getting the itemid */
?>
The registerJs use some jQuery assigning so seems that the function getValue is not visible by the button call but you could use jQuery for assign the onclick and code.
Assuming your button has a id named yourButton you could do this way
<div class="form-group pull-right">
<button id="yourButton" class="btn btn-primary" >Seach</button>
</div>
$this->registerJs (
"$('#yourButton').on('click', function() {
var uPc = $('#upc').val();
var startDate = $('#startdate').val();
var endDate = $('#enddate').val();
alert(uPc);
});"
);
In your javascript code you have '.upc' '.startdate' '.enddate' this mean that you are looking for class upc, startdate endate ... but in your html there is not this class associated to the input field .. you have id then you should search in jQuery using #udc #startdate ... an so
you can do it using ajax by serializing your data and send it to controll action like
$('body').on('click','#btn_id',function(){
var data = $('form#id').serialize();
$.ajax({
'type' : 'get/post',
'dataType' : 'html/json',
'url' : 'controller/action',
'data' : {variable:data},
success : function(data){
console.log('Data Pass Successfully');
},
error : function(){
console.log('There is an Error....!!!');
}
});
});

Yii2 How to Use Html::tag or Html::beginTag

i want to echo like this
<li>
<img src="img/h4-slide.png" alt="Slide">
<div class="caption-group">
<h2 class="caption title">some_title
</h2>
<h4 class="caption subtitle">Dual SIM</h4>
<a class="caption button-radius" href="some_route"><span class="icon"></span>check</a>
</div>
</li>
here my code for render image carousel :
$slides = [];
foreach (Slide::find()->orderBy('sortOrder')->all() as $slide) {
/** #var $slide common\models\Slide */
$slides[] = [
'content' => Html::img(Yii::$app->urlManager->baseUrl . '/uploads/slide/' . $slide->id . '.jpg'),
'caption' => Html::tag('content-group', $slide->title)."<br>".$slide->body,
];
}
And my carousel :
<div class="slider-area">
<div class="block-slider block-slider4">
<?= Carousel::widget([
'id' => 'bxlider-home',
'items' => $slides,
'options' => [
'class' => 'slide',
'data-interval' => 3000,
],
'controls' => [
'<span class="bx-next fa fa-angle-left"></span>',
'<span class="bx-prev fa fa-angle-right"></span>',
],
]) ?>
</div>
</div>
how to Slide->title, slide->body, and some links can be in class caption-group ?
I think it would be better to create new partial file.
Create a new file called _slider.php
Call $this->render('_slider') inside configuration of the slider. Please check below code.
$slides = [];
foreach (Slide::find()->orderBy('sortOrder')->all() as $slide) {
/** #var $slide common\models\Slide */
$slides[] = [
'content' => $this->render("_slider"),
'caption' => Html::tag('content-group', $slide->title)."<br>".$slide->body,
];
}
You can write html inside _slider.php easily now. Don't need to use Html::beginTag() etc.
Generating Tags
The code generating a tag looks like the following:
<?= Html::tag('p', Html::encode($user->name), ['class' => 'username']) ?>
<p class="username">samdark</p>
$options = ['class' => ['btn', 'btn-default']];
echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'
Hyperlinks:
<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
Images:
<?= Html::img('#web/images/logo.png', ['alt' => 'My logo']) ?>
generates
<img src="http://example.com/images/logo.png" alt="My logo" />
Lists:
<?= Html::ul($posts, ['item' => function($item, $index) {
return Html::tag(
'li',
$this->render('post', ['item' => $item]),
['class' => 'post']
);
}]) ?>
Even more?
visit

How to remove 'label' decorator from Zend 2 form

I have the simple Radio element:
$form->add([
'name' => 'account_type',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'label' => 'Account type',
'value_options' => [
1 => 'Employer',
2 => 'Performer'
]
]
]
);
But in my view I get this html:
<div class="zf-form-el-account_type">
<label for="account_type">Account type</label>
<div class="zf-radio">
<label>
<input type="radio" name="account_type" class="account_type" value="1">Employer
</label>
</div>
<div class="zf-radio">
<label>
<input type="radio" name="account_type" class="account_type" value="2">Performer
</label>
</div>
</div>
How I can to remove this empty label wrapper around an radio element? Or how I can to insert some tag after radio element? Thanks.
I extended standard view helper:
<?php
namespace Application\Form\View\Helper;
use Zend\Form\View\Helper\FormRadio;
use Zend\Form\Element\Radio as RadioEl;
class FormRadioElement extends FormRadio
{
protected function renderOptions(RadioEl $element, array $options, array $selectedOptions, array $attributes)
{ ...
... and set template in helper like:
$template = '%s%s';
Then I declared it in my bootstrap:
public function getViewHelperConfig() {
return [
'invokables' => [
'formRadioHelper' => 'Application\Form\View\Helper\FormRadioElement',
]
];
}
... and called in my view like:
<?php echo $this->formRadioHelper($form->get('account_type'))?>