Creating a Like Button but with Async/Ajax

Hi, so i have succesfully added a like button and it likes and unlikes a post succesfully.

But the problem is that it loads the home page everytime someone likes or unlikes a post.

Now ajax/Async fetch can do it without reloading the post, but how can i achive it ?

My models File

from django.db import models

from django.utils import timezone

from django_extensions.db.fields import AutoSlugField


class retailer(models.Model):

	links = models.CharField(max_length=9999, unique = True)

	title = models.CharField(max_length=300)

	slug = AutoSlugField(populate_from=['title'])

	date_posted = models.DateTimeField(default=timezone.now)

	no_of_likes = models.IntegerField(default=0)


	def __str__(self):

		return self.title


	def count(self):

		return self.count()

	


class LikePost(models.Model):
	
	post_id = models.CharField(max_length=500)
	username = models.CharField(max_length=100)
    
	def __str__(self):
		return self.username

My Views File

def home(request):

	prods = retailer.objects.all()

	context = {

		"prods":prods,
	}

	if request.method == 'POST':
		
		username = request.user.username
		post_id = request.POST.get("item-id")

		post = retailer.objects.get(id=post_id)

		like_filter = LikePost.objects.filter(post_id=post_id, username=username).first()

		if like_filter == None:

			new_like = LikePost.objects.create(post_id=post_id, username=username)
			new_like.save()
			post.no_of_likes+=1
			post.save()
			return render(request, 'testing/home.html', context)
		
		else:

			like_filter.delete()
			post.no_of_likes-=1
			post.save()
			return render(request, 'testing/home.html', context)

	return render(request, 'testing/home.html', context)

My HTML Template File

      <form action = "" method = "POST">
      {% csrf_token %}
      <button type="submit" name = "item-id" value = "{{item.id}}" class = 'btn btn-primary btn-sm'> {{item.no_of_likes}} Like </button>
      </form>

Thanks

Using AJAX, it would be just like any other AJAX-style interaction.

  • You have the button on the page to be clicked. (It needs to be a button, not a submit button.)
  • You capture the click event for that button to call a JavaScript function
  • That JavaScript function issues a POST to a new view that you will create to handle this interaction.
  • That view does whatever needs to be done on the server for that click
  • That view then returns whatever the JavaScript is expecting as a response. (It might be some HTML or it might be JSON.)
  • The JavaScript then uses the response to update the page.

The precise code to use will depend upon what (if any) JavaScript framework you are using.

(Note: There’s no need for this to use async/websockets/channels, unless you’re already using them for other reasons.)

Where is your ajax code that you try to use ,
I will give you ideas , but you must keep in your mind every case is different from one developer to another.
And you must read Ken’s reply carefully (It always has an answer)
Any way, try something like that

$(document).on('submit', ".product-form", function (e) {

            let name = $('#id_pro-name').val(); 
            let nameAr = $('#id_pro-name_ar').val(); 
            
            console.log(
                'submit button clicked successfully');

            $.ajax({
                type: 'POST',
                url: '{% url "products:add_product" %}', 
                dataType: 'json',
                data: {
                    csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
                     'identity': $('#identity').val(),
                    'department_manager': $('#department-manager').val(),
                    'email': $('#email').val(),
                    'phone': $('[name=phone]').val(),
                    'mobile1': $('[name=mobile1]').val(),
                    'mobile2': $('[name=mobile2]').val(),
                    'description': $('#description').val(),
                },
                success: function (data) { 
                    
                    $(function() {
                        var Toast = Swal.mixin({
                            toast: true,
                            position: 'top-end',
                            showConfirmButton: false,
                            timer: 9000
                        });
                        var proId = data['pro_id']; 
                        // var patch = 
                        
                        if (data['type'] == 'error'){
                            console.log(data['type'])
                            toastr.error(data['error']);
                        } else if (data['type'] == 'success') {
                            toastr.success(data['error']);
                        } else if (data['type'] == 'info') {
                            toastr.info(data['error']);
                        }
                    });
                },
                error: function (){
                    console.log('ERROR with ajax request');
                },
            });
            e.preventDefault();
        });

In view.py try to do like this

from django.http import JsonResponse

def add_employee(request):

    data = {}
    data['emp_id'] = None 
    data['error'] = 'ERROR !!!'
    data['type'] = 'error'
    if request.is_ajax() and request.method == "POST":
        form = EmployeeForm(request.POST or None)
        emp_name = request.POST.get("name") 

        img_txt = request.POST.getlist("img-txt")     # list from request.POST 
        img_input = request.FILES.getlist("img-input") # list from request.POST 

        ajax_txt = request.POST.getlist('imgTxtValues[]')     # success to get the list from ajax response
        ajax_input = request.POST.getlist('imgInputValues[]') # success to get the list from ajax response

        match = Employee.objects.select_related('user').filter(name=emp_name).exists()
        if not match:
            if form.is_valid():

                save_form = form.save(commit=False)
                save_form.user = request.user
                save_form.updated_user = request.user
                
                save_form.save()

                if ajax_input != []:
                    [
                        EmployeeImage.objects.create(
                            employee_id=save_form.id,
                            photo=obj,
                            user = request.user,
                            updated_user = request.user,
                        ) for obj in ajax_input
                    ]
                error = ('Employee with name "%s" saved successfully' % (emp_name))

                data['emp_id'] = save_form.id 

                data['error'] = error
                data['type'] = 'success'
                return JsonResponse(data)
            else:
                for f in form:
                    print('error from is not valid: ', f.name, f.errors)
                data['error'] = 'error from is not valid'
                return JsonResponse(data)
        else:
            print('name already exists !!!')
            error = ('Employee with name "%s" already exists !!!' % (emp_name))

            data['emp_id'] = None #save_form.id 
            data['error'] = error
            data['type'] = 'error'
            return JsonResponse(data)
    else:
        form = EmployeeForm()

    context = {
        'form': form,
        'title': 'Create Employee'
    }
    return render(request, 'employees/add_employee.html', context)

This a sample code to illustrate how to use it , But my scenario is not yours ,

  • If you have an ajax code and your problem only is to stop the page reload then use
    e.preventDefault();
    It will prevent page from reloading
    Hope it helps

hi sorry for the late reply, but i got it working, only problem is it only likes the first 6 images as i scroll down with lazy load, it does not get the other 6 and so on.

i tried the Scroll addevent listener but it made the LIke button and counter go crazy.

MY JS CODE:

let x;
window.addEventListener("scroll", function() {

x = [...document.getElementsByName('item-id')]; 
x.forEach((items) => 
items.addEventListener("click", function(event){ 

const clickedId = event.target.value 
const clickedBtn = document.getElementById(like-unlike-${clickedId})

$.ajax({ 
type: 'POST',
 url: "/like-unlike/", 
data: { 'item-id': clickedId, },
 
success: 
function(response)
{ console.log(response.likes) 
clickedBtn.textContent = ${response.likes} likes
        },
error: 
function(error)
{ console.log(error) } 
})
 }))
 });

MY HTML CODE:

<button id="like-unlike-{{item.id}}" name = "item-id" value = "{{item.id}}" class = 'btn btn-primary btn-sm'> {{item.no_of_likes}} Like </button>