Receiving checkbox information from EJS file in an Express.js app (unchecking a checkbox)

101 Views Asked by At

I have a simple todo list application which uses Express.js, EJS and Body Parser. It's a course homework. It doesn't have a database connection so the task list items do not persist between sessions. The goal of the homework was to practice form submission and handling the information received from the form.

The user can create new tasks and cross out completed tasks. She can also undo a crossout. This crossing out / undoing a crossout is implemented with checkboxes. When a user changes a checkbox, the site hits the route /checkClick in the index.js file:

app.post("/checkClick", (req, res) => {
  //console.log(req);
  console.log("number: " + req.body["number"]);
  console.log(req.body);
  todayTasks[req.body["number"]].done=!(todayTasks[req.body["number"]].done);
  console.log("todayTasks checkClick: ");
  console.log(todayTasks);
  res.render("today.ejs", {
    ttasks: todayTasks
  });
});

Following is an excerpt from today.ejs which contains the form:

<form action="/checkClick" method="POST">
        <input type="checkbox" id="checkbox" <% if(isChecked) {%> checked <% } %> name="number" value=<%=i%> onChange="this.form.submit()">
         <label for="checkbox"><% if(isChecked) {%> <s> <% } %><%=ttasks[i].taskName%><% if(isChecked) {%> </s> <% } %></label>
</form>   

My problem is that when I undo a crossout (uncheck a checkbox), the app.post() handler does not receive the attribute number. I get this error:

TypeError: Cannot read properties of undefined (reading 'done')
    at file:///C:/Users/suvi1/Documents/angela/test_todo/index.js:36:72
    at Layer.handle [as handle_request] (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\route.js:144:13)
    at Route.dispatch (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\route.js:114:3)
    at Layer.handle [as handle_request] (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\index.js:284:15
    at Function.process_params (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\index.js:346:12)
    at next (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\index.js:280:10)
    at serveStatic (C:\Users\suvi1\Documents\angela\test_todo\node_modules\serve-static\index.js:75:16)
    at Layer.handle [as handle_request] (C:\Users\suvi1\Documents\angela\test_todo\node_modules\express\lib\router\layer.js:95:5)

I have put print statements in index.js and I have found out that the req.body is empty. The problem does not occur when crossing out an item, only when undoing a crossout (unchecking a checkbox)!

I simply can't find the bug. What is the problem? The entire code is in GitHub.

2

There are 2 best solutions below

0
jQueeny On

The MDN docs for checkbox state this more clearly than I can:

Note: If a checkbox is unchecked when its form is submitted, neither the name nor the value is submitted to the server. There is no HTML-only method of representing a checkbox's unchecked state (e.g. value=unchecked). If you wanted to submit a default value for the checkbox when it is unchecked, you could include JavaScript to create a within the form with a value indicating an unchecked state.

So basically when you uncheck that checkbox and submit the form the checkbox doesn't get submitted so "the app.post() handler does not receive the attribute number" problem you face is the expected behaviour.

1
PrestOnTheWeb On

As someone else said, when the box is unchecked, the value isn't submitted to the server. You could remedy this by including a hidden input that handles your numerical indexing of the checkbox; this hidden input's name/value would be sent to the server when the form is submitted, but won't be affected by the checkbox's status.

E.g.:

<input type="hidden" name="number" value=<%=i%> >