form_widget : Add classes to existing classes - forms

I want to add classes to existing classes with twig, when invoking the form_widget()-function, so I'd like to merge them. But when I use
{{ form_widget(form.field1), {'attr': {'class': 'foo'}} }}
on an object that already has some classes attached to it by the controller, it doesn't add the class(es), but replaces them. According to the documantation this would
render a widget, but add a "foo" class to it
But the formulation isn't clear about, if the classes are really "added" or if they are replaced.
It seems that I would need to have a way to access the existing attributes/classes and merge them together with the ones I want to add. How can I accomplish this?

You might use form.field1.vars.attr.class and something like str1 ~ str2 to merge the already given classes and your new ones.
Putting it all together you get:
{{ form_widget(form.field1), {'attr': {'class': form.field1.vars.attr.class ~ foo'}} }}
this works and solves your problem. Some background:
According to the symfony documentation form.field1.vars.attr is a key based array, with a class-key.
So you can access all existing classes in this way.

Related

How to add DefaultAdress fields in Customer Sylius Form (symfony3)

I think the title is not very clear, so I will explain better :
I have edited the CustomerRegister form the add a few fields, and I would like to add DefaultAdress fields too (defaultAdress is a linked object to Customer - I have a getDefaultAdresse method in CustomerObject). I would like to add all the fields that are in the DefaultAddress object (street, country, etc.)
I don't know how to do that...
Do I need to modify the CustomerRegistrationTypeExtension to add fields for the address ?
How can I call the fields in my twig file ? Like that : {{ form_row(form.defaultAddress.street) }} ?
I didn't find doc to explain that case.
Thanks for your help !
You should create CustomerRegistrationTypeExtension, just like you described. Inside of this extension, simply do:
use Sylius\Bundle\AddressingBundle\Form\Type\AddressType;
$builder->add('defaultAddress', AddressType::class)
Then override the template and you should be able to render the fields or entire form with:
{{ form_widget(form.defaultAddress) }}
I'd recommend using our standard address form template, by simply including it:
{% include '#SyliusShop/Common/Form/_address.html.twig' with {'form': form.defaultAddress} %}

how to display particular fields in form Symfony 2.6

I need display particular fields in form in Symfony 2.6. I use a class Form. I have the folowing fields: name, email, message, send, recet. I need display all of them except recet .I try like this:
{{form_start(form)}}
{{ form_errors(form) }}
{{form_row(form.name)}}
{{form_row(form.email)}}
{{form_row(form.message)}}
{{form_end(form)}}
But, it's displaying all fields in form, it is not what I want. Even if i leave only {{form_start(form)}} and {{form_end(form)}} - its display all fields. Can someone help me wit this problem?
remove form_end, just close form with HTML
</form>
but then you must handle CSRF token generation by adding:
{{ form_widget(form._token) }}
{{ form_widget(form._token) }}
or try setting field you do not want to show using:
{% do form.recet.setRendered %}
but probably best way is not to add this field in the first place, rather than hiding it, by form options or event listeners depending on some criterias
A better solution is to remove the field from the form type. If you only remove it from the view, it may be interpreted as a blank submission for that field and delete existing data.
If you only use the form in one place, then just remove the field from the type. If you use it in multiple places, then you can selectively remove the field in a FormEvents::POST_SET_DATA event listener.

Parameter and view naming collisions in Play/Scala templates

I am new to Play Framework and still trying to wrap my head around some things with the new Scala template engine.
Let's say I have the following package structure:
app/
app/controllers/Items.scala
app/models/Item.scala
app/views/layouts/page.scala.html
app/views/item/show.scala.html
app/views/item/details.scala.html //partial
And this is my item/show template:
#(item: Item, form: Form[Item])(implicit flash: Flash)
#layout.page() {
#*want to include details partial, wont work due to item param*#
#item.details(item)
}
Since including another template (e.g. including item/details above) is the exact same syntax as accessing a template parameter (e.g. item above), obviously this existing naming convention won't work without something changing.
I know I can rename my "app.views.item" package to "app.views.items", and rely on singular/plural forms to differentiate the view from the param name, but this does not seem like a very straightforward solution. Also what if I really want the parameter name to be the same as the view package?
One idea I have is to prepend all my views with an extra top level package:
app/views/views/item/details.scala.html
So the include syntax would be #views.item.details(), but again this is obviously a hack.
What is a good way to avoid this issue? How can I better organize my code to avoid such naming collisions?
Most other template engines use operations like "include" or "render" to specify a partial include. I don't mean to offend anyone here, but is the Play Scala template engine syntax so terse that it actually dictates the organization of code?
3 solutions:
First
Typpicaly for partial templates you should use tags as described in the docs, where app/views/tags folder is a base:
file: app/views/tags/product.scala.html
in the templates (no initial import required in the parent view full syntax will allow you to avoid name-clash: #tags.packageName.tagName()):
<div id="container">
#tags.product(item)
</div>
Of course in your case you can also use packages in the base folder
file: app/views/tags/item/product.scala.html
<div id="container">
#tags.item.product(item)
</div>
I'm pretty sure that'll solve your problem.
Second
To avoid clash without changing package's name you can just rename the item in your view, also I recommend do not use a form name for the Form[T] as it can conflict with helpers:
#(existingItem: Item, existingItemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
#item.details(existingItem)
}
Third
If you'll fill your Form[Item] before passing to the view with given Item object, you don't need to pass both, as most probably you can get data from the form:
#(itemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
<div>Name of item is: #itemForm("name").value (this is a replacemnet for ##existingItem.name </div>
#item.details(itemForm)
}
Of course in you product.scala.html you'll need to change the #(item: Item) param to #(itemForm: Form[Item])

Generate subform in ajax call

I have a form with collection of subforms - student with different studies - relation manyToOne. I have corrent database schema and entities and form builder works well. I don't know how to append new "study" object. I need to get html tags from somewhere in either cases - when there is at least one "study: object (clone him) or there is no such a one.
Let's assume that study object has 2 fields: name and year. If for a student there is such a record (object) it's first input in generated form has name "student[study][0][name]". And is surrounded by . When I click "Add new study" button I want to duplicate this surrounding div and change id's and name's of html form elements respectively. Is there ready library or method to use?
But there may happen there is no study records so far. So I need to get form from server through ajax call. Unfortunately returned form has inputs with names like "study[name]". Is it possible to render this form similar to first case - I mean "student[study][0][name]". But i'd like to avoid manually generate twig template for form - I prefer
{{ form_widget(form) }}
You should be dealing with data-prototype rather than issuing separate AJAX request. The whole concept of adding/removing subform items is described here:
http://symfony.com/doc/current/reference/forms/types/collection.html#adding-and-removing-items
Obviously, you will need to some JS (jQuery is highly recommended) in order to replicate subform fields.
You should note, however, that data-prototype behaves differently when you initially have empty or non-empty collection. At least I have encountered this weird behavior. As far as I remember, in first your when you say {{ form_rest(form) }} additional DIV is appended with data-prototype attribute consisting of form's HTML. In second case actual HTML (not as an attribute) is appended with ID attribute "form_name_$$name$$" where you need to replace $$name$$ with proper index.
Now, you really should take a look - maybe all this has been fixed in some recent versions but I can't be sure...
Hope this helps a bit...

Explicitly print CSRF token field instead of form_rest(form)?

How can I explicitly print CSRF field instead of using {{ form_rest(form) }}?
I need this because I'm going to hide/show some fields based on conditions, however {{ form_rest(form) }} is going to print all of the remaining fields (which is what I'd like to avoid).
It can be done this way:
{{ form_widget(form._token) }}
Also you might want to consider adding fields conditionally in your form type instead of making that kind of decisions in a template.