Reputation: 23
My problem is that I have a list of 'Assignment' objects which all have a field called 'status'. The status is either true or false, and the user can choose to change the value by clicking on a checkbox for a specific assignment.
This is what the frontend looks like, each assignment has a checkbox which is its 'status'
My current solution is this:
course-detail.html:
{% for assignment in assignments %}
<tr>
<td scope="row" style="text-align: center">
<form>
{% csrf_token %}
{% if assignment.status %}
<input type="checkbox" checked onclick='assignmentFinish("False","{{assignment.id}}")'>
{% else %}
<input type="checkbox" onclick='assignmentFinish("True","{{assignment.id}}")'>
{% endif %}
</form>
</td>
<td><h5><span class="badge badge-{{assignment.module.colour}}">{{assignment.module}}</span></td>
<td><a href="{{ assignment.assigmentFile.url }}">{{assignment.title}}</a></td>
<td>{{assignment.deadline}}</td>
...
</tr>
{% endfor %}
ajax code:
function assignmentFinish(value,assignment) {
link = "{% url 'uni:finish-assignment' %}";
$.ajax({
type:'POST',
url: link,
data:{
status: value,
assignmentID: assignment,
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success: function(){
}
});
}
views.py:
def finishAssignment(request):
# Get the product that user has wished for
assignmentID = request.POST['assignmentID']
status = request.POST['status']
assignment = Assignment.objects.get(pk=assignmentID)
print(status)
if status == 'True':
print("saving to true")
assignment.status = True
else:
print("saving to false")
assignment.status = False
assignment.save()
return HttpResponse('')
enter code here
models.py
class Assignment(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
course = models.ForeignKey(Course, on_delete=models.CASCADE, default=None)
module = models.ForeignKey(Module, on_delete=models.CASCADE)
deadline = models.DateField()
assignmentFile = models.FileField(default=None)
status = models.BooleanField()
This solution will work once, but once the user clicks the checkbox again, it will not save the information in the database. For example, if the user clicks a checkbox which is initially unchecked repeatedly, the print statements will be this:
True
saving to true
[15/Jul/2020 16:11:51] "POST /uni/finishAssignment HTTP/1.1" 200 0
True
saving to true
[15/Jul/2020 16:11:52] "POST /uni/finishAssignment HTTP/1.1" 200 0
True
saving to true
It shows that the ajax request is being called, but the print statements should be alternating between true and false. The reason for this is probably because the information on the page which displays the checkbox is not updated after the new values are saved in the database after the first time. How do I fix this?
Upvotes: 2
Views: 2535
Reputation: 7744
The problem reloves around how you've built this. I will give you constructive feedback on what's happening and a solution.
You mentioned
1.
For example, if the user clicks a checkbox which is initially unchecked repeatedly, the print statements will be this:
[15/Jul/2020 16:11:51] "POST /uni/finishAssignment HTTP/1.1" 200 0
True
saving to true
[15/Jul/2020 16:11:52] "POST /uni/finishAssignment HTTP/1.1" 200 0
True
saving to true
This is True
since this <input type="checkbox" onclick='assignmentFinish("True","{{assignment.id}}")'>
will invoke the ajax
request with the value of True
. In the views.py
it will execute the following block
if status == 'True':
print("saving to true")
assignment.status = True
So the behavior of its printing shown above is completely normal since this block will be repeatedly executed.
2.
but the print statements should be alternating between true and false. The reason for this is probably because the information on the page which displays the checkbox is not updated.
This is correct since you do not update the values of the checkbox anywhere and you always presume that values are definitively true
and false
.
Solution:
To get around this, you need to modify your js
function, such that it takes in the element
as the first parameter and assignment.id
as the second. Within that you need update the status
param by directly getting the value of the checkbox, using the checked property.
<td scope="row" style="text-align: center">
<form>
{% csrf_token %}
{% if assignment.status %}
<input type="checkbox" checked onclick='assignmentFinish(this,"{{assignment.id}}")'>
{% else %}
<input type="checkbox" onclick='assignmentFinish(this,"{{assignment.id}}")'>
{% endif %}
</form>
</td>
function assignmentFinish(element,assignment) {
link = "{% url 'uni:finish-assignment' %}";
$.ajax({
type:'POST',
url: link,
data:{
status: element.checked ,
assignmentID: assignment,
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success: function(){
}
});
}
Now you will be passing the actual value of the checkbox and it should behave the way you expect.
Upvotes: 1