Modal popup to delete object in django - javascript

I am using django generic DeleteView() for deleting object from my database. The deleteview is working fine. But I want a alert message before deleting the object.
I have a ListView for showing the objects list in a table. In that table i have a trash icon, when user presses the trash icon it redirects to delete url and deletes the object. But i dont want to go a different page for my deletion instead I want to stay on that list page and want a popup alert message if i want to delete the object. if i click the yes button it deletes the object staying on that page and refreshes the list table.
I have tried several codes for this.
<button action="{% url 'employee:employee-delete' employee.id %}" type="button" name="button" class="btn btn-dnager" onclick="document.getElementById('deleteEmployee').style.display='block'">
<span data-feather="trash"></span>
</button>
<div id="deleteEmployee" class="modal">
<span onclick="document.getElementById('deleteEmployee').style.display='none'" class="close" title="Close Modal">×</span>
<div class="modal-content">
<h1>Delete Account</h1>
<p>Are you sure you want to delete your account?</p>
</div>
{% block footer%}
{% include 'employee/employee_delete.html' %}
{% endblock footer %}
</div>
currently I have above code for popup message and trash icon. when the icon is clicked a modal opens.
employee_delete.html:
<!DOCTYPE html>
{% load static %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
</head>
<body>
{% block footer%}
<form id="deleteForm" action="" method="post">
{% csrf_token %}
<div class="clearfix">
<button type="button" onclick="document.getElementById('deleteEmployee').style.display='none'" class="cancelbtn">Cancel</button>
<button type="submit" action="" onclick="document.getElementById('deleteForm').submit();" class="deletebtn">Delete</button>
</div>
</form>
{% endblock footer%}
</body>
</html>
above code is for my delete form. Everything is fine but when I click delete button nothing happens, doesnt delete the object and gives Method Not Allowed (POST) this error.
views.py:
class EmployeeDeleteView(DeleteView):
"""
Deletes a created employee
"""
template_name = 'employee/employee_delete.html'
context_object_name = 'employees'
model = Employee
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Employee, id=id_)
def post(self, request, *args, **kwargs):
employee = self.get_object()
#print(employee.errors)
return render(request, 'employee/employee_delete.html', {'employee': employee})
def get_success_url(self):
return reverse('employee:employee-list')

Related

Error: Cannot read properties of null reading "checked"

I'm having trouble fully wiring on my Django applications submit button, it seems that the JS function does not understand which checked boxes to look for
all the console returns are "cannot read properties of null, reading "checked" I'm assuming its something with the function defining but I cannot seem to get it working
Heres the code:
<html>
<head>
{% load static%}
{% block content%}
<link rel="shortcut icon" type="image/png" href="{% static 'IMG/favicon.ico' %}"/>
<link rel="stylesheet" href="{% static 'CSS/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'CSS/jquery-ui.css' %}">
<script type="text/javascript" src="{% static 'JS/bootstrap.min.js' %}"></script>
<title>Task List</title>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="{% static 'JS/jquery-ui.min.js' %}"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
let _csrf = '{{csrf_token}}';
function submit_delete() {
var listItems = $("#list li input");
var checkedListItems = [];
listItems.each(function() {
if (document.getElementById(this.id).checked) {
checkedListItems.push(getTaskId(this.id));
console.log(checkedListItems);
}
})
$.ajax({
headers: { "X-CSRFToken": _csrf },
type: "POST",
url: "/ptm/item_delete",
data: {
'deleteList[]': checkedListItems
}
}).done(location.reload());
}
function getTaskId(str) {
return str.split('-')[1];
}
</script>
</head>
<body>
<div id="logo" class="border-success border border-3 rounded-2" style="width: 61.rem;">
<div class="card-body">
<img class="card-img" src="{% static '/IMG/Logo.png' %}">
</div>
</div>
<div id="taskList" class="card">
{% if task_list %}
<ul class="list-group" id="list">
{% for item in task_list %}
<li class="list-group-item" id='tdList'>
<input id="check-{{ item.id }}" type="checkbox" class="form-check-input me-1" value="">
<label class='d-flex w-100 justify-content-between'>
<h2 class="form-check-label" for="check-{{ item.id }}">{{ item.title }}</h2>
<small class='text-muted'>{{ item.date }}</small>
<input size='3'>
</label>
<h5 class="form-check-label">{{ item.description }}</h5>
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no current tasks assigned to this department.</p>
{% endif %}
</div>
{% csrf_token %}
<div id="taskEnter" class="card-footer">
<div class="d-grid mx-auto">
{% if task_list %}
<button type="button" onclick="submit_delete()" value='delete' class="btn btn-success btn-lg d-grid" value='delete'><i class="">Submit</i></button>
{% endif %}
</div>
</div>
</body>
{% endblock %}
</html>
In the part:
document.getElementById(this.id).checked
document.getElementById(this.id) evaluates to null, which doesn't have any properties, hence the exception you're getting. You're effectively doing null.checked which won't work.
It looks like you're trying to iterate over the checkboxes and determine whether they're checked or not. I'm reasonably confident that this inside the function you wrote will just refer to the window object, so calling this.id won't give you a checkbox id. You have actually already fetched all of the checkboxes (you're iterating over them!) so there's no need to refetch each one manually. Just do:
listItems.each(function(listItem) {
if (listItem.checked) {
checkedListItems.push(getTaskId(listItem.id));
console.log(checkedListItems);
}
})
Note that the function takes as argument the individual listItem (confusingly named since they're actually checkboxes but I'm following your nomenclature here) that each is currently iterating over. Which is what you need.
Try adding a child combinator ('>') to the element selector used in the first line of function submit_delete:
var listItems = $("#list li > input");
- or use a more precise selector of your own devisement.
As posted there appear to be descendant input elements of .list li of form <input size='3'> that don't have an id attribute. Processing these in each returns null from getElementById and throws the error that checked can't be a property of null.
About each
JAuery's each function fires its callback with a this value set to the element being processed during the iteration. The element is also provided to the callback as its second argument. Given elements in HTML should have unique id values:
For elements referred to by this that have id values, using this for the element is simpler than calling getElementById(this.id).
For elements (referred to by this) that do not have an id, !this.id) is a simpler conditional expression than getElementById(this.id)===null.
Filtering out elements that should not be mnatched during selection is preferable to filtering them out later.

