0

First I have searched and seen another answer, but it doesn't address my need.

I am trying to POST data using jQuery/AJAX from my HTML to update a list that is also on my HTML.

When I first rendered my template, it had two list-group containers of which the left container is pre populated.

two containers

The choice made user makes on the left container determines the list group data of the right container.

I wanted to send back to the backend Python (server) which selection the user made from the left container, so that I may populate the appropriate list for the second (right) container. This is why I used the POST method using jQuery/AJAX to send users selection.

HTML

Here is a Plnkr of the HTML

Below is the jQuery/AJAX implementation which WORKS. It sends data back to Python (to my views.py):

JS/jQuery/AJAX:

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script>
    $("#leftContainer > a").click(function(event){
        event.preventDefault();
        $("#leftContainer > a").removeClass("active");
        $(this).addClass("active");

        var leftDataSet = parseInt($(this).attr("data-set"));        
        var item_selected = $(this).text();
        var item_index = $(this).attr("id")   //Users selection to send

        $.ajax({
            type:'POST',
            url:"home/view_results/onclick/",
            data:{
                selected_item:item_index,
                csrfmiddlewaretoken:"{{ csrf_token }}"
            },
            dataType:"text",
            success: function(){$('#message').html("<h3>Data Submitted!</h3>") }
        })        
    });

    $("#rightContainer > a").click(function(event){
        event.preventDefault();
        $(this).toggleClass("active");
    });
</script>

views.py

#app/views.py
from django.shortcuts import render
class View_Items():

   def render_view_items(self, request, shopid):
      item_history = self.get_item_list(shopid)     #Fetches a list
      return render(request, 'view_results/View_items.html',{
           'item_list':item_history,
        })

urls.py

#app/urls.py
from django.urls import path, re_path
from . import views
results = views.View_Items()
urlpatterns=[
        ...
        re_path(r'view_results/(?P<shopid>\w+)$', results.render_view_items, name = 'view_items'),
        re_path(r'view_results/onclick/$', results.render_view_items_again, name = 'view_results_new'),  # NEW
]

My question is:,

now that I have the AJAX data returned back to my Python backend at views.py, do I have to re-render my page to populate the Right container's list group items in my HTML? Or is it possible to update the list without having to re-render. If so, why is my proposed re-render function below NOT updating the RIGHT container of my HTML? Updating the Right container is the objective which required the selection choice of left container.

Addition I made to views.py

#app/views.py
def render_view_items_again(self, request):
    selected_item_by_user = request.POST.get('selected_item')
    # print(selected_item_by_user)
    models = self.get_all_models(selected_item_by_user)  #Fetches a list.
    # print(models)                     #Tested if my list is populated.
    return render(request, 'view_results/View_items.html',{
        'model_list':models,
        })
  • You need to do something with the data in your ajax `success` function. – Daniel Roseman Nov 30 '18 at 16:56
  • I was able to send the data in my ajax to the reverse end successfully. What the success function does at this point is of no use since I already got my data at the backend. My question is why am I not able to see the Right container data populated after the backend (Python) re-rendendered the template. The function render_view_items_again() was called and the left container's list-group items were not populated. – YouGotA.BigEgo Nov 30 '18 at 17:23
  • Should I write $("#rightContainer > a").each(function(){ $(this).show();}); inside the success function? – YouGotA.BigEgo Nov 30 '18 at 17:28
  • No you've completely misunderstood how this works. The success function is responsible for doing everything after sending the data, including updating the page to show any data sent by the backend in response to the post. – Daniel Roseman Nov 30 '18 at 17:42
  • A clue for you would be to look at what is in the ajax response: `success: function(res){console.log(res);}`. Djangos render function has nothing to do with actually displaying anything on the page. It generates html, but it is up to you to display that in the browser if you're using ajax. – BottleZero Nov 30 '18 at 17:55
  • Hi @Bott0610 , I am able to see my html generated in console.log(res), but I not printed in my actual HTML. I understand people saying that I need to do something with my success function to print it. What I did was append to my template div using the `.append` method. Which worked, But I found that I worked myself to a corner this way. What I really wanted is Jinja2 to render my template again with updated info after AJAX send the data. I don't know why I am able to see new HTML on the console log, but it won't render the page (in my case the rightcontainer div) with the list-group-items. – YouGotA.BigEgo Dec 08 '18 at 03:36

