easy simple question.
I made a register form. When you press the submit button the Controller handles the request and renders.
if($form->isSubmitted && $form->isValid()) {
return $this->render('x/register.html.twig', array(
'options' => 'userCreated',
'userName' => $user->getUsername()); }
in the .html.twig
{% if options=="userCreated" %}
user {{userName}} was successfully inserted into the database
{% else %}
//show the form
{% endif %}
This worked perfect but my "teacher" told me, that I have to do this more dynamic.
I did a new "Info.html.twig" now with 2 parameters (redirectUrl, redirectText) e.g.
$redirectUrl="/home"; $redirectText="Go to the home page"
in HTML
{{redirectText}}
and if there is a message at the top I use the flashMessage method ($this->addFlash).
Is that a good method or is there a way to get way more dynamical than this?
Related
i'm trying to add a field type url in the list view of an entity, this is the link at the documentation -> https://symfony.com/doc/master/bundles/SonataAdminBundle/reference/field_types.html#url .
This is my code, i've simply copied the documentation:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('url', 'url', [
'url' => 'http://example.com'
]);
}
This seems to work but the column "Url" is always empty.
I found the template of Sonata that is responsible to render this field -> #SonataAdmin/CRUD/list_url.html.twig .
Here is the code
{% extends get_admin_template('base_list_field', admin.code) %}
{% block field %}
{% spaceless %}
{% if value is empty %}
{% else %}
{% if field_description.options.url is defined %}
...
The problem is that value is always empty, i don't know what is this variable; and the documentation is not talking about any field named value.
So you can achieve this by creating a template which simply contains a button with the URL you'd like to link to. See below:
First we define a field on the list view which references a template, the type is null:
->add('foo', null, [
'template' => 'example/foobar.html.twig',
])
Inside our template we've just referenced, we can do the following:
{% extends '#SonataAdmin/CRUD/base_list_field.html.twig' %}
{% block field %}
<a class="btn btn-success" href="http://google.co.uk/">My Link</a>
{% endblock %}
and now you should see the button display as a column on the list view.
It would be nice if the documented suggestion worked as intended, this solution is a work around.
I tried to follow this answer to handle nested collections in forms.
I have an Application's Form with a collection of LienAppliServ's Form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('servLiens', 'collection', array(
'label' => ' ',
'type' => new LienAppliServType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' =>false,
'prototype' => true,
))
//...
In my LienAppliServ's Form, I have another collection of PortLienAppliServ's Form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('ports', 'collection', array(
'type' => new PortLienAppliServType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' =>false
))
//...
And the form of PortLienAppliServ is :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('numPort')
->add('type')
;
}
Now, I'd like to handle add/delete for each collection...
As I said, I tried to follow this answer
In order to do that, I tried :
{% block body -%}
{{ form_start(form) }}
<ul id="col-servliens" data-prototype="{{ form_widget(form.servLiens.vars.prototype)|e }}">
{# iterate over each existing tag and render its only field: name #}
{% for servLiens in form.servLiens %}
<li>{{ form_row(servLiens) }} </li>
<ul id="col-ports" data-prototype="{{ form_widget(ports.vars.prototype)|e }}">
{%for ports in servLiens.ports %}
<li>{{ form_row(ports) }}</li>
{% endfor %}
{% endfor %}
</ul>
{{ form_end(form) }}
{% endblock %}
{% block app_js %}
//Same as the other question
<script>
function FormCollection(div_id)
{
// keep reference to self in all child functions
var self=this;
self.construct = function () {
// set some shortcuts
self.div = $('#'+div_id);
self.div.data('index', self.div.find(':input').length);
// add delete link to existing children
self.div.children().each(function() {
self.addDeleteLink($(this));
});
// add click event to the Add new button
self.div.next().on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
self.addNew();
});
};
/**
* onClick event handler -- adds a new input
*/
self.addNew = function () {
// Get the data-prototype explained earlier
var prototype = self.div.data('prototype');
// get the new index
var index = self.div.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
self.div.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
self.div.append($(newForm));
// add a delete link to the new form
self.addDeleteLink( $(self.div.children(':last-child')[0]) );
// not a very nice intergration.. but when creating stuff that has help icons,
// the popovers will not automatically be instantiated
//initHelpPopovers();
return $(newForm);
};
/**
* add Delete icon after input
* #param Element row
*/
self.addDeleteLink = function (row) {
var $removeFormA = $('<i class="entypo-trash"></i>');
$(row).find('select').after($removeFormA);
row.append($removeFormA);
$removeFormA.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// remove the li for the tag form
row.remove();
});
};
self.construct();
}
</script>
<script>
$(document).ready(function() {
new FormCollection('col-servliens');
new FormCollection('col-ports');
});
</script>
And I get
Variable "ports" does not exist.
I really need some help.. Collections are actually my nightmare...
Thanks !
Let me start with apologies, because my answer in the post you mention was clearly wrong :) At least the example code was incorrect. I wonder if the original poster ever found the right solution.
The error is easy enough to spot. In the Twig you use the variable ports, but how should Twig know where it comes from?
{% for servLiens in form.servLiens %}
<li>{{ form_row(servLiens) }} </li>
<ul id="col-ports" data-prototype="{{ form_widget(ports.vars.prototype)|e }}">
{%for ports in servLiens.ports %}
<li>{{ form_row(ports) }}</li>
{% endfor %}
{% endfor %}
Using {{ form_row(servLiens) }} will actually already create the collection classes, so the whole <ul> inside it is not needed. In fact Symfony is smart enough that you don't even need the first <ul>. It will find any child forms (ex. collections) and create all the HTML needed.
So the only thing you need to have in your code is:
{{ form_row(form.servLiens) }}
If you would look at the HTML generated from that, you will see the data-prototype and the children. It will automatically have an id attribute that you can use.
Problem is the javascript part. You are using a collection within a collection. The javascript FormCollection class (which I wrote) cannot handle this as simply as you've tried it. It will handle the top collection fine, but it will not automatically instantiate collections on load/create/delete. Remember that each servLiens collection has a collection of ports. Therefore already at loading you can't simply load the col-ports as you do now, but would need to load each port collection. Then you'd need to instantiate a new FormCollection on the port collection every time you add a servLiens row.
I don't have time to create your code for you, but I hope my explanation helps you to find a solution.
Looks like you use symfony 2.6 or older.
I would start by saying you should'nt do "'type' => new PortLienAppliServType()" but pass the form type name. Symfony will instantiate it and it could be the problem.
Everything is described in extend here: https://symfony.com/doc/2.6/reference/forms/types/collection.html#basic-usage
Honestly, Collections are not that difficult you just need to understand how it works then Symfony will manage everything for you.
does anyone know now to create a custom view type for ez platform? The default 3 have been exhausted and we need a new one for 'link'
Alternatively, does anyone know how to use the render( controller( with a custom template as this would also resolve out block right now.
Basically, we have a multi-relational field in a content object used and we need to print links to all the related contentIds, path works great but we cannot find a way to extract the name of the content object for the link without doing some fairly funky tpl logic of passing in params.
EG: As a hack for now we can pass in "embed_type" as a custom param with the render(controller("ez_content:viewAction" to pull in an alternate view for the content object for a specific content type and view type.
{% if embed_type is defined %}
{% include "embed/#{embed_type}.html.twig" %}
{% else %}
<h1>{{ ez_field_value( content, 'name') }}</h1>
{% endif %}
However, this is very ugly and all we really want to do is use 1 template for all content types, so all we need to do is loop through the relational field and print links (as the only thing available in the content field: "destination ids"). I am sure there used to be this option in the docs but i cannot find it anymore eg:
{% set links = ez_field_value( footer, "first_links_row" ).destinationContentIds%}
{% for id in links %}
{{ render(controller("ez_content:viewAction", {"contentId": id, "template": "link.html.twig"})) }}
{% endfor %}
Where the link.html.twig would simple print the link:
<a href="{{ path( "ez_urlalias", {"contentId": id} ) }}">
{{ ez_field_value( content, "name" ) }}
</a>
If using a custom tpl is not possible with the render (controller ( helper then a new custom view type would also fix this issue, but i cannot find documentation for either.
You can create a twig function that would do that. We have something like this:
Definition:
new Twig_SimpleFunction(
'content_name',
array($this, 'getContentName')
),
Implementation:
public function getContentName($content, $forcedLanguage = null)
{
if (!$content instanceof Content && !$content instanceof ContentInfo) {
$contentInfo = $this->repository->getContentService()->loadContentInfo($content);
} elseif ($content instanceof Content) {
$contentInfo = $content->contentInfo;
} else {
$contentInfo = $content;
}
return $this->translationHelper->getTranslatedContentNameByContentInfo($contentInfo, $forcedLanguage);
}
which enables you to provide either content id, content info or content itself, and it returns translated content name
Having issues trying to redirect after from submission to edit more fields
Also with creating the hyperlink to the submission.
When submitting my form with the redirect i get the error below.
If i submit the form with the render request to another page the form saves ok.
Request Method: POST Request
URL: http://127.0.0.1:8000/resourcelib/add_pricebook Django
Version: 1.8.4 Exception Type: NoReverseMatch Exception Value:
Reverse for 'detail_pricebook' with arguments '()' and keyword
arguments '{'p_id': 22L}' not found. 0 pattern(s) tried: []
My Model.py
class PriceBook(models.Model):
pricebook_id = models.AutoField(primary_key=True)
pricebook_name = models.CharField(max_length=255,verbose_name='PriceBook Name')
discription = models.TextField(verbose_name='Discription')
date_created = models.DateTimeField(auto_now_add=True, blank=True)
active = models.SmallIntegerField(max_length=1, blank=True)
def __unicode__(self):
return self.pricebook_name
view.py
def new_pricebook(request):
if request.method == "POST":
pricebook_form = PricebookForm(request.POST)
if pricebook_form.is_valid():
post = pricebook_form.save(commit=False)
post.save()
#return render(request, 'resourcelib/thanks.html',)
return redirect('detail_pricebook', p_id=post.pricebook_id)
else:
pricebook_form = PricebookForm()
return render(request, 'resourcelib/pricebook_add.html', {'pricebook_form': pricebook_form})
def detail_pricebook(request, p_id):
pricebook_from = get_object_or_404(PriceBook, pk=p_id)
return render(request, 'resourcelib/pricebook_detail.html', {'pricebook_from':pricebook_from})
url.py
url(r'^add_pricebook', views.new_pricebook, name='new_pricebook'),
url(r'^list_pricebook', views.list_pricebook, name='list_pricebook'),
url(r'^detail_pricebook/(?P<p_id>[0-9]+)/$', views.detail_pricebook, name='detail_pricebook'),
I don't believe it's in url file, because i get no errors if i browse to the entry eg.
127.0.0.1:8000/resourcelib/detail_pricebook/3/ - works ok
However i can't get my links working either, i can list my entries ok. But the link won't work from the code below when you click on the link it just comes up 127.0.0.1:8000/resourcelib/%7B%%20url%20'detail_pricebook'%20p_id.pk%7D
{% if pricebooks %}
<ul>
{% for pricebook in pricebooks %}
<li><h1>{{ pricebook.pricebook_name }}</h1></li>
{% endfor %}
</ul>
{% else %}
<p>No price books have been created.</p>
{% endif %}
{% endblock %}
Any help would be greatly appreciated
% missing in the url tag. Be more careful.
thanks #ozgur, have the the idea that i have the wrong reference for the pk. I was able to sort out the issue. I had a name name space on the primary project urls.py ... probably information i should have give, forgot I used cookiecutter for this one
url(r'^resourcelib/', include('oneworksite.resourcelib.urls', namespace='resource')),
so i was then able to get the link working with
{{ pricebook.pricebook_name }}
Then in my redirect i changed to
return redirect('resource:detail_pricebook', p_id=post.pk)
How could I achieve a form for each list item using csrf and validation in symfony way?
I have a Task entity, which has comments property with a relation OneToMany. So I want to list all tasks and include a hidden comment form for every task. Usually I pass generated forms from controller to template, but how to create them dinamically in template?
{% for task in tasks %}
<taskinfo>
<task comment form>
{% endfor %}
Solved using this way:
In controller:
$forms = array();
foreach($tasks as $task) {
$entity = new TaskComment();
$forms[$task -> getId()] = $this ->createTaskCommentForm($entity, $task -> getId());
}
return $this->render('Bundle:blah:index.html.twig', array(
....
'forms' => $forms
));
An then comment box near every Task box in view:
...task info...
{% for task in tasks %}
<div class="comment-box">
{{ form(forms[task.id]) }}
</div>
{% endfor %}
P.S. I'm using collapsible panels to show/hide each task.
Maybe you need to embed a collection of forms? If so, here and here you can read more.