Is there any way to have my html page refresh/reload itself after a function in the django view.py tab completes?

I want to have my page refresh itself after a successful download of a zip file since successive attempts to click the submit button result in an error, and the only way to remedy it fairly easily is to manually refresh/reload the page. I was wondering if there is a way to set it up so that once the zip is completed the page will refresh itself without the user having to worry about it. Doing it this way also kills two birds with one stone, since I want to disable the submit button to prevent users from spamming it, but if I end up having the page refresh I could just out right remove it after it's clicked.
Here is my HTML code:
{% load static %}
<html>
<head>
<link rel="stylesheet" href="{% static '/styleSheet.css' %}">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edstore">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--BOOTSTRAP ASSETS-->
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght#400;700&display=swap" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<div class="main_Body">
<div class="section">
<h1>Fileconverter</h1>
<br>
<label for="file_field" class="custom-file-upload">
<i class="fa fa-cloud-upload"></i>Updload File(s)</label>
<input type="FILE" id="file_field" name="file_field" class="file-upload_button" multiple>
<label id="file_name"></label>
<br>
<br><br><br>
<br>
<button type="submit" class="file-submit__button" onclick="formDisableButton()" id="submitButton">Testing</button> <!--onclick="formDisableButton"-->
</div>
</form>
</body>
<footer>
<p>Click "Choose File(s)" and select the files you want to convert.</p>
<p>Once you click "Submit" the job will start.</p>
<p>Upon completion, a zip folder will be downloaded in your browser.</p>
<p>Do not click the submit buttons multiple times. If the tab is loading, the job is being processed.</p>
</footer>
</html>
<script>
document.querySelector("#file_field").onchange = function(){
document.querySelector("#file_name").textContent = this.files[0].name;
}
const tempButton = document.getElementById("submitButton");
function formDisableButton(){
// tempButton.disabled = true;
// setTimeout(formEnableButton, 10000);
location.reload();
}
function formEnableButton(){
tempButton.disabled = false;
}
/*setTimeout(()=>{
btn.disabled = false;
console.log('Button Activated')
}, 10000)*/
/* $(function(){
$("#submitButton").click(function(){
$("#submitButton").attr("disabled", "disabled");
setTimeout(function(){
$("#submitButton").removeAttr("disabled");
}, 10000)
});
});*/
</script>
And here is the views.py file:
from django.shortcuts import render
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic.edit import FormView
from django.views.decorators.csrf import csrf_exempt
from .forms import FileFieldForm
from django.http import HttpResponse
from .perform_conversion import FileConverter
import zipfile
import io
def FileFieldFormView(request, *args, **kwargs):
form = FileFieldForm(request.POST)
files = request.FILES.getlist('file_field')
if request.method == 'POST':
form = FileFieldForm(request.POST, request.FILES)
if form.is_valid():
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", False) as zip_file:
for f in files:
fileconverter = FileConverter(f.name)
fileconverter.run(f.file)
for img_name, img in fileconverter.output.items():
data = io.BytesIO(img)
zip_file.writestr(img_name, data.getvalue())
# Set the return value of the HttpResponse
response = HttpResponse(zip_buffer.getvalue(), content_type='application/octet-stream')
# Set the HTTP header for sending to browser
response['Content-Disposition'] = "attachment; filename=%s" % 'zip.zip'
response.set_signed_cookie('csrftoken', request.COOKIES['csrftoken'])
# Return the response value
return response
else:
return HttpResponse('Form Invalid')
else:
return render(request, 'pages/file_converter.html')
Based on what I've seen after doing digging before asking this question, Ajax seems to be the right direction for things, but I have no experience with it and everything I find online doesn't seem to apply to the type of question I'm asking. Also the onclick for the submit button doesn't work, but that's not a main problem right now. TBH any help would be massively appreciated!
Use javascript onclick to change the button class from class="file-submit__button" to something like class="file-submit__button-disabled", and of course add the corresponding css.

