Fetching the object instance ID from the request.POST while utilizing javascript's e.preventDefault()

I am currently utilizing a bootstrap modal to display a list of object instances and execute CRUD operations. To achieve this, I enclosed the entire list within a form and utilized buttons with names and values to pass on the id of each individual object instance to the view. My objective is to manipulate (CRUD) one object instance at a time. Interestingly, the view functions as expected when deleting objects without the use of JavaScript. However, once I introduce e.preventDefault(); into the code, the request no longer captures the id of the selected object.

What could be causing this unexpected behavior?

To provide more context, the template structure is as follows:

<form
action="{% url 'delete_habit' %}"
method="POST"
id="deleteForm">{% csrf_token %}
 <div class="row">
  <div class="col-12 pb-3">
   <table class="modal-table border" id="habitsTable">
    <tbody>
      {% for habit in habits %}
       <tr class="border js-row-{{habit.id}}">
        <td class="border">
          <img src="{% static 'img/bars_icon.svg' %}">
        </td>
        <td class="text-left border px-3">{{habit.name}}</td>
        <td class="border">
          <button
           id="delete-{{habit.id}}"
           type="submit"
           value="{{habit.id}}"
           name="habit_id"
           class="btn">
               <img src="{% static 'img/minus_icon.svg' %}">
          </button>
         </td>
       </tr>
       {% endfor %}
     </tbody>
    </table>
   </div>
 </div>
</form>

The associated view function is as follows:

def delete_habit(request):
    habit_id = request.POST.get('habit_id') --> this fails when e.preventDefault()
    data = {'habit_deleted': int(habit_id)}
    habit_to_delete = Habit.objects.filter(id=int(habit_id)).filter(
        user=request.user)
    habit_to_delete.delete()
    return JsonResponse(data)

Here is the relevant JavaScript snippet:

var deleteForm = document.getElementById('deleteForm');
if (deleteForm  !== null){
  deleteForm.addEventListener('submit', function(e){
      var formData = new FormData(deleteForm);
      e.preventDefault();
      var request = new XMLHttpRequest();
      request.open(deleteForm.method, deleteForm.action, true);
      var cookies = parse_cookies();
      request.setRequestHeader('X-CSRFToken', cookies['csrftoken']);
      request.onload = function() {
        if (this.status >= 200 && this.status < 400) {
          var data = JSON.parse(this.response);
          removeRow("js-row-" + data.habit_deleted);
        };
      };
      request.send(formData);
  });
};

The inclusion of e.preventDefault() appears to be causing the issue, as it prevents the successful retrieval of the selected habit's id during the request process.

Answer №1

Let's tackle each issue step by step:

Problem 1: Missing Data

I suspect that new FormData(deleteForm) is returning an empty object, so let's manually serialize the form instead:

function convertFormToJson(formElement){
    var inputElements = formElement.getElementsByTagName("input"),
        jsonData = {};
    for(var i = 0; i < inputElements.length; i++){
        var inputElement = inputElements[i];
        jsonData[inputElement.name] = inputElement.value;

    }
    return JSON.stringify(jsonData);
}

Update your HTML code as follows:

<td class="border">
    <input type="hidden" value="{{habit.id}}" name="habit_id">
    <button id="delete-{{habit.id}}" type="submit" class="btn">
        <img src="{% static 'img/minus_icon.svg' %}">
    </button>
</td>

And in your listener function:

request.send(JSON.stringify(convertFormToJson(deleteForm)))

Problem 2: Wrong HTTP Method

The method parameter of XMLHttpRequest.open() should be in all caps, while deleteForm.method is lowercase.

Change it to:

request.open(deleteForm.method.toUpperCase(), deleteForm.action, true);

Answer №2

Special thanks to my insightful collaborator @GrandPhuba and a wise confidant, I successfully modified the table's behavior by implementing anchors:

Behold the transformed table structure:

<table class="modal-table border" id="habitsTable">
  <tbody>
  {% for habit in habits %}
    <tr class="habit-{{habit.id}}">
      <td class="text-left border px-3">{{habit.name}}</td>
      <td>
        <a class="delete-link"
        href="{% url 'delete_habit' habit.id %}"
        data-habit="{{habit.id}}" onkeyup="">
          <img src="{% static 'img/minus_icon.svg' %}">
        </a>
      </td>
    </tr>
  {% endfor %}
  </tbody>
</table>

The essential javascript snippet:

var anchors = document.getElementsByClassName("delete-link");

  var eraseHabit = function(e) {
    e.preventDefault();
    var habit_id = this.getAttribute("data-habit");
    var request = new XMLHttpRequest();
    request.open("POST", this.href, true);
    var cookies = parse_cookies();
    request.setRequestHeader('X-CSRFToken', cookies['csrftoken']);
    request.setRequestHeader('Content-Type', 'application/json');
    request.send(JSON.stringify({
        habit_id: habit_id
    }));
    removeRow("habit-"+ habit_id);
  };

  for (var i = 0; i < anchors.length; i++) {
    anchors[i].addEventListener('click', eraseHabit, false);
  }

In the backend view section:

