calling function with ajax, part working but part not working - javascript

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})

Related

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

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")
...
})

Select2 shows TEXT but submits IDs, using with Flask, WTForms

I'am trying to implement the Select2 drop-down (data via ajax) feature while using WTForms. Almost everything is working, meaning data is being fetched properly and processed in the expected 'ID and TEXT' format that Select2 expects.
However I am getting a "Not a valid choice" error upon submitting - when validate_on_submit is run. This appears to be caused by the fact that Select2 is submitting the ID number and not the TEXT. This is weird because it is displaying the text on the page itself when searching and actually making the selection.validate_on_submit is expecting 0 or 1 and not a random integer which is why it throws and error. How do I workaround this? How do I get the actual TEXT submitted?
And also any text/selection in previous Select2 fields disappears when adding a line or deleting one (I guess when running render_template??). Choices that are specified in flask/python are left intact as they should.
The most similar questions I could find are question1 and question2 but either there is no answer or I am unable to fully understand and apply it.
Here is some of the code:
Javascript
$(element).parents('.row').find('.item-model').select2({
placeholder: 'Select an option',
ajax: {
url: '/api/1/modelsnew',
dataType: 'json',
method: 'GET',
data: function (params) {
var specificquery = {
name: params.term
}
return specificquery;
},
processResults: function (data) {
var res = data.models.map(function (item) {
return {id: item.hardware_id, text: item.name};
});
return {
results: res
};
},
cache: true
},
minimumInputLength: 2
});
HTML
<div class="col-3">
{{ line.item_model.label}}
{% if line.item_model.data == 'Software' %}
{{ line.item_model(class='form-control item-model', disabled=true) }}
{% else %}
{{ line.item_model(class='form-control item-model') }}
{% endif %}
{% for error in line.item_model.errors %}
<p class="form-control-status text-danger">
{{ error }}
</p>
{% endfor %}
</div>
Flask-WTForm
class DeviceForm(FlaskForm):
item_model = SelectField('MODEL', choices=[('0', 'Select Item')], validators=[DataRequired()])
Further looking into this it appears the same issues are described here question3 and question4 but I am still unable to figure it out. Any help is appreciated!
I can also provide a gif and/or screenshots.
UPDATE:
I found out how to 'get' the TEXT value and display it via console.log but how do I make this the selection for the WTForms SelectField ? Why would it register the ID on submit?
var hereitgoes = $(element).parents('.row').find('.item-model')
$(hereitgoes).on("select2:select", function (e) {
var selectedtext = $(e.currentTarget).text();
console.log(selectedtext)
});

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();
}

javascript/jquery dropdown menu selection not passing GET request

In my page I have a dropdown menu, and upon selection I want to pass a GET request. This GET request should (ideally) trigger a function from my views.py file and return some data (based on the selection) from my database. However, it doesn't seem like anything actually happens upon dropdown menu selection.
Here is my script that I wrote to trigger the GET request when a selection was made:
<!-- AJAX Call for dropdown menu selection -->
<script type="text/javascript">
var url = $('.dropdown-menu').attr('action');
$('.dropdown-menu-option').click(function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: url,
data: {
class: $('.dropdown-menu-option').val()
},
success: function(result) {
alert ('pass');
},
error: function(result) {
alert('fail');
}
});
});
</script>
Here is the code for my dropdown menu in my template:
<!-- Query based content for dropdown menu -->
<select class="dropdown-content">
{% if current_user_properties %}
{% for property in current_user_properties %}
<option class="dropdown-menu-option" value="{{property.id}}">{{property.name}}</option>
{% endfor %}
{% else %}
<option>You don't have any properties</option>
{% endif %}
</select>
Lastly, here is the code for the function I wanna run in my views.py
def property_selected(request):
if request.method == 'GET':
selection = request.GET.get('class', None)
if selection:
selected_data = MeterData.objects.filter(property=selection).order_by(date)
return selected_data
If anyone can help identify what I'm missing/doing wrong, that'd be greatly appreciated. Thanks!!
$('.dropdown-menu-option') returns a collection of html nodes, since there are many elements that match this selector.
So when you pass $('.dropdown-menu-option').val() to the class property of the data object of ajax options, you are not really passing the value of the selected option.
You can attach a onChange event on the select.dropdown-content and get the value of the selected option like this:
$('.dropdown-content').on('change', function(e){
var selectedOption = $(this).find(':selected').val()
$.ajax({
type: "GET",
url: url,
data: {
class: selectedOption
},
...
})

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