I'm working on a website on which users can comment something below the posts, running on Python & Django.
As soon as a user comments something, then I'm updating comments without refreshing the web-page. Here's the code,
In views.py
postType1 = sorted(Posts.objects.filter( . . . ), key=lambda x: random.random())
postType2= Posts.objects.filter( . . . )
In template,
// BLOCK - 1
{% for post in postType1 %}
<p>{{ post }}</p>
<div class="comm_update" action="{% url 'comment:create' post.id %}">
<form class="comm_form" action="{% url 'comment:create' post.id %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<textarea id="id_comment"></textarea><br /><br />
<button type="submit">Submit</button>
</form>
</div>
{% endfor %}
<hr />
// BLOCK - 2
{% for post in postType2 %}
<p>{{ post }}</p>
<div class="comm_update" action="{% url 'comment:create' post.id %}">
<form class="comm_form" action="{% url 'comment:create' post.id %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<textarea name="comment_text" id="id_comment"></textarea><br />
<button type="submit">Submit</button>
</form>
</div>
{% endfor %}
Auto updating comments without refreshing webpage,
$(document).on("submit", ".comm_form", function(t) {
t.preventDefault();
var o = $(this),
e = $.post(o.attr("action"), o.serialize()),
n = o.attr("action");
e.done(function(t) {
var e = $(t).find(".comm_update[action='" + n + "']");
o.closest(".comm_update").html(e), o[0].reset()
})
});
On localhost everything is working fine.
*But on live server the first block BLOCK - 1 is not updating the comments, instead when user presses submit entire comment section disappears.
How can we fix this issue?
Thank You!
Related
DOM is driving me crazy! I did everything right but still not working. I am trying to validate form in Jinja via DOM or Javascript using innerHTML before submitting the form in flask. I know I am doing the right thing but the div doesn't change. I need your help guys. What am I doing wrong ?
{% extends "layout.html" %}
{% block content %}
<form action="" method="post" enctype="multipart/form-data" class="form">
<fieldset>
<legend> <h5>{{ legend }} </h5></legend>
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.course_name.label(for="name") }}<br>
{% if form.course_name.errors %}
{% for error in form.course_name.errors %}
{{ form.course_name(size=100, class="form-control", id="name", placeholder="Enter course name") }}<br>
<span style="color: red;">{{ error }}</span>
<h1 id="nameeee" style="color: red;"></h1>
{% endfor %}
{% else %}
{{ form.course_name(size=100, class="form-control", id="name", placeholder="Enter course name") }}<br>
{% endif %}
</div>
<p>
{{ form.submit(class="btn btn-primary", id="submit") }}
</p>
</form>
<script type="text/javascript">
const name_course = document.getElementById('name');
const submit = document.getElementById('submit');
const name = document.getElementById('nameeee')
submit.addEventListener('click', () =>{
if (name_course.value.length < 1){
name.textContent = "Name must not be empty";
alert(name_course.value.length);
};
});
</script>
{% endblock %}
Not sure on what you mean by right thing but the div doesn't change. Please expand on this in the comments if the proposed solution below doesn't solve the problem.
I believe in this case the jinja HTML render
{{ form.submit(class="btn btn-primary", id="submit") }}
does not achieve the purpose of submitting the form to the back-end. It's is not equivalent to having a submit button, as so
<button type="submit"> Send </button>
that performs the method and action set on your opening form tag. Try with this <p>{{ form.submit() }}</p> and see if it solves the problem.
It did not work because the h1 was placed inside the loop. So I had to take the h1 out of the loop.
<h1 id="nameeee" style="color: red;"></h1>
I have a function that currently runs whenever the user clicks/tabs out of the employee_number field. I would like it to run whenever the length of the numbers entered is equal to 6, without having to leave the field, since when I try using the tab, it conflicts with loading the next field which is a drop-down that is part of the function ran.
I tried by running it using .change and putting the constraint within the function, but it did not work and I don't know what else to try.
enter_exit.html
{% extends "base.html" %}
{% load core_tags staticfiles %}
{% block main %}
<form id="warehouseForm" action="" method="POST" data-employee-activity-lookup-url="{% url 'operations:employee_activity_search' %}" novalidate >
{% csrf_token %}
<div>
<div>
<div id="employee-name" style="margin-bottom: 10px"> </div>
<label>Employee #</label>
{{ form.employee_number }}
</div>
<div=>
<label>Work Area</label>
{{ form.work_area }}
</div>
<div style="display: none" id="my-hidden-div">
<label>Station</label>
{{ form.station_number }}
</div>
</div>
<div>
<div>
<button>Enter Area</button>
<button>Exit Area</button>
</div>
</div>
</form>
<script>
// Grab the employee name and their current active work log (if any)
$(document).on('blur', "#{{ form.employee_number.id_for_label }}", function(){
var url = $("#warehouseForm").attr('data-employee-activity-lookup-url');
var employeeId = $(this).val();
# ... more fields ...
if (employeeId !== "") {
# .. Rest of function ...
})
</script>
{% endblock main %}
Instead of using on blur have you tried using .keyup or .keydown?
Here's a simple version of it working in CodePen:
$("#test1").keydown(()=>{
if($("#test1").val().length>6)
console.log('6+');
})
https://codepen.io/orunnals/pen/JjoRGLX
I have a webapp build in Python 2.6 and Django.
I am trying to send parameters to the HTML page but it seems that the HTML page is refreshing to the default values all the time.
Meaning i can see that movetobi is being called but it looks like the moment movebi return the value the page is reloaded again
View.py
def adminoperation(request):
return render(request,'app/adminoperation.html',{'some_flag':'999999'})
def movetobi(request):
if 'check' in request.POST and request.POST.get('check'):
data= {'newtest':3}
return JsonResponse(data, safe=False)
adminoperation.html
{% extends "app/layout.html" %}
{% block content %}
<p>Adminstration site for FTMS 2017</p>
<h2> {{mssg}}</h2>
<p>{{ mssg2 }} </p>
<p>{{ mssg3 }} </p>
<form id="data_form" method="post" enctype="multipart/form-data">
{% csrf_token %}
<button id="run_reports" type="submit" name="action" value="commit">Run Reports For BI</button>
<br> <br>
<button id="Rollback" type="submit" name="action"
value="commit">Rollback</button>
input type="hidden" id="commitok" name="commitok" value="{{ some_flag }}" />
</form>
{% endblock %}
{% block scripts %}
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css">
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<script>
$(function () {
$('#run_reports').click(function () {
$.ajax({
type: "POST",
url: 'movetobi',
data: {
'check' : '1',
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success: function (data){
if (data['newtest']==3) {
confirm("You are trying to run a month that allready exist");
}},
error: function(data){
if (data['newtest']==5) {
confirm("test");
}}
});
});
});
</script>
{% endblock %}
$('#run_reports').click(func) will not prevent the form from being submitted directly by the browser. You have to get the click event and call preventDefault() on it:
$('#run_reports').click(function(evt) {
evt.preventDefault();
# your code here
})
I've built dynamic forms using django formsets and javascript, but unfortunately on submitting the form only the first form is submitted. I'd like all dynamically added forms to be submitted also. Any help would be appreciated.
Views:
def routestepinfo(request):
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
RouteStepFormSet = formset_factory(RouteStepForm, formset=RequiredFormSet, extra=1, can_order=False, can_delete=True)
if request.method == 'POST':
formset = RouteStepFormSet(request.POST)
if formset.is_valid():
for form in formset.forms:
form.save()
print 'apple'
return redirect("/buildpage/")
else:
formset = RouteStepFormSet()
return render(request, "buildpage/routestepinfo.html", {'formset' :formset})
HTML
<form id= "myForm" method = 'POST' action="{% url 'buildpage:routestepinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{ formset.management_form }}
<div id="form_set">
{% for form in formset %}
<table class='no_error'>
<tbody>.
{{form.as_table}}
</tbody>
</table>
{% endfor %}
</div>
<p><input type = "button" value = "Add another step" id = "add_more" ></p>
<div id="empty_form" style="display:none">
<table class='no_error'>
{{ formset.empty_form.as_table }}
</table>
</div>
<div id="forms"></div>
<p> </p>
<p> </p>
<input type = "submit" name = "Submit Steps">
</form>
JS Clone:
<script>
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
Fixed it ! Only took a week. Here's how it worked eventually. Views are largely unmodified, just added commit=False to save the list.
def routestepinfo(request, slug=None):
RouteStepFormSet = formset_factory(RouteStepForm, formset = RequiredFormSet, extra=1)
if request.method == 'POST':
formset = RouteStepFormSet(request.POST)
print formset
if formset.is_valid():
for form in formset.forms:
form_item = form.save(commit=False)
print form
form_item.save()
messages.success(request, "Record created")
return redirect ("/buildpage/")
else:
formset = RouteStepFormSet()
return render(request, "buildpage/routestepinfo.html",{'formset':formset})
Javascript was the main thing that changed, with quite a few additions and quite a bit of SO help. The prefix was the first issue, and that was fixed by using formset.empty_form and modifying it from there. Another vital part was updating the total forms, which fixed the saving issue.
<script>
$(document).ready(function() {
$('.add-item').click(function(ev) {
ev.preventDefault();
var count = $('#items-form-container').children().length;
var tmplMarkup = $('#item-template').html();
var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
$('div#items-form-container').append(compiledTmpl);
// update form count
$('#id_form-TOTAL_FORMS').attr('value', count+1);
$('html, body').animate({
scrollTop: $("#add-item-button").position().top-200
}, 800);
});
});
</script>
Finally the html. This combined some of my own stuff with a very helpful SO post(forgot the question it came from), where formset is generated as an empty form and cloned from there.:
<div type="text/html" id="item-template">
<table>
{{ formset.empty_form.as_table }}
</table>
</div>
<font face = Flexo>
<form id= "myForm" method = 'POST' action="{% url 'buildpage:routestepinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{ formset.management_form }}
<div id="items-form-container">
{% for form in formset.forms %}
<div id="item-{{ forloop.counter0 }}">
<table>
{{form.as_table}}
<table>
</div>
{% endfor %}
</div>
Add Step
<input type = "submit" name = "Submit Steps">
</form>
Hope this helps some people. Cheers
I'm trying to create my first ajax function in Django.
I want to change my code using JQuery, the idea is pretty simple:
User type a subject name and this name is displayed in subject-list below the form,
The problem is I don't really know what to type in JQuery function.
JQuery:
function create_subject() {
$("input").focus(function(){
var subject = $(this).val();
$(".btn-create").click(function(){
/* What I need to write in here */
});
});
}
In HTML "subjects" refer to database.
HTML
<div id="subjects-list">
{% if user.username %}
<ul>
{% if subjects %}
<form method="post" action=".">{% csrf_token %}
{% for subject in subjects %}
-------- TYPED TEXT SHOULD BE HERE --------> <li>{{ subject.name }}</li>
{% endfor %}
</form>
{% else %}
<p>No Subjects for this user</p>
{% endif %}
</ul>
{% else %}
You are in else
{% endif %}
</div>
That's how HTML looks in "View Page Source"
<div id="create-subject">
<form method="post" action="."> <div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='cfbd1893742c3ab9936bacaae9653051' /></div>
<p><label for="id_name">Subject Name:</label> <input id="id_name" type="text" name="name" size="9" /></p>
<input type="button" name="subject-create-b" value="Create Subject" class="btn-create"/>
</form>
</div>
<div id="subjects-list">
<ul>
<form method="post" action="."><div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='cfbd1893742c3ab9936bacaae9653051' /></div>
<li>Math 140<span id="subject-link"></span></li>
</form>
</ul>
</div>
</div>
And that's my form
forms.py
class SubjectCreationForm(forms.Form):
name = forms.CharField(label="Subject Name", widget=forms.TextInput(attrs={'size':9}))
class Meta:
exclude = ('created_by', 'created_time', 'num_of_followers', 'vote')
def clean_name(self):
name = self.cleaned_data['name']
if len(name)>1:
return name
else:
raise forms.ValidationError("Subject name should be longer")
In order to do what (I think) you want to do which is some basic AJAX using Django as your backend, you'll need the following:
A view which returns the data you want to load
There are a number of ways you can represent the data, but to keep it simple, I'll use HTML.
Javascript to load that view (using JQuery if you like)
Your code might look like this for the first part:
urls.py:
...
(r'^get-subjects/$', 'yourapp.views.get_subjects'),
...
views.py:
...
def get_subjects(request):
subjects = # code to fetch your subjects.
return render_to_response('subjects_template.html', {'subjects': subjects})
...
subjects_template.html:
{% for subject in subjects %}
<li>{{ subject.name }}</li>
{% endfor %}
For the second part, it might look like this:
main_template.html:
...
<ul id="subjects-list"></ul>
<script>
function loadSubjects() {
$.ajax({
url: "/get-subjects",
success: function (data) {
$("#subjects-list").html(data);
}
});
}
</script>
...
[1] render_to_response()
[2] jQuery.ajax()
This will get you most the way there. When you want to reload the list, you call the loadSubjects() function.
As far as creating the subjects go, that is a different thing. What you'll want to look into is how to do an HTML form submission without leaving the page. There are plenty of tools and libraries to do that stuff with a nice api. If you want to stick with JQuery, you might consider this plugin for a nicer api.
function create_subject() {
$("input").focus(function(){
var subject = $(this).val();
$(".btn-create").click(function(){
$('#subjects-list').append(subject);
});
});
}
that said, you probably don't want to assign the click handler every time the input is focused. i'd move that out of the focus handler.