I have an article where i allow people to comment.
When the user clicks on the reply button in a submitted comment an ajax request is being sent to retrieve html from a file to add a new element to the DOM that contains the reply form.
I'm using this code:
function handle_ajax_request(event) {
if ( request.readyState === 4) {
if (request.status === 200 || request.status === 304) {
console.log("AJAX request from get_reply_form was received successfully from the server.");
parentElement = document.getElementById("reply_comment");
reply_form_element = document.createElement("div");
reply_form_element.id = "reply_comment_form";
parentElement.appendChild(reply_form_element);
reply_form_element.innerHTML = request.responseText;
} else {
console.log("Error: AJAX request from get_reply_form failed!");
}
}
}
function get_reply_form(event) {
event.preventDefault();
reply = document.getElementById("reply_comment");
request = new XMLHttpRequest();
if (! request) {
console.log("Error: Unable to create AJAX request.")
}
console.log("Created ajax request, checking for state.");
request.onreadystatechange = handle_ajax_request;
request.open("GET", "http://localhost:8000/static/html/experience/comment_reply_form.html", true);
request.send(null)
}
I fetch this file with the ajax request:
{% load comments %}
{% get_comment_form for article_details as form %}
<form action="{% comment_form_target %}" method="post">{% csrf_token %}
{{ form.object_pk }}
{{ form.content_type }}
{{ form.timestamp }}
{{ form.security_hash }}
{% if node.id %}
<div class="form-group">
<input type="hidden" class="form-control" name="parent" id="parent_id" value="{{ node.id }}" />
</div>
{% endif %}
{{ form.comment }}
<div class="col-md-4">
<div class="form-group">
<input type="hidden" class="form-control" name="next" value="/article/display/{{ article_details.id }}" />
<input type="submit" class="form-control" value="Reply">
</div>
</div>
</form>
As you can see there is some django template syntax code in that html.
When i add this html to a div on the page it works except from that the django syntax is not being interpreted by django for some reason and i dont understand why its not being interpreted normally.
I literally get this displayed:
Posted by an anonymous user 4 days, 20 hours ago
test
Reply
{% get_comment_form for article_details as form %}
{% csrf_token %} {{ form.object_pk }} {{ form.content_type }} {{ form.timestamp }} {{ form.security_hash }} {% if node.id %}
{% endif %} {{ form.comment }}
The django syntax is being display literally and should not be visable at all if it was interpreted by django. Why doesnt this work ?
In the html code a " is inserted before the django syntax for some reason, i dont know why and a " is added at the end. Also, its seem that every time a { is encountered a " is put in front of it and a " is put at the end and i dont know why.
I'm not using jquery since im currently learning about javascript and i like to learn the plain version as welll and not just frameworks.
You're making a get request against a static HTML template. You should be making the request against a URL that calls a view, like any other Django page.
Related
I'm trying to make a stock finance like website where anyone can get fake money and buy stocks. So in the buy page, I am trying to implement a feature where as the user types the stock symbol and the number of shares, in real time, the pricing shows up in the h1 tags that have an id of "render". This can be achived if user input is sent to my app.py and after looking up the price using an api and some math, app.py send the price back to javascript to update the page.
I've been trying to use fetch() and AJAX but I don't understand any of the tutorials or stack overflow questions. Can someone give me a reliable solution and explain it to me?
HTML:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" name="symbol" placeholder="Symbol" value="{{ input_value }}" id="symbols">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" autofocus name="shares" placeholder="Shares" id="shares">
</div>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<h1 id="render">
</h1>
<script>
</script>
{% endblock %}
App.py:
#app.route("/buy", methods=["GET", "POST"])
#login_required
def buy():
"""Buy shares of stock"""
if request.method == "GET":
return render_template("buy.html", input_value = "")
else:
return render_template("buy.html", input_value = request.form.get("symbol"))
I'm trying to use the function above for rendering the template
Accepting response and sending back information:
#app.route("/show_price", methods=["GET", "POST"])
def show_price():
#logic stuff
return #price
TL;DR at bottom
I found a solution to the problem by using this as my app.py:
#app.route("/show_price", methods=["GET", "POST"])
#login_required
def show_price():
# https://www.makeuseof.com/tag/python-javascript-communicate-json/
data = request.get_json()
if data[1].isdigit() == True:
data = jsonify() # the data
return data
else:
return ""
and using fetch() in my javascript:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input id="symbols">
</div>
<div class="mb-3">
<input id="shares">
</div>
<h2 id="render">
</h2>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<script>
let input1 = document.getElementById('symbols');
let input = document.getElementById('shares');
input.addEventListener('keyup', function(event) {
value = [
input1.value, input.value
]
fetch("http://127.0.0.1:5000/show_price",
{
method: 'POST',
headers: {
'Content-type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(value)}).then(res =>{
if(res.ok){
return res.json()
} else {
document.querySelector('h2').innerHTML = "Keep typing...";
}
}).then(jsonResponse=>{
word = "That would be " + jsonResponse
document.querySelector('h2').innerHTML = word;
})
.catch((err) => console.error(err));
});
</script>
{% endblock %}
so as the user is typing in the the shares field the event listener will get the symbols and shares fields, use fetch() to get the data over to def show_price() with a jsonified array of symbol and shares. If there is an error the div id="render" will display "Keep typing". After python gets the information it will look it up using a function, then it will return the price of the shares in json format. Then javascript will get the data and use some javascript to change the html.
TL;DR
Basically I used fetch() to get the data to python, did some algorithm stuff and python return it to javascript. https://www.makeuseof.com/tag/python-javascript-communicate-json/ is really useful in teaching you how to use fetch().
im trying to send requests without refreshing the pae using ajax requests.
Watching the google event listerner when i i click the submit button my script is not begin called.
script.js
$("#new_app_b").click(function(event) {
//prevent submit
event.preventDefault();
//do things on submit
$.ajax({
data : {
data_app : $('#data_app').val(),
time_app : $('#time_app').val(),
id : $('#id').val()
},
type: "POST",
url: "/update",
beforeSend: function(){
//before send data
},
success: function(data){
// the data
console.log(data);
}
});
});
in layout.html i call this in the
in page html the part with the form is like this it has the {% extends 'layout.html' %} and the form is the the blockcontent and is begin displayed correctly it has 300+ lines so i wont post it all.
<form action="/update" method='POST' id="new_app">
<input name="id" id="id" type="hidden" value="{{ pratica[0][1] }}">
</input>
{% for cell in pratica %}
{% if cell[0] == 'data_app' %}
<td><input name="data_app" id="data_int" class="form-control form-control-sm"
type="text" value="{{ cell[1] }}"/></td>
{% elif cell[0] == 'time_app' %}
<td><input name="time_app" id="ora_app" class="form-control form-control-sm"
type="text" value="{{ cell[1] }}"/></td>
{% endif %}
{% endfor %}
<td>
<button id="new_app_b" type="submit" class="btn btn-success">
<i class="fa fa-check"></i>
</button>
</td>
</form>
while the /update controller is just like:
#app.route("/update", methods=['GET','POST'])
def update():
print("request: ")
print("id: " + request.form['id_pratica'])
print("data_app: " + request.form['data_app'])
print("time_app: " + request.form['time_app'])
return ''
So ive found the solution and this is what i did:
I moved the into the child template, using a block block like so:
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="{{ url_for('static',filename='js/script.js') }}"></script>
{% endblock %}
and put that block on top of the content block, and then i call the block in the layout.html file like so
{% block scripts %}{% endblock %}
in the tag, and now is begin loaded and called when it needs to.
Hi I am trying to create a printable page from data send by a form in octobercms
I have created a plugin component which I have called PrintPageForm
<?php namespace Acme\PrintPage\Components;
use Cms\Classes\ComponentBase;
use Input;
class PrintPageForm extends ComponentBase
{
public function componentDetails()
{
// TODO: Implement componentDetails() method.
return
[
'name' => 'Print Page Form',
'description' => 'Detail page print form'
];
}
public function onHandleForm()
{
$var =
[
'overview' => Input::get('print_overview'),
'photos' => Input::get('print_photos')
];
I have this in the default htm file
<form action="/print" data-request-data="printpageform::onHandleForm" data-request-validate data-request-flash accept-charset="utf-8" class="form ajax-form">
<h3 class="sub-heading">Print Details</h3>
<p>To build a printer friendly formatted page, please select from the options shown below:</p>
<ul class="print-section">
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_overview" id="print_overview">
<label class="checkbox-label period" for="print_overview">Overview: Summary and key features alongside a photo of the property.</label>
</li>
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_photos" id="print_photos">
<label class="checkbox-label period" for="print_photos">Photos: Photo gallery of the property.</label>
</li>
</ul>
<input type="hidden" name="print" value="1">
<button class="btn button-large one-third palm-one-whole" type="submit" rel="print" >Print</button>
</form>
I am trying to access the value of print_overview and print_photo values in my print view page but can not figure out how to access these values I can see these values being passed in Debugbar as follows "request_query
array:2 [ "print_overview" => "1" "print" => "1" ]" and in my view file I have
{%if "print_overview" == "1" %}
{{ 'checked' }}
{% else %}
{{ 'Not Checked' }}
{% endif %}
but it does seem to matter what the value of print_overview is the page only echos out Not Checked I'm in a rut that I can't figure out any thoughts would be gratefully accepted.
Couple of pointers. When rendering a form in Twig, you should use either the {{ form_open() }} or {{ form_ajax() }} tags
Secondly, you can access the request data via the post() function in your component class; and you pass it to your view (the component partial) through the page property. So, your handler would like something like:
public function onHandleForm()
{
// Pass the variables to the view renderer
$this->page['print_overview'] = (bool) post('print_overview');
$this->page['print'] = (bool) post('print');
// Return a partial response http://octobercms.com/docs/ajax/update-partials#pushing-updates
return ['#view-response-element' => $this->makePartial('#response')];
}
While your response.htm partial file would look something like this:
{% if print_overview %}
"checked"
{% else %}
"not checked"
{% endif %}
As a note, if you are using the {% macro %} tags, these do not have access to the local scope of the partial file, i.e. they do not have access to the variables provided to the view. Any evaluation done within {% macro %} tags needs to be based on variables passed to it.
The best strategy for printing I find is to use JavaScript:
<!-- Link to print -->
<p>Print this invoice</p>
<!-- Invoice printer -->
<script type="text/template" id="invoiceTemplateContents">
Printable contents go in here
</script>
<!-- Script -->
<script>
function printInvoice() {
var printWindow = window.open('','','left=0,top=0,width=950,height=500,toolbar=0,scrollbars=0,status=0')
printWindow.document.write($('#invoiceTemplateContents').html())
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
}
</script>
I'm trying to replace a 'reply' button with a form in my Django app.
Here's my Javascript code:
$(document).on('click', '.comment-reply-link', function(e) {
$(this).replaceWith("<form method='post'>{% csrf_token %}<div class='form-group'><label for='comment'>Comment:</label><textarea class='form-control' id='comment' rows='5' maxlength='300' minlength='1' name='comment' placeholder='Tell us how you loved this product :D'></textarea></div><button type='submit' name='post_comment' value='True'>Comment</button></form>");});
// The replacing line should contain no whitespace.
// Otherwise it will raise Uncaught SyntaxError: Unexpected token ILLEGAL
I get the form element but the problem is that {% csrf_token %} is processed as just unicode in replaceWith(). {% csrf_token %} is necessary in Django to submit a form. Any kind of help and advice will be thankful :)
Edit:
I assume that {% %} means that Django needs to be involved to retrieve the right value. So I thought I should render an html page with form and update that form with 'reply' button. Here's my logic.
view.html
<div class="reply">
<a class='comment-reply-link' href='{% url "rango:reply_form" %}'aria-label='Reply to Araujo'>Reply</a>
</div>
reply.js
function ajax_get_update(item){
$.get(url, function(results){
//get the parts of the result you want to update. Just select the needed parts of the response
// var reply_form = $("#reply_form", results);
var reply_form = $(".head", results);
console.log(reply_form);
//console.log(results);
//update the ajax_table_result with the return value
$(item).html(reply_form);
}, "html");
}
$(document).on('click', '.reply', function(e) {
console.log("Debuggin...");
e.preventDefault();
url = ($( '.comment-reply-link' )[0].href);
console.log(url);
ajax_get_update(this);
});
reply_form.html
<!DOCTYPE html>
... code omitted ....
<form id="reply_form" method="post">
{% csrf_token %}
<div class="form-group">
<label for="comment">Reply:</label>
<textarea class="form-control" id="comment" rows="5" maxlength="300" minlength="1" name="comment" placeholder="Tell us how you loved this product :D"></textarea>
</div>
<button type="submit" name="post_comment" value="True">Reply</button>
</form>
</body>
</html>
When I click the reply button, the button disappears but nothing updates. The html page variable results gets the correct html page data but it seems like
$(item).html(reply_form);
is not working right. Because when I do
$(item).html('<p>button disappears</p>');
the paragraph will appear. Any thoughts?
To use django template language in javascript you should encapsulate your code in a Verbatim tag.
example :
{% verbatim %}
var hello = {% if some_condition %} 'World' {% else %} 'foobar' {% endif %};
{% endverbatim %}
From the docs :
Stops the template engine from rendering the contents of this block tag.
A common use is to allow a JavaScript template layer that collides with Django’s syntax
In your case :
<script>
{% verbatim %}
$(document).on('click', '.comment-reply-link', function(e) {
$(this).replaceWith("<form method='post'> {% csrf_token %} </form>")
};
{% endverbatim %}
</script>
I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?
A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()