Utilise AJAX & javascript to create a toast with Djangos messaging framework - javascript

I have followed a tutorial to utilise AJAX to validate an input field before attempting to submit. I have it working on my django built site; however, I have been using toasts to alert the user to other actions and did not want to get way from this.
$("#id_hub_name").focusout(function (e) {
e.preventDefault();
// get the hubname
var hub_name = $(this).val();
// GET AJAX request
$.ajax({
type: 'GET',
url: "{% url 'validate_hubname' %}",
data: {"hub_name": hub_name},
success: function (response) {
// if not valid user, alert the user
if(!response["valid"]){
alert("You cannot create a hub with same hub name");
var hubName = $("#id_hub_name");
hubName.val("")
hubName.focus()
}
},
error: function (response) {
console.log(response)
}
})
})
This is my current JS, I want to change the alert function to use toasts instead.
In my base.html I use the following to listen for toasts and create them.
{% if messages %}
<div class="message-container">
{% for message in messages %}
{% with message.level as level %}
{% if level == 40 %}
{% include 'includes/toasts/toast_error.html' %}
{% elif level == 30 %}
{% include 'includes/toasts/toast_warning.html' %}
{% elif level == 25 %}
{% include 'includes/toasts/toast_success.html' %}
{% else %}
{% include 'includes/toasts/toast_info.html' %}
{% endif %}
{% endwith %}
{% endfor %}
</div>
{% endif %}
Thanks in advance

