Drupal 9 Webforms - using webform_token and testing for defined fields - webforms

We have 6-8 different webforms on our site which submit via ajax and display the conformation message inline. I would like to put data from the form submissions into a JavaScript data layer so we can pass it on to Google Tag Manager. I thought the most fool proof way to do this, and make sure it gets done on any new form going forward, would be to create a custom webform-confirmation.html.twig template and drop the fields we are interested in. Once there I am printing the submitted data by using the following TWIG:
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'email': '{{ webform_token('[webform_submission:values:email]', webform_submission) }}',
'timeline' : '{{ webform_token('[webform_submission:values: timeline]', webform_submission) }}',
});
</script>
That works great for the email field as it is on every form and always required. However some forms have a “timeline” field and other do not. For forms that have timeline I expected
{{ webform_token('[webform_submission:values: timeline]', webform_submission) }}
Would just print nothing, but instead I get the following output:
[webform_submission:values:project_timeline]
I have tried everything I can think of in TWIG to test to see if the webform_submission:values: timeline is defined but am unable to get anywhere. Is this possible? Any ideas?
Drupal Version 9.4.9
Webform Version: 6.1.3
Thanks,
summer

I ended up doing it as follows, feels like there should be a better solution but this is working....
{% set project_timeline= webform_token('[webform_submission:values:project_timeline]', webform_submission) %}
{% if project_timeline!= "[webform_submission:values:project_timeline]" %}
'project_timeline' : '{{ project_timeline }} ',
{% endif %}

Related

October CMS and navigation on current page

I am trying to get the basically the active class applied to the current page. As it goes, the builder plugin is setting the URL through:
<a href="{{ detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }) }}">
However I am new to October so I am not sure how to reference this.page.id in comparison to the url set above.
Basically I want this:
{ set UrlParam = detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }
{% if this.page.id == UrlParam %} class="active" {% endif %}
Any ideas?
One of the best debugging plugins out there for OctoberCMS is this: https://octobercms.com/plugin/davask-dump
That plugin makes connecting your twig templates to your database / php rendering a breeze.
After installing that plugin you can use {{ d(variable) }} instead of {{ dd(variable) }} and get more information on the array nests etc.
So I would do {{ d(UrlParam) }} and {{ d(this.page.id) }} in your twig template. See what the dump has to say about each of those variables. For clarity I do believe you need the % here {**%** set 'variable' **%**}.
I am also not a fan of the builder component and I use the PHP section on the page / partial pages. And establishing a class with the use function and access the data with $this['variable']. Maybe worth looking into here is a quick example:
Pluginauthor\Plugin\Models\Plugin;
function onStart() {
$plugin = Pluggin::all();
$this['plugin'] = $plugin;
}

How to update a modelForm in Django with Ajax

