How to display multiple data sets in Symfony2 - database

I am totally new to Symfony and i d like to know how I manage to display multiple data sets from my db in a twig...
untill now my attempt is the following:
class ProjController extends Controller
{
/**
* #Route("/", name="_projekte")
* #Template("FHBingenBundle:projekte:list.html.twig")
*
*/
public function indexAction()
{
$projekte = $this->getDoctrine()
->getRepository('FHBingenBundle:Projekt')->findAll();
return $projekte;
}
}
to get all the data sets. Here is where my Problem starts... how do I extract the data from the array? (the entity has multiple columns but i only want two of them, name and description)
{% extends "FHBingenBundle::layout.html.twig" %}
{% block content %}
<table>
<?php foreach ($liste as $projekt ?>
<tr><p>{{ $projekt->getName() }}</p></tr>
<?php endforeach;?>
</table>
{% endblock %}
thats how I tried to do it but apperently I am not allowed to use $ inside of {{}}? atleast thats what the error says

You should consider reading the cookbook.
Since you are using twig, think about using twig templating system.
{% for item in navigation %} // equivalent to foreach($navigation as $item) {
{{ item.name }} // equivalent to $item->name or $item->getName() or $item->hasName()
{% endfor %} // equivalent to }
EDIT : I don't really remember but it seems that you have to return an array for the twig templating system. return array('projects' => $projects);

Related

Initializing a modelchoicefield to a value in get_context_data()

I need to initialized a ModelChoiceField value to an instance retrieved in get_context_data() but it does not seem to work. I have tried .initial= but no luck so far.
This is the form
class PostEditForm(forms.ModelForm):
post_category = forms.ModelChoiceField(label='Category',queryset=Category.objects.all(),empty_label="--Select Category--",required=False)
class Meta:
model=Post
fields=('title','summary','content')
and this is the view
class EditPostView(LoginRequiredMixin, AjaxableResponseMixin, UpdateView):
model = Post
form_class = PostEditForm
template_name = 'postapp/editpost.html'
success_url = reverse_lazy('postapp:draftposts')
def get_context_data(self):
context = super().get_context_data()
post=self.get_object()
print(post)
try:
post_category = PostCategory.objects.get(post=post)
print(post_category)
except:
print("Post Category not yet assigned")
else:
context['form']['post_category'].initial = post_category
print(context['form']['post_category'])
return context
and here is the post category model
class PostCategory(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE)
category = models.ForeignKey(Category,on_delete=models.CASCADE)
def __str__(self):
return self.category.title
UPDATE
I forgot to mention I was rendering the form manually, here is the HTML
<select class="form-select" name={{form.post_category.html_name}} id='{{form.post_category.auto_id}}'
{% if form.post_category.field.required %}required{% endif %}>
{% for value, text in form.post_category.field.choices %}
<option
{% if form.post_category.value == value|stringformat:"s" %}selected="selected"{% endif %} value={{value}}>{{text}}
</option>
{% endfor %}
</select>
The value in the initial needs to be PK.
So:
context['form']['post_category'].initial = post_category.id
Also, since post and post category are mapped 1-to-many, PostCategory.objects.get() can return multiple post categories which raises MultipleObjectsReturned error. I suggest using a combination of filter and first so you get the first category if there are many. You will probably change this logic to something that makes sense but it's important to be aware of it.
post_category = PostCategory.objects.filter(post=post).first()
Bonus points: override the get_initial method as it's better practice when using class based views.
def get_initial(self):
initial = super().get_initial()
post=self.object
print(post)
post_category = PostCategory.objects.filter(post=post).first()
if post_category is not None:
print(post_category)
initial.update({'post_category': post_category.id})
print(initial['post_category'])
else:
print("Post Category not yet assigned")
return initial

In Twig: Check if array element exists. If not set this one element

In Twig, I pass an array params to a macro. Within the macro I check if all required elements (here: required_element) of params are set. If not, I want to set that to a default value.
This code is working, but I think there must be a better way:
{% macro my_macro(params) %}
{% if not params.required_element is defined %}
{% set params = params|merge({'required_element: 'value'}) %}
{% endif %}
I thought of something shorter like {% params.required_element ?: value %}, but that does not work.
For various reasons I do not want pass them one by one as parameters to the macro, so this is not an alternative:
{% macro my_macro(required_element, another_element, yet_another, puh_another, next_element) %}
Nope, that is the only (vanilla) way. If you want to make it shorter u'd need to extend twig with something like this:
<?php
$twig = new \Twig\Environment($loader);
$function = new \Twig\TwigFunction('set_array_value', function (&$context, $array_name, $index, $value) {
if (!isset($context[$array_name])) return;
/**
- If value is array just do arr[index] = value
- Otherwise test if object
-> test if method $index exists
-> test if there is a setter for the property $index
**/
if (is_array($context[$array_name])) $context[$array_name][$index] = $value;
elseif(is_object($context[$array_name])) {
if (method_exists($context[$array_name], $index)) $context[$array_name]->{$index}($value);
elseif(method_exists($context[$array_name], 'set'.$index)) $context[$array_name]->{'set'.$index}($value);
}
}, ['needs_context' => true, ]);
$twig->addFunction($function);
{% macro foo(my_array) %}
{% if not array.foo is defined %}{% do set_array_value('my_array', 'foo', 'bar') %}{% endif %}
{{ my_array.foo }}
{% endmacro %}
{% import _self as sandbox %}
{{ sandbox.foo({}) }} #output: bar
{{ sandbox.foo({'foo': 42,}) }} #output: 42

Twig: Append to array inside array/object

I have an object which, in JSON, would look like this:
{
'class': ['nav-link', 'dropdown-toggle'],
'data-toggle': ['dropdown']
}
I need to then be able to append another class to the class array inside the object.
This code doesn't seem to work; it just overwrites the class array.
{% set link_attribs = { 'class' : ['nav-link', 'dropdown-toggle'], 'data-toggle':'dropdown'} %}
{% set link_attribs = link_attribs|merge({'class': ['highlighted']}) %}
Really I want to do something like this, but it just throws a punctuation error.
{% set link_attribs.class = link_attribs.class|merge(['highlighted']) %}
Any ideas?
Using Twig, you can't set object properties directly, so "set (...).class" will never work. But instead, you can create a new variable that will inherit from both default and options values (just like in most JavaScript codes).
For example:
{%
set options = link_attribs | merge({
'class': link_attribs.class | merge(['highlighted'])
})
%}
{% for class in options.class %}
{{ class }}
{% endfor %}
Will display:
nav-link
dropdown-toggle
highlighted
See fiddle.
This looks like it works:
{% set c = link_attribs.class %}
{% set c = c|merge(['highlighted']) %}
{% set link_attribs = link_attribs|merge({'class': c}) %}
Not sure if its the most elegant way though.

Move if/then logic into view or model or keep in template?

after creating a web app using backbone for an engine design firm, I'm wondering if I should move the "if/then" logic out of the html templates.
To help clarify what I mean, here are two examples that I am currently using in production.
If I move the if/then logic out of the template, I would move it to the view, but I'm not sure if that's the "right" way or "backbone" way of doing things.
Am I making poor design decisions, or is what I've done OK?
Thanks!
Simple Example 1:
In the view:
//m is the model used by the view
return Backbone.View.extend({
template: _.template(tmpl, null, { variable: 'm' }),
In the template:
{% if(m.title) { %}
<h4> {%- m.title %} </h4>
{% } else { %}
<h4>Experiment Title Goes Here</h4>
{% } %}
Complex Example 2:
In the view:
//args are the model attributes passed into the view
initialize: function (args) {
this.currentEngine = args.currentEngine;
this.engineDisplay = args.engineDisplay;
this.engineType = args.engineType;
this.isCurrent = this.model.isCurrent(this.currentEngine);
},
render: function () {
this.$el.html(this.template({
engineDisplay: this.engineDisplay,
engineType: this.engineType,
isCurrent: this.isCurrent;
}));
In the template:
{% if(!engineDisplay) { %}
{% if (m.isCurrent && (engineType === 'GAS' || engineType === 'ECO')) { %}
<span>Not Available</span>
{% } else { %}
<span>
<span>Click here to select</span>
</span>
{% } %}
{% } %}
I think your first implementation was correct. Keep the logic out of the view. The "correct" way, or the "backbone" way is to keep the logic where it needs to be:
the model/collection houses code of "where" the data needs to come from.
the view houses code of "what" it needs to do/display. (what needs to happen if event X happens)
the template should house the code of "how" it needs to be displayed.
I'm sure im missing stuff.. i'll wait until the comments tells me how wrong i am and then i'll correct it.
-Sheers

Google App Engine: Outputting 'values' from a SearchResult object on Jinja2 template.

I would like to return the field values of a SearchDocument's object. For example, I have generated a SearchResult object using:
class SearchResult(Handler):
def get(self):
index = search.Index("INDEX_NAME")
results = index.search("Brian")
self.render('search-result.html', results = results)
The results object looks something like this:
search.SearchResults(results=[
search.ScoredDocument(
doc_id=u'6122080743456768',
fields=[search.TextField(name=u'full_name', value=u"Brian Jones"),
language=u'en',
rank=106509239L),
search.ScoredDocument(
doc_id=u'4714705859903488',
fields=[search.TextField(name=u'full_name', value=u"Brian Lara"),
language=u'en',
rank=106427057L)],
number_found=2L)
Inside search-result.html, how can I return the values of the fields?
...
<body>
{{ field_values }} #return the field values "Brian Lara" and "Brian Jones"
<body>
...
Start here:
{% for result in results %}
{{ result.fields[0].value }}
{% endfor %}
(You have a '[' mismatch in your fields. Fix that, then check the syntax)

Resources