How can I get my html page to refresh upon completion of a django function?

I keep getting an error related to the csrf token when I try to employ consecutive submissions, and refreshing the page seems to work. The purpose of the program is to create zip files, so I figured the easiest solution would be to have the web page automatically reloaded once the zip file is done being created from the function in the views.py file and available for the user to open. The main issue I'm having is how to actually do that.
Here is the code for my HTML file:
{% load static %}
<html>
<head>
<link rel="stylesheet" href="{% static '/styleSheet.css' %}">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edstore">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--BOOTSTRAP ASSETS-->
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght#400;700&display=swap" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<div class="main_Body">
<div class="section">
<h1>Fileconverter</h1>
<br>
<label for="file_field" class="custom-file-upload">
<i class="fa fa-cloud-upload"></i>Updload File(s)</label>
<input type="FILE" id="file_field" name="file_field" class="file-upload_button" multiple>
<label id="file_name"></label>
<br>
<br><br><br>
<br>
<input type="submit" class="file-submit__button" id="submitButton"> <!--onclick="formDisableButton"-->
</div>
</form>
</body>
<footer>
<p>Click "Choose File(s)" and select the files you want to convert.</p>
<p>Once you click "Submit" the job will start.</p>
<p>Upon completion, a zip folder will be downloaded in your browser.</p>
<p>Do not click the submit buttons multiple times. If the tab is loading, the job is being processed.</p>
</footer>
</html>
<script>
document.querySelector("#file_field").onchange = function(){
document.querySelector("#file_name").textContent = this.files[0].name;
}
const tempButton = document.getElementById("submitButton");
function formDisableButton(){
tempButton.disabled = true;
setTimeout(formEnableButton, 10000);
}
function formEnableButton(){
tempButton.disabled = false;
}
/*setTimeout(()=>{
btn.disabled = false;
console.log('Button Activated')
}, 10000)*/
/* $(function(){
$("#submitButton").click(function(){
$("#submitButton").attr("disabled", "disabled");
setTimeout(function(){
$("#submitButton").removeAttr("disabled");
}, 10000)
});
});*/
And this is the code from my views.py file:
from django.shortcuts import render
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic.edit import FormView
from django.views.decorators.csrf import csrf_exempt
from .forms import FileFieldForm
from django.http import HttpResponse
from .perform_conversion import FileConverter
import zipfile
import io
def FileFieldFormView(request, *args, **kwargs):
form = FileFieldForm(request.POST)
files = request.FILES.getlist('file_field')
if request.method == 'POST':
print(request)
form = FileFieldForm(request.POST, request.FILES)
if form.is_valid():
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", False) as zip_file:
for f in files:
fileconverter = FileConverter(f.name)
fileconverter.run(f.file)
for img_name, img in fileconverter.output.items():
data = io.BytesIO(img)
zip_file.writestr(img_name, data.getvalue())
# Set the return value of the HttpResponse
response = HttpResponse(zip_buffer.getvalue(), content_type='application/octet-stream')
# Set the HTTP header for sending to browser
response['Content-Disposition'] = "attachment; filename=%s" % 'zip.zip'
response.set_signed_cookie('csrftoken', request.COOKIES['csrftoken'])
# Return the response value
return response
else:
return HttpResponse('Form Invalid')
else:
return render(request, 'file_converter.html')
As a bonus if you're willing to provide a bit of extra help, I can't ever seem to have any sort of onclick for my submission button. Every time I try to add it, the python files never actually end up running and the page just sits there. I'd like to have it so that when the submission button is clicked it is removed form the page to prevent excessive submission attempts and since, in theory, the page will be refreshing after a successful run through, the submit button will just be reposted onto the page.