I would like to update a template with Ajax.
My problem is:
I select a client in a list on the form and display only the corresponding data in an another list on the same page in a second list
At this time, I can not update my template with protocols corresponding to the client
In my views, I try to create a list with a queryset (it works)
but I cannot update my template with the new list
I retrieve the selected client but when I post with render_to_request
it does not update the template
Is there any possibility to do that and how can I update my list with the ajax part of the program.
You can use something like this:
(based on https://stackoverflow.com/a/21762215/5244995)
second_list.tmpl (template)
{% for value in corresponding_data %}
<li>{{ value }} (replace with your own templating)</li>
{% endfor %}
views.py
def update_second_list(request, ob_id):
# (get the data here)
return render('second_list.tmpl', {'corresponding_data': ...}
JS script on main page (uses jQuery)
$.ajax({url:"", dataType:"text", success: function(html) {
var newDoc = $.parseHTML(html, document, false); // false to prevent scripts from being parsed.
var secondList = $(newDoc).filter(".secondList").add($(newDoc).find(".secondList"));
$(".secondList").replaceWith(secondList); // only replace second list.
// other processing
}});

Most common way to structure similar but unique ajax requests that depend on Django pk?

(I'm using jquery and django)
Let's say I have a todo list, with each item having a unique primary key (pk). In the template, I list these items with a for loop so that each item is clickable, to display item details on another portion of the page (without reloading the entire page of course).
What is the generally accepted best way to do this?
I have tried multiple ways of "uniqueifying" each div, and multiple ways of passing this pk along in the ajax request.
Part 1 - getting unique divs:
I put the pk as the suffix to each item div's id. e.g. {% for item
in todolist %} stuff
$('body').on('click',"#item_{{item.pk}}", function(){var id = {{item.pk}}, .ajax stuff })
{% endfor %}
instead of suffixing pk, I add a custom html attribute called
data-id. This allows me to use .attr("data-id") to get the pk from
the clicked div and to remove the js from the for loop.
instead of adding a custom html attribute, I add a hidden form field.
Part 2 - passing pk to ajax request:
in the $.ajax() body, I set url: id+"/details" with the data field empty. In Django, I grab the id from the url regex definition.
in the $.ajax() body, I set url: "/details" with data: {id:id}. In Django, I grab the id from inside views.py with request.POST['id'].
in js, I just submit the form. Django gets the id as a form field.
So... with so many (probably bad) ways of doing this, which would you use?
I will go for a single ajax function and it should be:
{% for item in todolist %}
<div id="{{item.id}}" class="item_ajax" >{{item.name}}</div>
{% endfor %}
<script>
$('.item_ajax').click(function(){
$.ajax({
type: 'POST',
url: '{% url item_url %}',
data: {'id': $(this).attr('id'), 'csrfmiddlewaretoken': '{{csrf_token}}'},
dataType: "text",
success: function(response) {
// do something
},
error: function(rs, e) {
alert(rs.responseText);
}
});
});
</script>
I have used a class selector, obviously you can choose what ever you like e.g. having a custom attribute but it should be common.

Building a widget manager on top of Symfony 2 (multiple controllers in one page)

Use case
I am developing a CMF on top of Symfony2. One of the features will be the support of "widgets": an possibility for end users to add small 'blocks' or 'modules' to a page. Examples:
A small login form
A list of products
Some photo's from a gallery
A shopping cart
The idea is that most of those widgets will link to to normal, full page Routes/Controllers.
For example: a user want a list of popular products in a sidebar on a content page. The items will link to the normal /product/{name} route of the ProductController. But the list in this case would be a widget. The end user can define where it must be placed, and for example, how much items must be shown.
The behavior of the 'widgets' is the same as regular Symfony2 controllers, it has routes, actions, it renders a view, etcetera. There is a WidgetManager with a catch-all route to load the widgets, configure them and render them in the right place.
I have not that much experience with Symfony2, but I am playing wit it now for more then 3 months. I definitely want to stay with Symfony2, but will need to add some magic to realize some of my ideas.
Question
What is the best way to support rendering multiple controllers (widgets) in one request?
Research
Symfony's TwigExtension "ActionExtension" contains a "render" method, which contains the basic idea:
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
(Documentation: http://symfony.com/doc/current/book/templating.html#embedding-controllers)
But it is quite limited. Some problems with this approach:
I cannot configure the 'widgets' before rendering them (for example: $myWidget->set('show_toolbar', false)), I don't want to pass all options as controller action parameters.
It is not possible to use template inheritance. I need this for example for 'injecting' the asset references (javascript/css) in de base <HEAD> block.
What I want
I want the following code to work (this is a simplified example):
// Serius\PageBundle\Controller\PageController.php
// executed by a catch-all route
public function indexAction($url) {
// load CMS page, etc
$widgets = $this->loadWidgets($page); // widgets configuration is stored in database
// at this point, $widgets is an array of Controller *instances*
// meaning, they are already constructed and configured
return $this->render("SeriusPageBundle:Page:content.html.twig", array(
'widgets' => $widgets
));
}
Serius\PageBundle\Resources\views\Page\content.html.twig
{% extends 'SeriusPageBundle::layout.html.twig' %}
{% block content %}
{% for widget in widgets %}
<div>
{% render widget %}
<!-- Of course, this doesn't work, I would have to create my own Twig extension -->
</div>
{% endfor %}
{% endblock %}
An example of a widget template:
{% extends '::base.html.twig' %}
{% block stylesheets %}
My stylesheets
{% endblock %}
{% block body %}
This is a shoppingcart widget!
{% endblock %}
How can I achieve this? Do someone have experience with anything like this? I already looked at the Symfony CMF project, but it has no support for this (as far as I could find out).
I have something similar going around and I think that this code will help you. In chosen template you get the variables with the names of blocks.
public function render()
{
$modules = $this->moduleService->getModules();
foreach($modules as $m){
$templateName = $m->getTemplateName();
$template = $this->twig->loadTemplate($templateName);
$blockNames = $template->getBlockNames();
foreach($blockNames as $b){
if(isset($this->blocks[$b]) == false)
$this->blocks[$b] = '';
$this->blocks[$b] .= $template->renderBlock($b, array('a' => 'aaa', 'b' => 'bbb'));
}
}
$content = $this->twig->render('Admin/index.html.twig',$this->blocks);
return new \Symfony\Component\HttpFoundation\Response($content);
}
I know this is old, but if anyone is looking for something like this the SonataBlockBundle might be your solution.
https://github.com/sonata-project/SonataBlockBundle

Django and ajax image file upload errors and csrf

I tried out Alex Kuhl's ajax script to upload images to Django 1.4.
My first question is why I'm getting an empty page with firebug telling me I have an error:
In my template html:
$ is not defined
element: $('#file-uploader')[0],
Here is my entire html file for it:
http://pastebin.com/NjbV5gMn
My second question is why the ajax code uses {{ csrf_token }} instead of {% csrf_token %}. But if I use {% csrf_token %}, I get the firebug error:
missing } after property list
'csrf_token': '<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='Cx0zFFak6OLgrHiAnFa3k4BPDmn4BgoT' /></div>',
EDIT: I changed the element to document.getElementById('file-uploader') and it seems to work, so I think I've solved my first question.
For the first question, $ is introduced by jQuery library, you need to load it before the usage. (or use document.getElementById('file-uploader') which is equivalent to $('#file-uploader')[0])
For the second question, the javascript line expects a csrf token, which could be introduced through {{ csrf_token }}, instead of a div tag including an input field w/ csrf token as its value, which the {% csrf_token %} does.
For {{ csrf_token }} to work, check the 3rd step in the doc, add 'django.core.context_processors.csrf' into your TEMPLATE_CONTEXT_PROCESSORS and use RequestContext in your view.

Resources