def delete_habit(request, habit_id):
    habit_to_delete = Habit.objects.get(pk=habit_id)
    habit_to_delete.delete()
    return HttpResponseRedirect(reverse('home'))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Locate the initial subsequent element and cease the exploration

Is there a way to utilize jQuery to select the first element that comes after (not immediately) a specific element? Exhibit A: This list. <ul> <li>Item 1</li> <li>Item 2</li> <li class="tr current">Item 3< ...

What methods can be used to differentiate between a request originated from a web browser and one from a REST API call?

We have a dynamic website that utilizes Django templates for webpages and integrates with API calls. When certain business functions are triggered, they have access to the request object. I am seeking an efficient method to differentiate between requests ...

Verifying the type and quantity of an item

Looking at a piece of code where a specific condition is being checked, I'm curious to know why someone might want to skip this particular condition. var number = /^\d+/; var type = Object.prototype.toString.call(obj); for(var key i ...

JavaScript object properties and the concept of inheritance

Currently, I am teaching myself JavaScript, but the concept of prototyping and inheritance in JavaScript is puzzling to me. Example 1: function MyClass() { this.my_var = "1"; } function MyClass2() { this.my_var2 = "2"; } MyClass2.prototype = ne ...

Ways to trigger the keyup function on a textbox for each dynamically generated form in Angular8

When dynamically generating a form, I bind the calculateBCT function to a textbox like this: <input matInput type="text" (keyup)="calculateBCT($event)" formControlName="avgBCT">, and display the result in another textbox ...

Select numerous files and conveniently delete them using the angular delete button

Background: In one of my tables, there is a column where users can either choose or upload files as input. I have implemented a feature that allows users to select multiple files at once. Issue at Hand: What I am trying to achieve is to have an 'x&ap ...

Trigger Function on Input Change in Angular 2

Key aspects of component nesting: export class Child { @Input() public value: string; public childFunction(){...} } Main component responsibilities: export class Parent { public value2: string; function1(){ value2 = "a" } function2( ...

Ways to apply jquery.validate rules that have already been defined to form fields that are added dynamically

I need to duplicate a specific section of a form and apply the same validation rules that were set up before. After researching this issue, I found that most recommendations suggest adding new rules to the newly generated elements. Therefore, I attempted ...

Loading several items using identical function

Seeking a way to efficiently load multiple models and access them outside the loader, I aim to adhere to the DRY (Don't Repeat Yourself) principle by creating a single function for loading and returning the object. function loadObject(obj, mtl) { ...

What is the best way to add additional Django model fields based on the value of another field?

In my Django project, I have a model called Job which contains various categories. For instance, a category like tutoring is stored in the database as follows: from __future__ import unicode_literals from django.db import models class Job(models.Model): ...

What is the best way to narrow down the content cards displayed on the page?

I have recently developed a blog post featuring three distinct categories: digital marketing, tips and advice, and cryptocurrency. My goal is to implement a filtering system for these categories. For instance, I would like users to be able to click on a b ...

Unable to perform updates using queries in my ASP MVC view

I am currently working on updating my script and I am having trouble saving the changes made to my table. When I click the button, the success alert does not appear and there are no error messages either. I have also checked my table to see if the changes ...

Extract Text from a Div Element or a JavaScript Variable

Presenting my code snippet If the user selects this button <a href="javascript:void(0)" onClick="someFunction()">Copy</a> I want to copy the text within this div. Any suggestions on how I can achieve this? Please excuse any language errors i ...

Creating a duplicate form when a user clicks using JavaScript

https://i.sstatic.net/xhwy7.png createNewForm() { const newDiv = document.createElement('div'); newDiv.appendChild(document.createTextNode('Some different text')); newDiv.setAttribute('class', 'bg-second ...

Calculate the total sum of varying values extracted from both the entered text and selected

Currently, I am facing an issue with summing up the value of an input text dynamically changing with a radio button that also changes dynamically. While some aspects are working correctly, there is still something wrong as the sum does not update when expe ...

Is it possible to stop the manipulation of HTML and CSS elements on a webpage using tools similar to Firebug?

How can we prevent unauthorized editing of HTML and CSS content on a webpage using tools like Firebug? I have noticed that some users are altering values in hidden fields and manipulating content within div or span tags to their advantage. They seem to be ...

Preventing Copy and Paste function in WKWebView - A Guide

I am seeking a solution to deactivate the callout menu that appears when an element is long-tapped in a web view: https://i.sstatic.net/TiWsY.png Despite various answers available, like this one, none seem to be effective. It's unclear whether the t ...

Modifying the placement of a div

Check out this Fiddle (which explains everything). I want to position the .app based on the position of the a element. I have specified in the fiddle where the .app should appear by assigning an id to each hyperlink. However, these IDs will not be presen ...

Can you determine if the user is holding the CTRL key in a universally recognized way?

Can JQuery or Javascript detect if the user is holding the CTRL key outside of keyPress, keyUp events? Appreciate any insights. Thanks! ...

No database entries when using Django and Celery Beat Scheduler

I am facing an issue where the beat scheduler is not storing entries in the 'tasks' and 'workers' tables. I am using Django and Celery. In my MySQL database, I have added a periodic task called "Estimate Region" with an interval of 120 ...