1 Answers1

0

It is totally possible to fill the right container, without having to reload your page.

What is usually done is to divide the function from views.py into the case of the first render and when you return from an AJAX POST. In your case, the views.py will be something like:

if request.method == 'POST': # Returning from AJAX
    selected_item_by_user = request.POST.get('selected_item')
    models = self.get_all_models(selected_item_by_user)  #Fetches a list.
    return JsonResponse({'completed': "ok", 'list': models})

else:  # First time render
    item_history = self.get_item_list(shopid)     #Fetches a list
    return render(request, 'view_results/View_items.html',{
         'item_list':item_history,
       })

As you can see, I have only rendered the template the first time. When you get back from AJAX, I only call JsonResponse. Add the following import to your code:

from django.http import JsonResponse

Please be aware that depending on how is built your list (you have not provided the details), you will need to encode it accodingly.

Then, in the success function of your AJAX method, you can easily use the list (adapt it so that you fill the right container):

success: function(data){console.log(data.list)}

Hence, the right container will be filled without doing a re-render/refresh of the page.

Edit 1

Now I see that you are also redirecting to a different url in your AJAX method. If you want not to refresh, set your url in the AJAX method as follows:

$.ajax({
    type:'POST',
    url: window.location.href,
    data:{
        selected_item:item_index,
        csrfmiddlewaretoken:"{{ csrf_token }}"
    },
    dataType:"text",
    success: function(){$('#message').html("<h3>Data Submitted!</h3>") }
})  

So you only need one url in the urls.py file too.

I do not know the HTML code of your right container, but if it is a list ul (let's suppose that it has an id=list_conditions), you could add an item to the right container as follows:

// Get where I should add the index
let ul=document.getElementById("list_conditions");
// Create a new child
let li=document.createElement("li");
li.setAttribute("class", "list-group-item list-group-item-secondary");              
li.appendChild(document.createTextNode(data.list[0])); // Here you can replace by the index you need from the list
ul.appendChild(li);
Community
  • 1
  • 1
David Duran
  • 1,786
  • 1
  • 25
  • 36
  • `success: function(data){console.log(data.list)}` works, and shows the data in the console log. How do I actually print the data on the page? New to AJAX/JS. – YouGotA.BigEgo Nov 30 '18 at 19:45
  • Also, I updated my dataType in my AJAX is 'text' not 'json'. I figured out answer to my earlier comment how to print data on page this way, `success: function(res){console.log(res);$("#rightContainer").html(res);},}) – YouGotA.BigEgo Nov 30 '18 at 20:34
  • What value would I give for the 'url' field in my AJAX if I use your suggested method in views.py? Also, how would this change my urlpatterns in urls.py ? – YouGotA.BigEgo Nov 30 '18 at 21:52
  • You have to use Javascript to change the data on the page. Just use jquery via id. You should not change your urls at all. – David Duran Nov 30 '18 at 22:14
  • The url field in my AJAX is currently pointing to url:"home/view_results/onclick/", which I have mentioned in my urls.py. Are you saying I should not change this at all? url_patterns is trying to call results.render_view_items_again() function. Can you please edit your answer with changes? – YouGotA.BigEgo Nov 30 '18 at 23:39
  • I tried but it doesn't fill the right container without a re-render/refresh of the page no matter what I am trying to do.I am not sure I understood how you are telling me it's possible. – YouGotA.BigEgo Dec 01 '18 at 00:23
  • Look at my edit. I think that I have now answered both aspects you are mentioning. – David Duran Dec 01 '18 at 01:12