Django and ajax image file upload errors and csrf - ajax

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.

Related

Drupal 9 Webforms - using webform_token and testing for defined fields

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 %}

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;
}

Use AJAX to update django if-else template

In template I have:
{% for item in items %}
{% if item.public is True%}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon1
</a>
{% else %}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon2
</a>
{% endif %}
{endfor}
I use ajax to handle the request here:
$(anchor).click(function(e){
e.preventDefault();
var href = $(this).attr('href')
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
//refresh a div ?
}
});
});
Ajax handle the post, and in view it reverse a boolean value 'public'.
Question is, how do I update the template? I can pass the opposite icons and value, but it seems very redundant. Is there a way just to refresh that div with anchor and let the if else statement takes care of what's showing ?
Thanks
You are 99% close to answer your own question.
First, you you must wrap the {% for %} in a div and save it as a separate file, say:
<!-- injection.html -->
<div id="some-id>
{% for item in items %}
same code here
{% endfor %}
</div>
Now in your main template you should include that file like this:
<div id="wrapper">
{% include 'templates/injection.html' %}
</div>
Now, once you make an AJAX request to your views function then this view should render that div (which is a separate html file) but with a different items value. Like this:
# views.py
def article_public_edit(request, id):
if request.is_ajax():
# new calculation of the items QuerySet
# depending on the data passed through the $.ajax
return render(request, 'injection.html', locals())
Finally, you can do this inside the $.ajax() success function:
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
// replace the inside of #wrapper div with the injection.html (that has the new items values)
$("#wrapper").replaceWith(response);
}
});
With ajax calls there is no way the Django template tags will be re-evaluated. They only get evaluated on initial page load.
I think the best way to go is to have the ajax view return the boolean value and then set the image in your front-end code depending on that value.

Posting form in Laravel 4.1 and blade template

I'm having trouble posting forms using Laravel 4.1 with the blade template engine. The problem seems to be that the full URL including http:// is being included in the form action attribute. If I hard code the form open html manually and use a relative url, it works OK, however, when it has the full url, I am getting an exception.
routes.php
Route::any("/", 'HomeController#showWelcome');
HomeController.php
public function showWelcome()
{
echo($_SERVER['REQUEST_METHOD']);
return View::make('form');
}
Form opening tag in form.blade.php
{{ Form::open(["url" => "/","method" => "post","autocomplete" => "off"]) }}
{{ Form::label("username", "Username") }}
{{ Form::text("username", Input::old("username"), ["placeholder" => "john.smith"]) }}
{{ Form::label("password", "Password") }}
{{ Form::password("password", ["placeholder" => ""]) }}
{{ Form::submit("login") }}
{{ Form::close() }}
So if I go to my home dir / in the browser, I see the form that I have created. If I fill in the form details and click submit, I am simply taken to the same page - the request method is still GET as shown by echo($_SERVER['REQUEST_METHOD']);
I notice that the full
http://localhost/subdir/public/
url is used in the form markup. If I hardcode a form open tag in such as
<form action="/subdir/public/" method="post">
it works fine and $_SERVER['REQUEST_METHOD'] shows as post.
What am I doing wrong here?
You have created the route for the post?
example:
{{Form::open(["url"=>"/", "autocomplete"=>"off"])}} //No need to later add POST method
in Route.php
Route::post('/', 'YouController#postLogin');
you have not set up a route to handle the POST. You can do that in a couple of ways.
As pointed out above:
Route::post('/', 'HomeController#processLogin');
note that if you stick with your existing Route::any that the `Route::post needs to be before it as Laravel processes them in order (I believe).
You could also handle it in the Controller method showWelcome using:
if (Input::server("REQUEST_METHOD") == "POST") {
... stuff
}
I prefer the seperate routes method. I tend to avoid Route::any and in my login pages use a Route::get and a Route::post to handle the showing and processing of the form respectively.

rebuild content of a Div tag in complete function of $.ajaxt

I have a 4 column table of products in template,each item in table has an anchor with onclick like this:
<div id="tablepro">
<table>
<tr>
{% for product in cat.products.all %}
{% if forloop.counter|divisibleby:4 %}
</tr>
<tr>
<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>
{% else %}
<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>
{% endif %}
{% endfor %}
</table>
</div>
in remove function I have :
function remove(id)
{
var URL='{% url CompanyHub.views.catDetails company.webSite,cat.id %}';
URL+='delpro/'+id+'/';
$.ajax({
url:URL,
type:'POST',
complete:function(){
var str='<table><tr>';
{% for product in cat.products.all %}
{% if forloop.counter|divisibleby:4 %}
str+='</tr><tr>';
str+='<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>';
{% else %}
str+='<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>';
{% endif %}
{% endfor %}
str+='</table>';
$('#tablepro').html(str);
},
error:function(){
alert('Error');
}
});
}
in views.py :
def deleteProduct(request,key,cat_id,pro_id):
try:
company=Company.objects.get(webSite__iexact=key)
except Company.DoesNotExist:
Http404
cat=Category.objects.get(pk=cat_id)
if pro_id:
try:
product=Product.objects.get(pk=pro_id)
product.delete()
except Product.DoesNotExist:
Http404
return render_to_response('CompanyHub/Company/%s/cat_details.html'%(company.theme),{'company':company,'cat':cat}, context_instance=RequestContext(request))
as U see I've returned cat object that now a product object has removed from its list,but I can't get my Div updated in template!that sounds like cat object has not been updated in template tag.
any suggestion is appreciated
Template are compiled on server side and the browser renders the HTML.
To update your div after ajax call, you'd need to update it using javascript code in complete method. Your server side view can return JSON, XML, HTML or any other data type and your complete method has to render that data. Here is an example of how your complete method should look like if your server side returns partial html (i.e. just the table):
complete:function(data) {
$('#tablepro').html(data);
},
Remember that templates are compiled on the server side and the resulting HTML is then passed to the client. This means that the template code you have within your complete function (in the ajax call) will always be the same - in other words, every time you delete an element (and remove is called), you are redisplaying all the original categories again, as the HTML generated within the for loop is created on the server side once - not asynchronously

Resources