I want to modify Django admin interface.
There is delete button already has a confirmation page. But I want to add this confirmation to save or change buttons. Actually not exactly the same delete button.
I want to change default admin buttons like this JS or I want to add JS to admin buttons.
<input type="submit" onclick="linkSubmit('http://www.google.com')" value="Submit">
<p id="demo"></p>
<script>
function linkSubmit(link) {
let text = "Press a button!\nEither OK or Cancel.";
if (confirm(text) == true) {
window.location.href = link;
} else {
}
document.getElementById("demo").innerHTML = text;
}
</script>
We found the solution in the files of the delete command. We took copies of the files confirm to the delete function and connected them to the confirm button.
We still can't give it as a alert. Gives confirmation on a another page.
Assuming there is already some type of event listener for the button I would add my own custom function as an additional listener for the on click event. Then I would put in my if(confirm) logic and call event.stopImmediatePropagation() as needed to prevent the original functionality from occuring.
Create templates/admin/change_form.html in your project:
{% extends "admin/change_form.html" %}
{% block admin_change_form_document_ready %}{{ block.super }}
<script id="django-admin-form-change-constants"
data-model-name="{{ opts.model_name }}">
let modelName = document.getElementById('django-admin-form-change-constants').dataset.modelName;
let form = document.getElementById(modelName + '_form');
form.addEventListener('submit', (event) => {
let text = "Press a button!\nEither OK or Cancel.";
if (!confirm(text)) {
event.preventDefault();
}
});
</script>
{% endblock %}
Set DIRS in myproject/settings.py to point to your project's templates directory:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
...
}
]
References:
https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#overriding-admin-templates
https://docs.djangoproject.com/en/4.1/howto/overriding-templates/#overriding-from-the-project-s-templates-directory
https://github.com/django/django/blob/4.1/django/contrib/admin/templates/admin/change_form.html#L66-L74
https://github.com/django/django/blob/4.1/django/contrib/admin/static/admin/js/change_form.js#L5
Related
I used Django to develop a web app.
In one page there's a form, once filled, a duplicate button should open a new tab of the page with the same data filled.
I already finished the new tab js function, but I do not know how to make the form in new tab filled with the data in previous tab(the same isbn filled in previous tab in my case).
<form>
<label> iSBN: </label> <input type="text" id="iSBN" name="iSBN"><br>
</form>
<button onclick="Duplicate()">Duplicate</button><br>
{% endblock %}
<script>
{% block script %}
function goBack() {
window.history.back();
}
function Duplicate(){
document.getElementById("demo").innerHTML = "Duplicate Copy for editing";
window.open(
'/new-content-checklist/',
'_blank' // <- This is what makes it open in a new window.
);
}
{% endblock %}
</script>
You can pass data from url parameters and in another tab you can then access url parameters and fill the form like this.
// const url = new URL(window.location);
const url = new URL('http://example.com/new-form.html?isbn=12345')
const previousData = url.searchParams.get('isbn')
console.log(previousData)
//output: 12345
A working demo code: jsFiddle
In short:
const data = new URL(window.location).searchParams.get('isbn')
Hey guys I'm creating a social media messaging app and right now I'm on the basics of creating a button to follow people.
When you click the button, it should change the button from saying "Follow" to "UnFollow". Then the counter for Followers should go up by 1.
So far this is my code and it's not doing anything. I'm not getting any errors but it's also not doing anything at all.
Can someone figure out what I'm doing wrong? Thanks
network.js:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('followButton').addEventListener('click', () => follow_user());
});
function follow_user() {
const element = document.getElementById('followButton');
element.value = "Un-Follow";
const element2 = document.getElementById('followers');
element2.textContent += 1;
}
profile.html :
{% extends "network/layout.html" %}
{% block body %}
<h2>{{user.username}}'s Profile</h2>
<p id="followers">Followers: {{user.followers}}</p>
<p>Follows: {{user.follows}}</p>
{% for newquery in newqueries reversed %}
<div class="newpost"><p>{{ newquery.body }}</p><p>By: {{ newquery.username }} on: {{ newquery.timestamp }} Likes: {{ newquery.likes }}</p></div>
{% endfor %}
<input type="button" value="Follow" id="followButton">
{% endblock %}
Your first problem is your follower count does not have an ID. You are trying to target it with #followers, but it only has a class .followers.
Your second problem is button inputs don't display textContent. They display their value.
const element = document.getElementById('followButton');
element.value = "Un-Follow";
Try something like this: const element = document.getElementById("followButton").value="Un-Button Follow" i think the value should be Button in between the un and follow i.e un-follow, Note(change it to suit your code)
Check this article here: https://www.permadi.com/tutorial/jsInnerHTMLDOM/index.html
I created a form which collects data to either launch an external process (bash script) or to make a database query (using queryBuilder). Since both procedure could take some time, I would like to update the submit button, as soon as it is clicked, with a message (like 'Processing..., please wait') or an icon (like the animated icons of FontAwesome). Here is the function I set in my Controller class (Symfony2):
public function inputAction(Request $request)
{
$form = $this->createForm(new InputType());
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$data = $form->getData();
$cmd = '... my command using $data and taking some time ... ';
$process = new Process($cmd);
$process->setTimeout(120);
$process->run();
// Alternative DB query
// $qb = $this->getDoctrine()->getManager()
// ->createQueryBuilder();
// $query = $qb->select('COUNT(p)')
// ->add('from','myBundle:Ec p')
// ->add('where', 'p.ec LIKE :ec')
// ->setParameter('ec', $data['..'].'%')
// ->getQuery();
//
// $result = $query->getSingleScalarResult();
return $this->redirectToRoute('_input');
}
return $this->render('myBundle:Default:form.html.twig', array(
'form' => $form->createView(),
));
}
I thus added a JQuery call in my template
{% extends 'myBundle:Default:input.html.twig' %}
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{% block form %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
$(function() {
$('.btn-default').on('click', function() {
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
});
});
</script>
{%endblock %}
But the message or the icon is not displayed when the button is clicked. It is only displayed if I stop the process in the browser. I also tried the 'submit' event, with no more success, while 'mouseover' is perfectly working.
EDIT 1
Following the advice from #Micha, when I modified JS like that:
$(function() {
$('.btn-default').attr('prepend', 'false')
$('.btn-default').on('click', function(e) {
if($('.btn-default').attr('prepend') == 'false'){
e.preventDefault();
$('.btn-default').attr('prepend','true');
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
$(this).trigger('click');
}
});
});
I see that the DOM is updated and the query (or the process) launched, but the prepend text or icon is not actually displayed in the browser.
How about preventDefault() and then submit() the form from in the click function?
<script>
$(function() {
$('.btn-default').on('click', function(event) {
event.PreventDefault();
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
$(#my-form).submit();
});
});
</script>
Hope this helps.
The problem I was facing is apparently only occurring with Safari. My original code (and most of the proposed solutions by #Micha and #chris-rogers) are perfectly working in Chrome and Firefox.
I have an external python program, named c.py, which "counts" up to 20 seconds.
I call it from my Django app views.py and in the html page I have a button to start it. It's ok (= in Eclipse I can see that c.py prints 0,1,2,3,...20 when I press the button on the webpage) but I would like that the button changes from "GO" to "WAIT" during c.py process (or I would like to perform a waiting page during the counting or also a pop-up).
c.py
import time
def prova(z):
z = 0
while z < 20:
time.sleep(1)
z = z + 1
print(z)
views.py
from django.shortcuts import render_to_response
#etc.
import c
def home_user(request):
return render_to_response('homepage/home.html',{'user.username':request}, context_instance = RequestContext(request))
def conta(request):
c.prova(0)
return redirect(home_user)
where in homepage.html I have the "GO" button that I would like to change in "WAIT" if the function conta is running.
urls.py
urlpatterns =patterns('',
url(r'^homepage/home/$', views.home_user, name='home'),
#etc.
url(r'^conta', views.conta, name='conta'),
)
home.html
{% if c.alive %}
WAIT
{% else %}
GO
{% endif %}
I don't put the whole code.. I hope this is sufficient to understand my trouble.
I also see at How to create a waiting page in Django but I would start with something simpler.
Up to now when I start c.py I see that my web page is loading something (=it is "counting") but my button does not change and, after c.py execution, I return to 127.0.0.1:8000/homepage/home/ page.
Is the problem in html or in my function definition or both?
UPDATE
I try to simplify the question:
I found this script...
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
var text = "";
var i = 0;
while (i < 10) {
text += "<br>The number is " + i;
i++;
}
document.getElementById("demo").innerHTML = text;
}
</script>
I would like to "import" my conta() function in while instead of the cicle with i++
i.e. I would like to have a similar thing:
while conta() is running, appear something like Waiting.. and when it stop i return to my home page.. I don't know how "put" conta() in the script.. is this possible? Am I a dreamer? :)
You're trying to check a server-side value on the client, but the problem is that the if c.alive statement only gets evaluated when your view is rendered - not as the status of c changes.
You would need to be able to report back the status of c to the client via ajax long polling or WebSockets, or, if you don't care about the incremental status of c and just want to change the text of the link, you'll need to use JavaScript to set the value when the click event of the link fires:
// assuming jQuery for brevity...
$(document).ready(function() {
// avoid hard-coding urls...
var yourApp = {
contaUrl: "{% url 'conta' %}"
};
$('#btnGo').click(function(e) {
e.preventDefault(); // prevent the link from navigating
// set css classes and text of button
$(this)
.removeClass('btn-primary')
.addClass('btn-danger')
.text('WAIT');
$.get(yourApp.contaUrl, function(json) {
window.top = json.redirect;
});
});
});
but... your conta function will need to return a JsonResponse instead of an HttpResponse in order to do the redirect on the client-side:
from django.core.urlresolvers import reverse
from django.http import JsonResponse
def conta(request):
c.prova(0)
redirect = reverse('name_of_home_user_view')
return JsonResponse({'redirect': redirect})
I post my working solution. Thanks to #Brandon for the useful answer.
in conta.js some changes:
$(document).ready(function() {
// avoid hard-coding urls...
var yourApp = {
contaUrl: "/conta/"
};
$('#btnGo').click(function(e) {
e.preventDefault();
// set css classes and text of button
$(this)
.removeClass('btn-primary')
.addClass('btn-danger disabled') // with *disabled* I'm sure that the button is not clickable
.text('WAIT');
$.get(yourApp.contaUrl, function(json) {
alert("I have finished counting");
parent.window.location.reload(true);
});
});
});
in views.py
def conta(request):
c.prova(0)
redirect = reverse('home')
return JsonResponse({'redirect': redirect})
I have a template in Django with a foor loop that looks roughly like this:
{% if items %}
<form method="post" name="managerform" id="managerform" action="">{% csrf_token %}
{{ managerform }}
</form>
{% for item in items %}
<script type='text/javascript'>
var yes = function yes() { manager(function(response) {
if(response && response.status == 'user') {
var object = '{{ item }}'
document.managerform.item.value = object;
document.managerform.preferences.value = "Yes";
document.managerform.submit();
}
else{
authUser(); } });}
</script>
...
<button onclick=yes()>Yes</button>
...
{% endfor %}
Which submits the form, the problem is it always submits the last item from items. I've tried making yes take an argument, aitem, which didn't help because using <button onclick=yes("{{item}}")> failed entirely and doing:
<script>
aitem="{{ item }}"
</script>
<button onclick=yes(aitem)>
just uses the last item from items again.
Is there an obvious solution to this to anyone?
Change your button's HTML to be:
<button onclick='yes("{{item}}");'>Text</button>
And take out the <script> code completely outside of your django conditionals and loops so that it is always available, but change it to be:
var yes = function (item) {
manager(function (response) {
if (response && response.status == 'user') {
var object = item;
document.managerform.item.value = object; // You could combine this and the previous line
document.managerform.preferences.value = "Yes";
document.managerform.submit();
} else {
authUser();
}
});
}
This way, the only thing inside of your django for loop is the button, and each one ends up having a different argument for the yes function. The yes function now accepts a parameter and uses it like you wanted. You'll probably have to modify this to fit your needs though, because your code snippet seems like an example and is not exactly what you have.