problem with rendering <form> asynchronously using fetch in javascript in django application

Viewed 15

I have written an ajax request in jQuery that I want to rewrite to pure javascript using fetch.

What I am currently using is this:

views.py

@login_required
def like_article(request, id):
    article = get_object_or_404(Article, id=id)
    is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
    liked = False
    if article.likes.filter(id=request.user.id).exists():
        article.likes.remove(request.user)
        liked = False
    else:
        article.likes.add(request.user)
        liked = True

    context = {
        'article': article,
        'is_liked': liked,
        'total_likes': article.total_likes(),
    }
    if is_ajax:
        like_form = render_to_string('components/ajax_like.html', context, request=request)
        return JsonResponse({'like_form': like_form})

url.py

path('like_article/<int:id>/', views.like_article, name='like_article'),

ajax_like.html

<form action="{% url 'like_article' article.id %}" method="POST">
    {% csrf_token %}
    {% if is_liked %}
    <button type="submit" id="like" value="{{article.id}}" class="btn btn-clicked"><i class='bx bxs-like'></i></button>
    {% else %}
    <button type="submit" id="like" value="{{article.id}}" class="btn btn-to-be-clicked"><i class='bx bx-like'></i></button>
    {% endif %}
    {{ total_likes }} like{{ total_likes|pluralize }}
</form>

jQuery ajax request (working fine)

  $(document).ready(function(event){
  $(document).on('click', '#like', function(event){
    event.preventDefault();
    var id = $(this).attr('value');
    $.ajax({
      type: 'POST',
      url: '{% url "like_optimazon" article.id %}',
      data: {
        'id':id, 
        'csrfmiddlewaretoken': '{{ csrf_token }}'
      },
      dataType: 'json',
      success: function(response){
        $('#like-section').html(response['like_form'])
      },
      error: function(rs, e){
        console.log(rs.responseText);
      },
    });
  });
});
});

What I tried to do is below. Basically, after clicking the like button the class should change from .btn-not-liked to .btn-liked and the number of likes should increase by 1. I;d like to keep the same logic in the backend but I am getting The view articles.views.like_article didn't return an HttpResponse object. It returned None instead. error. However, when I come back to the webpage counter and class is updated correctly.

function like_handeler(element) {
  element.addEventListener("click", () => {
    id = element.getAttribute("value");
    liked = element.getAttribute("data-liked");

    form = new FormData(this);
    form.append("id", id);
    form.append("is_liked", liked);

    fetch('{% url "like_article" article.id %}', {
      method: "POST",
      body: form,
      credentials: 'same-origin',
      headers:{
          'Accept': 'application/json',
          'X-Requested-With': 'XMLHttpRequest', 
          'X-CSRFToken': '{{ csrf_token }}',
      }
    })
    .then((res) => res.json())
    .then((res) => {
          console.log(res)
      if (res.status == 200) {
        if (res.is_liked === "yes") {
            button.classList.toggle(".btn-not-liked");
            element.setAttribute("data-liked", "no");
          } else {
              button.classList.toggle(".btn-liked");
            element.setAttribute("data-liked", "yes");
          }
          count.textContent = res.like_count;
        }
      })
      .catch(function (res) {
        alert("Network Error. Please Check your connection.");
      });
  });
}
0 Answers
Related