Comments (20)
Seems we need to add more docs on how to customize it, at least.
from form.
@terabytesoftw
I can configure the template itself in factory, but how am I supposed to change the dynamic part for each field individually? In my example <span class='fas fa-envelope fa-fw'></span>
is dynamic part, which is not actually part of predefined template and it needs to be set for each field. So the template is:
"{label}\n<div class='input-group'>\n{input}\n<div class='input-group-append'><div class='input-group-text'>{dynamic}</div></div>{hint}\n{error}</div>"
and I want something like:
$field->config($form, 'email')
->label(false)
->textInput(['required' => true])
->setDynamicPart('dynamic', 'Here goes dynamic contents')
from form.
I'm updating here again with another issue encountered while working on project (not to forget to address them all) and easy non-bc fix.
7. Field
class dropDownList
method and DropDownList
widget don't support setting custom attributes on items (options) which is valid html and is widely used for storing additional data needed for js as an example.
Update: The fix is not as trivial as I thought :(
Update 2: This is already supported. PHPDoc comments were a little messy on this one, so I've found it later, while reading the code.
from form.
You can configure the widget to your liking in various ways, regards.
<?php
declare(strict_types=1);
use App\Asset\LoginAsset;
use Yiisoft\Yii\Form\Widget\Form;
use Yiisoft\Yii\Form\Widget\Field;
use Yiisoft\Html\Html;
$this->params['breadcrumbs'] = 'Login';
$this->setTitle($this->params['breadcrumbs']);
$assetManager->register([
LoginAsset::class
]);
$fieldConfig = [
'labelOptions()' => [['class' => 'block text-gray-800 text-sm font-bold mb-2', 'label' => '']],
'inputOptions()' => [['class' => 'hadow appearance-none border rounded w-full py-2 px-3 text-gray-700 ' .
'leading-tight focus:outline-none focus:shadow-outline', 'placeholder' => false]],
'errorOptions()' => [['class' => 'text-red-500 text-xs font-bold italic']],
'hintOptions()' => [['class' => 'text-blue-500 text-xs font-bold']]
];
?>
<?= Html::beginTag('div', ['class' => 'form-security-login']) ?>
<?= Html::beginTag('p', ['class' => 'form-security-login-subtitle font-bold']) ?>
Please fill out the following fields <br/> Sign In
<?= Html::endTag('p') ?>
<?= Html::tag('hr', '', ['class' => 'mb-2']) ?>
<?= Form::begin()
->action($urlGenerator->generate('auth/login'))
->options(
[
'id' => 'form-security-login',
'class' => 'forms-security-login bg-white shadow-md rounded px-8 pb-8',
'csrf' => $csrf
]
)
->start() ?>
<?= Field::widget($fieldConfig)
->config($data, 'login', ['class' => 'mb-4'])
?>
<?= Field::widget($fieldConfig)
->config($data, 'password', ['class' => 'mb-6'])
->passwordInput()
?>
<?= Field::widget($fieldConfig)
->config($data, 'rememberMe')
->checkbox()
?>
<?= Html::beginTag('div', ['class' => 'flex items-center justify-between']) ?>
<?= Html::submitButton(
'Login',
[
'class' => 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded ' .
'focus:outline-none focus:shadow-outline',
'id' => 'login-button',
'tabindex' => '4',
]
) ?>
<?= Html::a(
'Forgot Password',
$urlGenerator->generate('recovery/request'),
['class' => 'inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800']
) ?>
<?= Html::endTag('div') ?>
<?= Html::beginTag('div', ['class' => 'text-center pt-3']) ?>
<?= Html::a(
'Didn\'t receive confirmation message',
$urlGenerator->generate('registration/resend'),
['class' => 'inline-block align-baseline font-bold text-sm text-red-500 hover:text-red-800']
) ?>
<?= Html::endTag('div') ?>
<?= Form::end() ?>
<?php echo Html::endTag('div');
from form.
@terabytesoftw Sorry, but your answer doesn't help with any of the issues mentioned. I'm not sure why you have closed the issue (I don't always have time to answer to all github replies immediately).
Now, for the issues:
- I still don't see a way to do that customization globally. You have showed how to customize some aspects in the view, but when I try to that customization in DI Container nothing happens, container code is the following for example:
\Yiisoft\Form\Widget\Field::class => [
'labelOptions()' => [['class' => 'some-class']],
],
- I still don't see any way to not apply your default options. They are applied in any case, but while customizing global defaults I want to have a way to not apply defaults at all. I'm ok with the approach of applying default options when you just want to add custom class to label for example in the view, and you don't need to re-specify the default options in that case, but I want to have a way to customize the defaults (by also removing those that are there).
- I still don't see a way to extend the functionality for input groups or anything similar.
Now, the Yii2 approach of not having final
class allowed to simply extend the class and make the necessary modifications, but the new approach extremely limits the possibilities. And now to have a form for any custom css framework we need to again build a custom library, but instead of just applying the changes we need, we must simply duplicate all the code that we need from here and customize it.
I'm not sure what's the right approach to solve that problem. One way I guess would be to provide also traits with common functionality for anybody who needs customization. Another way (the better one) would be to make the widgets (especially the Yiisoft\Form\Widget\Field
) make more extendable by keeping it final (closed for modification), but I'm not sure how.
@samdark Do you have any input here?
from form.
If you see the code example you will see that you can customize everything, through the constructor options.
In the example above I changed all the default settings to tailwindcss.
Options correct setting factory:
$fieldConfig = [
'labelOptions()' => [['class' => 'block text-gray-800 text-sm font-bold mb-2', 'label' => '']],
'inputOptions()' => [['class' => 'hadow appearance-none border rounded w-full py-2 px-3 text-gray-700 ' .
'leading-tight focus:outline-none focus:shadow-outline', 'placeholder' => false]],
'errorOptions()' => [['class' => 'text-red-500 text-xs font-bold italic']],
'hintOptions()' => [['class' => 'text-blue-500 text-xs font-bold']]
];
<?= Field::widget($fieldConfig)
->config($data, 'login', ['class' => 'mb-4'])
?>
Global:
Field::class => static function () {
$fieldConfig = [
'labelOptions()' => [['class' => 'block text-gray-800 text-sm font-bold mb-2', 'label' => '']],
'inputOptions()' => [['class' => 'hadow appearance-none border rounded w-full py-2 px-3 text-gray-700 ' .
'leading-tight focus:outline-none focus:shadow-outline', 'placeholder' => false]],
'errorOptions()' => [['class' => 'text-red-500 text-xs font-bold italic']],
'hintOptions()' => [['class' => 'text-blue-500 text-xs font-bold']]
];
return Field::widget($fieldConfig);
},
WebViewFactory:
$webView->setDefaultParameters(
[
'field' => $container->get(Field::class)
]
);
we just have to know how to use the container-di and the factory, in his example its use is wrong.
from form.
I prefer keeping final
and making everything customizable.
I still don't see a way to do that customization globally. You have showed how to customize some aspects in the view, but when I try to that customization in DI Container nothing happens
That should be customizable via factory config. Have you used it?
from form.
In Yii2 exists a lot of extensions based on form, activeform and their fields (e.g Kartik-v). With final class you will lock out future migrations from Yii2 to Yii 3.
I fear that either Yii2 will survive next 10 years or they will fork form package. In general the more breaking staff is built in Yii 3 more developers will stay on Yii2 instead of migrate. We have learnt this during switch from Yii 1 to Yii2. It shouldn't be a target to maintain three different Yii's for years. But the version steps would be another discussion.
Back to the current discourses. Inheritance isn't just css class configuration. It could have further methods. Once i wanted to extend activefield with automatic type recognition delivered from model. How can you do this withou inheritance or traits? Think about such scenarios please.
from form.
@Enrica-r most likely, you can do so with composition instead of inheritance.
from form.
@samdark Thanks for your answer.
I think composition isn't an ideal instrument for this purpose. I found a good blog named The Decision Between Inheritance And Composition which describes when using what.
An inheritance is a strong dependency saying "is a" while composition communicates between classes via interface (and DI) especially when reusing code.
In this case here I have a strong dependency like a "specialField is a Field". The "specialField" isn't eg. a frontend which communicates with a backend. They are never independant.
I have a theoretic example:
You want to add something in method "run" before running. What would i do:
Inheritance:
new class SpecialField extends Field
override method "run", add further functionality and call "parent::run"
--> that's it
Composition:
new class SpecialField
inject interface "FieldInterface" -> store it in private variable "$field"
redefine all methods and call interface like eg
private function renderBegin() {
return $field->renderBegin();
}
even if my class never changes this method. And more, such a class "SpecialField" will never be independent of changes in class "Field". It has to adapt to new content. Also, you inherit Field from Widget because Field is a Widget.
Do I have something missunderstand?
from form.
There are multiple ways to solve your example:
- Introduce beforeRun event. Then you don't have to deal with either inheritance or composition.
- Introduce an interface. Then you can implement decorator pattern.
But in your case you're using SpecialField explicitly and are willing to replace it in views. So it will be:
class SpecialField
{
public function run()
{
// before run
return Field::widget()->run();
}
}
from form.
What is the big advantage of not allowing extending classes/inheritance?
from form.
In many cases it results in better design.
from form.
After working a little bit with Field
and FormModel
in real project, I have following concerns:
requiredCssClass
,successCssClass
,errorSummaryCssClass
properties are not used anywhere- default options (all set by constants, e.g. classes) can not be removed at all. Why make them hardcoded at all?
isAttributeRequired
property inFormModel
is ignored when building field. Why not setrequired
input attribute by default in that case?- No way to determine if the form (
FormModel
) is already validated. Maybe add some flag? - Nested forms (
FormModel
s) to avoid duplicate code when building complex model from simple ones, that are already used somewhere else? - No way add dynamic parts. So for adding bootstrap frameworks input group to input field, I had to do for each field:
$field->config($form, 'email')
->template("{label}\n<div class='input-group'>\n{input}\n<div class='input-group-append'><div class='input-group-text'><span class='fas fa-envelope fa-fw'></span></div></div>{hint}\n{error}</div>")
What about a way to add some sort of dynamic parts, that can be precofigured, and we will just need to specify content of that part in view?
These are all main issues while building complex forms in real application.
from form.
If you have a proposal you can do it, nested forms seem like a good idea to me, and in general the use in real projects does not give a better way to use them.
from form.
@terabytesoftw isn't it possible to configure factory to solve point 6?
from form.
- An ability to disable container for the field (
Field
class). Use case: when stacking inputs in one row we don't need container (https://getbootstrap.com/docs/4.5/components/forms/#form-row) ✅ #33
from form.
- Array properties in the form model.
from form.
After working a little bit with
Field
andFormModel
in real project, I have following concerns:
requiredCssClass
,successCssClass
,errorSummaryCssClass
properties are not used anywhere- default options (all set by constants, e.g. classes) can not be removed at all. Why make them hardcoded at all?
isAttributeRequired
property inFormModel
is ignored when building field. Why not setrequired
input attribute by default in that case?- No way to determine if the form (
FormModel
) is already validated. Maybe add some flag?- Nested forms (
FormModel
s) to avoid duplicate code when building complex model from simple ones, that are already used somewhere else?- No way add dynamic parts. So for adding bootstrap frameworks input group to input field, I had to do for each field:
$field->config($form, 'email') ->template("{label}\n<div class='input-group'>\n{input}\n<div class='input-group-append'><div class='input-group-text'><span class='fas fa-envelope fa-fw'></span></div></div>{hint}\n{error}</div>")
What about a way to add some sort of dynamic parts, that can be precofigured, and we will just need to specify content of that part in view?
These are all main issues while building complex forms in real application.
Solve in new PR
.
from form.
from form.
Related Issues (20)
- Adapt after removing result set in validator
- Rename FormErrors to FormErrorSet (and similar) - consistency, best practices HOT 1
- Yiisoft\Form\Widget\Validator\FieldValidator::getValidatorAttributes() shouldn't apply required attribute for Required rule indiscriminately
- Remove filter of null values in methods for setting classes HOT 1
- Code style - chain calls HOT 15
- Add `$content` parameter to `Field::*Button()` methods
- Yiisoft\Validator\DataSet\AttributeDataSet not found
- Dependency update/adjust to yiisoft/html HOT 2
- Nested array form with translations HOT 3
- Checkbox don't accept label parameters HOT 1
- Input field name array HOT 1
- Add php attribute like #[SkipHydration] to skip private properties in collectAttributes() HOT 1
- Naming issue: attribute HOT 1
- Allow use fields without form model HOT 1
- Add constant with default theme and theme parameter to `Field` helper HOT 1
- Make fields indepent from validator HOT 1
- Raise PHP version to 8.1 HOT 1
- Add theme for Bootstap 5 HOT 1
- Checkbox 'checked' parameter input HOT 20
- Add ability partly change theme in `PureFieldFactory`
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from form.