You just need to append the html element for the toast.
First of all, loose the {% if messages %}, make sure <div class="message-container"> is always present in your template. If there are no messages, it will just be an empty div.You also need to add the templates for the toasts in js as well, so that you can just append the toasts from JS.
Now you can just append the template for the toast after your ajax response.
something like:
function show_alert_from_js(alert_type, text) {
msg = `<<your template here>>${text}`; // to render the text message to show.
msg_html = $.parseHTML(msg);
$('.message-container').append(msg_html);
}
$.ajax({
type: 'GET',
...
success: function (response) {
if(!response["valid"]){
show_alert_from_js("error", "You cannot create a hub with same hub name")
...
})

Related

How do i create and use variables in django

New to Django and its templates.
I'm trying to set a variable given a specific situation, and that part I think ill be able to do, the code below isn't the exact conditions its just there as a demo. The part im stuck on is how do i create a variable name, and then use that name variable elsewhere. Such as within a div or within a method or anywhere else within the html file, and withing different <Script> tags to run methods and for really any purpose.
demo scenario :
{% for row in table.rows %}
{% if row == 2 %}
{% var name = row.name %}
{% endif %}
{% endfor %}
{% if name %}
<div>{{name}}</div>
{% endif %}
my actual code Im trying to implement:
<script type="text/javascript">
function map_init_basic(map, options) {
var markerClusters = L.markerClusterGroup({ chunkedLoading: true });
{% for row in table.rows %}
var x = "{{ row.cells.x }}"
var y = {{ row.cells.y }}
var m = L.marker([y, x])
m.bindPopup("{{row.cells.first_name}} {{row.cells.last_name}} <br>{{row.cells.chgd_add}}");
m.on("click" , ()=>{
//console.log(`${first_name} ${last_name}`)
{% var first_name = {{row.cells.first_name}} %}
})
//changed row.cells.chgd_add to row.cells.Chgd_add to make sure its matching the table
markerClusters.addLayer(m);
{% endfor %}
markerClusters.addTo(map);
}
{% if first_name %}
console.log("{{first_name}}");
{% endif %}
</script>
Django templates are intended to render html but you are trying to render javascript. It can work but the way you are trying to do it is not a good practice; very soon you won't be able to maintain your code.
If you want to pass data directly from python/django to javascript, an accceptable way to do so is to put the data in a dictionary, translate it to a json string and have it set to a var in your javascript.
in a view:
data = dumps(some_dictionary)
return render(request, 'main/template.html', {'data': data})
in the template:
<script>
var data = JSON.parse("{{data|escapejs}}");
</script>
https://docs.djangoproject.com/fr/3.1/ref/templates/builtins/#escapejs
Alternative: You can use django to generate a widget with data attributes and have a javascript operating on this widget and do whaterever needs to be done.

How to retrieve Django model id from admin page via javascript

Suppose I have a Django model like this one.
class Car(models.Model):
speed = models.IntegerField()
color = models.CharField(max_length=120)
I registered it in admin via
admin.site.register(Car)
I want to add custom JS button for admin site object view, which will alert value of a color of an instance of a Car model. So when I press it I get something like "The car with id 13 is red"
How can I get id of an object and value of a color field via JavaScript?
You have to extend change_form.html template for you app (https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#overriding-vs-replacing-an-admin-template)
For example I have store app and inside models.py I've put Car model.
Then inside store/templates/admin/store/change_form.html I've put this template:
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block content %}
{{ block.super }}
<script>
const object = {
pk: {{ original.pk }},
color: '{{ original.color }}',
};
</script>
{% endblock %}
{% block object-tools-items %}
{{ block.super }}
<li>
My button
<script>
const button = document.getElementById('my-button');
button.addEventListener('click', function() {
alert(`The car with ${object.pk} is ${object.color}`);
});
</script>
</li>
{% endblock %}
Admin view:

How to refresh a part of the DOM HTML when querying a foreign django view

Hello Awesome People!
So many questions on StackOverflow are about "How to refresh dom via jquery (from the same view/url)" It's not what I'm looking for.
With a website that large of its parts are running with ajax, I wonder how to refresh a part of the HTML DOM when querying a foreign django view.
Let me be clearer with some examples:
I have that view that sends all_users to template
def usersList(request):
all_users = User.objects.all()
return render(request,'administration/users-list.html',{'all_users':all_users})
In the template I loop through all_users... The 2nd <span> reflects the activation state of the user
{% for u in all_users %}
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
{% endfor %}
With jquery, I send a request to a specific view responsible only to activate or deactivate the account of the user. We can activate/deactivate user in many parts of the website, that's why I do so in a different view.
Here's the view:
def deactivateUser(request):
user = request.user
if user.has_perm('is_admin') and request.is_ajax() and request.method == 'POST':
id_user = request.POST.get('id')
targeted_user = get_object_or_deny(User,id=id_user)
# get_object_or_deny is my own function
it will get the object or raise PermissionDenied otherwise
if targeted_user.is_activate:
targeted_user.is_activate = False
state = 'deactivated'
else:
targeted_user.is_activate = True
state = 'activated'
targeted_user.date_update_activation = NOW() # own function
targeted_user.save()
return JsonResponse({'done':True,'msg':'User successfully %s' %s state})
# Here we return a JsonResponse
raise PermissionDenied
So now, how can I refresh the Dom with following jquery stuff to get the current state of each user
$(document).on('click','.btn-circle',function(){
var id = $(this).data("id");
$.ajax({
url:'/u/de-activate/?ref={{ request.path }}',
type:'post',
data:{
csrfmiddlewaretoken:"{{ csrf_token }}",
id:id,
},
success:function(response){
$("#user_"+id+"_state").replaceWith($("#user_"+id+"_state",response));
if(response.created) alert(response.msg);
},
error:function(){
alert("An error has occured, try again later");
}
});
});
Note that all_users is required to loop through. deactivateUser() return a Json response, even though it doesn't returned it, it will not matter.
You can send http response, not json.
First, just move your html that want to change. in this situation,
{% for u in all_users %}
<div id="user-part">
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
</div>
{% endfor %}
Then save it i.e. user_part.html
Second, make your view return HttpResponse with that html, and context. You can use either HttpResponse or render_to_response. I recommend render_to_response.
context = {
'all_users': all_users,
}
return render_to_response(
'path_to/user_part.html',
context=context,
)
Third, you just change script for replacing your html.
success: function(response){
$('#user-part').html(response);
prevent();
}

calling function with ajax, part working but part not working

Sorry if the title isn't very clear. I have search engine that works with ajax function. Right now if I type t in a search box, the tags that contain the word t shows up(ex if I type t, then test shows up) but thing is after I delete the word t all the tags show up in the result part. Does this make sense? if I'm not clear I'll post the picture. I'm not sure why or how to fix this.
Here;s my code.
<h3>Search</h3>
{% csrf_token %}
<input type="text" id="search" name="search" onkeyup="handle_keyup()"/>
<ul id="search-results">
</ul>
Here I can't delete search-results as this will show the search results but on this section when nothing is typed still all the tags show up. (it only shows all when I finish using search bar)
my ajax
function handle_keyup() {
$.ajax({
type: "POST",
url: "/search/",
data: {
'search_text' : $('#search').val(),
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: 'html'
});
};
function searchSuccess(data, textStatus, jqXHR)
{
$('#search-results').html(data);
}
problem is probably occurring from up there, but I'll post the back end as well. This is python django framework.
def search_titles(request):
# categories = SearchQuerySet().autocomplete(content_auto=request.POST.get('search_text', ''))
categories = Category.objects.filter(name__icontains=request.POST.get('search_text', ''))
return render_to_response('main/ajax_search.html', {'categories' : categories})
ajax_Search.html
{% if categories.count > 0 %}
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
{% else %}
<li>None to show!</li>
{% endif %}
thanks in advance
This is happening because when the user "deletes" the word, your handle_keyup function is fired, sending a search request of '' to the server.
The server then looks for the empty string '' in the category names and finds it in all of them.
One approach is for the server to check if the search text is empty, and if it is, return nothing. Something like:
def search_titles(request):
txt = request.POST.get('search_text', '')
if txt:
categories = Category.objects.filter(name__icontains=txt)
else:
categories = []
return render_to_response('main/ajax_search.html', {'categories' : categories})

HTML refreshing on click

I'm using the sample found here http://stackoverflow.com/questions/27218680/how-can-i-reload-just-one-div-on-click and I think I'm missing something in my example or maybe the value is not passing as I'm using MPTT instead of a standard menu.
This is how I'm loading my menu found in my base.html -
{% recursetree nodes %}
{{ node.name }}
{% endrecursetree %}
Here is the javascript I've included -
<script>
$(document).on('click','.node',function(e) {
id = $(this).attr("id");
$.ajax({
type: "GET",
url: '/gui/details/' + id,
success: function (result) {
$('.details').html(result);
},
});
});
</script>
I'm then trying to use this id to reload the template here -
<div class="details">
{% include 'gui/details.html' %}
</div>
Here is the view for generating the details -
def display_details(request, list_id):
qs_details = Details.objects.filter(owner=request.user, list=list_id)
return render(request, 'gui/details.html', {'qs_details': qs_details,})
Currently when I click anything on my list it doesn't do anything.

Categories

Resources