I'm trying to create an 'auto-placeholder' element using Yii2 and since I couldn't find an actual answer to my question, I thought I'd try it here.
For example, I have this field:
<?= $form->field($model, 'username',
[
'template'=>'{input}{label}{error}'
])
->textInput(['placeHolder'=>'{name}')
->label(false);
?>
However this case would obviously render "name" in the placeholder attribute.
But I would like to generate the placeholder attribute automatically depending on the model's variable I'm using, causing it to render the following:
<input type="text" id="loginform-username" class="form-control" name="LoginForm[username]" placeholder="Username">
Is there a known way of accessing and inserting the form->field's attribute and displaying it inside its own element?
Yes we can do by defining the attributes labels in model file like below.
public function attributeLabels() {
return [
'username' => 'Username',
];
}
then you can fetch the label automatically based on fields like following.
<?= $form->field($model, 'username',
[
'template'=>'{input}{label}{error}'
])
->textInput(['placeholder' => $model->getAttributeLabel('username'))
->label(false);
?>
I hope this will sort it out your problem.
If you are in for some extra hassle you can extend ActiveField class for that.
class MyActiveField extends \yii\widgets\ActiveField
{
public function textInput($options = [])
{
if (empty($options['placeholder'])) {
$options['placeholder'] = $this->model->getAttributeLabel($this->attribute);
}
return parent::textInput($options);
}
}
Now just need to use your class instead of default one.
You can do every time in view:
<?php $form = ActiveForm::begin([
'fieldClass' => 'fully\qualified\name\of\MyActiveField'
]); ?>
Or extend ActiveForm:
class MyActiveForm extends \yii\widgets\ActiveForm
{
$fieldClass = 'fully\qualified\name\of\MyActiveField';
}
and use it instead of default ActiveForm widget:
<?php $form = MyActiveForm::begin(); ?>
Now you can use <?= $form->field($model, 'attribute')->textInput() ?> (or just <?= $form->field($model, 'attribute') ?> since textInput is default) and placeholder should be there.
Related
I have a code in my indext.ctp:
<?php echo $this->Form->input('full_name'); ?>
It gives me
Label is named Full Name my target is Full name
I know i can use:
<?php echo $this->Form->input('full_name', ['label'=>'Full name']); ?>
My question is: Can i do it globaly? Somehow override ucwords(); using in auto generating labels to ucfirst(); ?
Cakephp generate the label text (when not provided) here
It uses Inflector::Humanize() (see the manual)
I guess you can override the default helper (remember that input() is deprecated and you should use control() instead)
class MyFormHelper extends FormHelper
{
public function control($fieldName, array $options = [])
{
if(!isset($options['label']))
$options['label'] = // you own code here;
return parent::control($fieldName, $options);
}
}
then in your AppView.php initialize() you load your helper
$this->loadHelper('Form', [
'className' => 'MyForm',
]);
So when you want to define a custom label you use the 'label' option
<?php echo $this->Form->input('full_name', ['label'=>'Insert the full name here']); ?>
Instead if you don't set the 'label' option
<?php echo $this->Form->input('full_name'); ?>
the helper will use your logic
I tested the behavior and it works in my forms
I want to disable all the label of activeform fields but my code is not working
<?php $form = ActiveForm::begin(['enableLabel'=>false]); ?>
<?= $form->field($model, 'modeid')->textInput() ?>
<?= $form->field($model, 'projectid')->textInput() ?>
<?= $form->field($model, 'projecttype')->textInput() ?>
<?php ActiveForm::end(); ?>
There is no property enableLabel in ActiveForm.
If you want to remove labels from the field widgets add
->label(false)
after ->textInput().
You should use fieldConfig from ActiveForm to do this:
use yii\bootstrap\ActiveForm;
<?php $form = ActiveForm::begin(['fieldConfig' => ['enableLabel'=>false]]); ?>
I found another option.
In your model class. public function attributeLabels().
Set your properties labels to empty strings.
public function attributeLabels()
{
return [
'modeid' => '',
'projectid' => '',
'projecttype' => '',
];
}
I am newbie to yii2. I am trying to create my simple form in yii2 to retrieve password. Here is class code:
<?php
namespace app\models;
use yii\base\Model;
class RetrievePasswordForm extends Model
{
public $email;
public function rules()
{
return [
['email', 'required'],
['email', 'email'],
];
}
}
Here is action code:
$model = new RetrievePasswordForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()){
return $this->render('retrievepassword-confirm', ['model' => $model]);
} else {
return $this->render('retrievepassword', ['model' => $model]);
}
My form looks like this:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$this->title = 'Retrieve password';
$this->params['breadcrumbs'][] = $this->title;
?>
<h1><?= Html::encode($this->title) ?></h1>
<p>We will send link to retrieve your password to the following email:</p>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'email')->textInput(['style'=>'width:200px'])?>
<div class="form-group">
<?= Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
The problem is that $model->load(Yii::$app->request->post()) always returns false, so when I am clicking "submit" button, page just reloads.
I am currently working without database. I am just creating form and trying to go to another form, when valid data received in model. Thanks for help.
Try explicitally assign the method and the action to the active Form
Then Assuming that your target action is named actionRetrivePassword
<?php $form = ActiveForm::begin([
'method' => 'post',
'action' => Url::to(['/site/retrivepassword']
); ?>
I'll go with I feel it's wrong, if this doesn't help, please give more information.
It's a registration form, so I assume you need email and password for that (since you have those columns in database). But you also declared public member $email in your model. This removes any value associated to $email from database. Therefore, remove this line:
public $email;
For example we have this ActiveForm implementation in a sample view:
<?php $form = ActiveForm::begin(); ?>
<?=$form->field($model, 'first_name')->textInput(['maxlength' => true]); ?>
<?=$form->field($model, 'last_name')->textInput(['maxlength' => true]); ?>
<div id="additional-form-fields"></div>
<a href="#" id="load-additional-form-fields">
Load more fields
</a>
<?php ActiveForm::end(); ?>
Now, I want to add more ActiveField / ActiveForm fields inside this form and place them in the #additional-form-fields element with Ajax, I'd do a simple jQuery callback:
$('#load-additional-form-fields').click(function() {
$.get('/site/additional-fields', {}, function(data) {
$('#additional-form-fields').html( data );
});
});
And the action additional-fields inside SiteController would be something as:
public function actionAdditionalFields() {
$model = new User;
return $this->renderAjax('additional-fields', [
'model' => $model,
// I could pass a 'form' => new ActiveForm, here, but it's a big NO-NO!
]);
}
And this works perfectly, only if I don't use any other ActiveField fields inside this action's view:
<?=$form->field($model, 'biography')->textInput(['maxlength' => true]); ?>
<?=$form->field($model, 'country')->textInput(['maxlength' => true]); ?>
<?=$form->field($model, 'occupation')->textInput(['maxlength' => true]); ?>
Of course, I have to pass or instatiate $form somehow in this view, but it's NOT an option to use another ActiveForm::begin() / ActiveForm::end() anywhere inside this view since it will create another <form> tag and thus when I inject the Ajax response, I'll end up with with a <form> inside a <form> ...
Now, my question is as follows: Since I want to use ActiveForm, how can I share an instance of the ActiveForm through out multiple requests?
Is it doable / possible, if so, please help me realize how?
So far I have tried to put $form inside a session, but that's definitelly not working and not an option. Different than that, I've tried when passing parameters to renderAjax:
[
'model' => $model,
'form' => new ActiveForm,
]
In this case I get the following:
Form fields are created as they should with appopriate names and id's.
jQuery is loaded again (at the bottom of the response: <script src="..."> ... you get the idea)
I don't get the generated JavaScript for validation.
Is there anyway to share an instance of $form?
Okay, I have manage to do this, so I'll post the solution here and I'll open an issue on Github - might be useful in future versions.
1. Updates in yii2\widgets\ActiveForm.php
I've added a following property to the ActiveForm class:
/**
* #var boolean whether to echo the form tag or not
*/
public $withFormTag = true;
And I've changed run() method into this (check for // <-- added):
public function run()
{
if (!empty($this->_fields)) {
throw new InvalidCallException('Each beginField() should have a matching endField() call.');
}
$content = ob_get_clean();
if($this->withFormTag) { // <-- added
echo Html::beginForm($this->action, $this->method, $this->options);
} // <-- added
echo $content;
if ($this->enableClientScript) {
$id = $this->options['id'];
$options = Json::htmlEncode($this->getClientOptions());
$attributes = Json::htmlEncode($this->attributes);
$view = $this->getView();
ActiveFormAsset::register($view);
$view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
}
if($this->withFormTag) { // <-- added
echo Html::endForm();
} // <-- added
}
Thus if we instantiate a form like this:
$form = ActiveForm::begin([
'withFormTag' => false,
]);
It will not echo a <form> tag, but will render all ActiveField items and it will create their respective JavaScript/jQuery validators if $this->enableClientScript = true;.
2. Updates in my local view/file
After applying the previous fix in the base class, I needed to do the following in my view:
<?php $form = ActiveForm::begin([
'withFormTag' => false,
'id' => 'w0',
]); ?>
I had to pass the id parameter since every next instance of the ActiveForm class is incremented by 1, and I want my JavaScript/jQuery validators to be applied to the parent form, which by default starts from 0 -> w0.
And this is what did the trick!
Here's the Github issue as well: https://github.com/yiisoft/yii2/issues/12973
I am trying to get to figure out the proper way of handling a form receiving relational data in Yii2. I haven't been able to find any good examples of this. I have 2 models Sets and SetsIntensity, every Set may have one SetsIntensity associated with it. I'm am trying to make a form where you can input both at the same time. I'm not sure how to handle getting the input for a particular field 'intensity' in SetsIntensity.
Where
$model = new \app\models\Sets();
If I put it in the field like this client validation won't work and the attribute name is ambiguous and saving becomes difficult
<?= $form->field($model, 'lift_id_fk') ?>
<?= $form->field($model, 'reps') ?>
<?= $form->field($model, 'sets') ?>
<?= $form->field($model, 'type') ?>
<?= $form->field($model, 'setsintensity') ?>
I would like to do something like this but I get an error if I do
<?= $form->field($model, 'setsintensity.intensity') ?>
Exception (Unknown Property) 'yii\base\UnknownPropertyException' with message 'Getting unknown property: app\models\Sets::setsintensity.intensity'
I could do make another object in the controller $setsintensity = new Setsintensity(); but I feel this is a cumbersome solution and probably not good practice especially for handling multiple relations
<?= $form->field($setsintensity, 'intensity') ?>
relevant code from SetsModel
class Sets extends \yii\db\ActiveRecord
{
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios['program'] = ['lift_id_fk', 'reps', 'sets', 'type', 'intensity'];
return $scenarios;
}
public function rules()
{
return [
[['lift_id_fk'], 'required'],
[['lift_id_fk', 'reps', 'sets','setsintensity'], 'integer'],
[['type'], 'string', 'max' => 1],
['intensity', 'safe', 'on'=>'program']
];
}
public function getSetsintensity()
{
return $this->hasOne(Setsintensity::className(), ['sets_id_fk' => 'sets_id_pk']);
}
SetsIntensity Model
class Setsintensity extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'setsintensity';
}
public function rules()
{
return [
[['sets_id_fk', 'intensity', 'ref_set'], 'required'],
[['sets_id_fk', 'intensity', 'ref_set'], 'integer']
];
}
public function getSetsIdFk()
{
return $this->hasOne(Sets::className(), ['sets_id_pk' => 'sets_id_fk']);
}
}
I was also thinking maybe I could put in a hasOne() relation for the specific attribute 'intensity' in 'Sets'
You should simply try this :
<?= $form->field($model->setsintensity, 'intensity') ?>
EDIT : And because "every Set may have one SetsIntensity", you should check this relation before displaying form, e.g. :
if ($model->setsintensity===null)
{
$setsintensity = new SetsIntensity;
$model->link('setsintensity', setsintensity);
}
PS: link method requires that the primary key value is not null.