Add href in OnClick attribute in html form

I want to redirect to the python flask route home after showing the alert window.
<input type="submit" value="Register" onclick="call(); log();"></input>
Here are both functions.
<script>
function call()
{
window.alert("Congragulations! You Registerd Sucessfully ");
}
</script>
<script>
function log()
{
<a href="/home" > </a>
}
</script>
If I understood your project correctly, you want to forward the user after he has registered. At the same time, a message should appear that the process was successfully completed.
I think your javascript approach is not sufficient for this, since the data must first be sent from the client to the server so that the process is complete. Here the inputs should also be validated and will likely be processed or stored in some way.
I have written a small example for you, which accepts form data and checks it. If the verification is successful, the user is redirected and a message appears. To forward and display the message I use redirect and flash from the flask package.
Python Flask
import re
from flask import Flask
from flask import (
flash,
redirect,
render_template,
request,
session,
url_for
)
app = Flask(__name__)
app.secret_key = b'your secret here'
#app.route('/')
def home():
return render_template('index.html')
#app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
if username and re.match(r'^[a-z0-9\_\-]+$', username, re.IGNORECASE):
session['username'] = username
flash('Congragulations! You Registerd Sucessfully.')
return redirect(url_for('home'))
return render_template('register.html')
HTML (index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<nav>
<ul style="list-style: none;">
<li>Register</li>
</ul>
</nav>
{% with messages = get_flashed_messages() -%}
{% if messages -%}
<ul class="flashes">
{% for message in messages -%}
<li>{{ message }}</li>
{% endfor -%}
</ul>
{% endif -%}
{% endwith -%}
<h1>Welcome {{ session.get('username', 'Guest') }}!</h1>
</body>
</html>
HTML (register.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Register</title>
</head>
<body>
<form method="post">
<div>
<label for="username">Username</label>
<input type="text" name="username" id="username" />
</div>
<input type="submit" value="Register" />
</form>
</body>
</html>

Django, calendar widget doesn't work with ModelForm and Form Media

I found one blog. It explains how apply calendar widget with form media. It is what I exactly want to make. so I followed instructions.
But js and css files doesn't work in widget. I tried to figure out this problem. I spent quite much time by searching and reading stuffs. But I can't get what's wrong in my situation exactly. Well, It could be very easy question but I will appreciate if you can give me any hint to figure out this!
model.py
class Birthday(models.Model):
birthday = models.DateField(null=True)
views.py
def register_birthday(request):
if request.method == 'POST':
form = BirthdayForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/success')
else:
form = BirthdayForm()
return render(request, 'sale/registerbirthday.html', {'form':form})
forms.py
class DateUIWidget(forms.TextInput):
def _media(self):
return forms.Media(css = {
"all": ("tiny-date-picker.css",)
},
js = ("tiny-date-picker.js", "date-init.js",))
media = property(_media)
class BirthdayForm(forms.ModelForm):
class Meta:
model = Birthday
fields = ('birthday',)
widgets = {
"birthday" : DateUIWidget(attrs={'class':'dateuiwidget', 'id':'id_birthday'}),
}
actually I wrote at first like below. but I changed to check if it works when I use media as a dynamic property.
class DateUIWidget(forms.TextInput):
class Media:
css = {
"all": ("tiny-date-picker.css",)
}
js = ("tiny-date-picker.js", "date-init.js",)
forms.py first
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
{{ form.medai}}
I changed it because I read that I should read this when I changed.
As we have already seen, the string representation of a Media object is the HTML required to include the relevant files in the <head> block of your HTML page.
<html>
<head>
{{ form.media }}
</head>
<body>
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
</body>
</html>
under myapp/static/date-init.js
$(".dateuiwidget").each(function(){
return TinyDatePicker(this);
});
I copied two files(tiny-date-picker.js,tiny-date-picker.css) under myapp/static/.
I got two files from here
it shows widget in a form without error. I assume that somehow js, css file didn't apply to this widget.
html source code
<html>
<head>
<link href="/static/tiny-date-picker.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/static/tiny-date-picker.js"></script>
<script type="text/javascript" src="/static/date-init.js"></script>
</head>
<body>
<form action="." method="post">
<input type='hidden' name='csrfmiddlewaretoken' value='VC8ahwDLBOsy4IlAzf1iIiukK7ZvTcGDQjL9RxywlauCOX3c8rG7DVJ1ClozHEEW' />
<p><label for="id_birthday">Birthday:</label> <input class="dateuiwidget" id="id_birthday" name="birthday" type="text" required /></p>
<input type="submit">
</form>
</body>
</html>

Categories

Resources