0

I have dynamically generated text boxes and each value has to be stored in a JSON array when posted. I pushed all the values to an array and when I post it, those values in an array are read as one object in a JSON array in my JavaScript server file.

For a better understanding, here's my code snippet below:

// my javascript server

const express = require("express");
const MongoClient = require("mongodb").MongoClient;
const app = express();
const {DB_URL} = require("./credentials");

const connectionString = DB_URL

MongoClient.connect(connectionString, {useUnifiedTopology: true})
.then(client => {

    console.log('Connected to Database');
    const db = client.db('todo-items');
    const itemsCollection = db.collection('items');

    app.use(express.urlencoded({extended: true}));
    app.use(express.static("public"));
    app.set("view engine", "ejs");
    app.use(express.json());

    var items = [];

    app.get('/', (req, res) => {
        db.collection('items').find().toArray()
        .then(items => {
            res.render('result.ejs', { items: items })
        })
        .catch(error => console.error(error))
    })

    app.get('/myForm', (req, res) => res.render("pages/myForm"));
    app.get('/result', (req, res) => res.render("pages/result", {
    items:items}));

    app.post('/myForm', (req, res) => {
        itemsCollection.insertOne(req.body);
        items.push(req.body);
        console.log(req.body);
        res.redirect("/result");
    });

    app.put('/items', (req, res) => {
        itemsCollection.findOneAndUpdate(
            { item: 'anything' },
            {
                $set:{
                    items: req.body.items
                }
            },
            {
                upsert: true
            }
            )
            .then(result => res.json('Success'))
            .catch(error => console.error(error))
    })

    app.delete('/items', (req, res) => {
        itemsCollection.deleteOne(
            { items: req.body.items }
        )
        .then(result => {
            if(result.deletedCount === 0) {
                return res.json('Nothing to delete')
            }
            res.json('deleted the selected item')
        })
        .catch(error => console.error(error))
   })
   const port = 3000
   app.listen(port, function () {
     console.log(`listening on ${port}`)
   })
 }).catch(console.error)
    
<!-- this is my result.ejs -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/style.css">
    <title>Assignment 2</title>
</head>
<body>
  <p style="text-align: center; display: inline-block; color: black;">Enter the todo item you want to modify, and the new name you want to give it.</p></br>
  <input type="text" id="item-given" cols="18" rows="2"></br>
  <input type="text" id="item-update-or-delete" cols="18" rows="2"></br>
  <button type="button" id="update-button">Update</button></br>
  <button type="button" id="delete-button">Delete</button></br>
  <div id="message"></div></br>
  <form action="/todoitems" action="POST">
    <fieldset class="items todo-list">
      <legend class="todo-list__title">My Special Todo List</legend>
      <% for(var i = 0; i < items.length; i++) {%>
      <label class="item todo-list__label">
        <input type="checkbox"/>
        <i class="check"></i>
        <span><%= items[i].items %></span>
      </label>
      <% } %>
    </fieldset>
  </form>
      
</body>
</html>
<!-- this is my myForm.ejs -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.0.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="myFormStyle.css">
    <title>My Form</title>
</head>
<body>
<div class="container">
    <br/>
    <br/>
    <div class="form-group">
        <form method="post">
            <div class="table table-bordered" id="item_field">
                    <h1>Todo Item 1</h1>
                    <input type="text" id="item1" class="task" cols="22" rows="2">
                    <button type="button" id="add" class="addButton">+</button></td>
            </div>
            <input type="submit" id="submit" value="Submit"/>
        </form>
    </div>
</div>
</body>
</html>
<script>
    $(document).ready(function() {
        var count = 1;
        //var $itemIds = Array.from($('h1 + .task'));
        //var ids = $itemIds.map(task => $(task).attr('id'));
        $('#add').on('click', function() {
            count++;
            $('#item_field').append('</br><h1>Todo Item ' + count +'</h1><input type="text" id="item'+ count +'" class="task" cols="22" rows="2">');
            $('#add').insertAfter('#item' + count);
        }); 
        $('#submit').on('click', function() {
            var items = [];
            for (let i = 1; i <= count; i++) {
                items.push($('#item' + i).val());
            }
        $.ajax({
            method: 'POST',
            url:'/myForm',
            type: 'POST',
            data: {
                items: items
            }
        }).
        done(function(data) {
        console.log(data);
        }).
        fail(function(error) {
        console.log(error);
        })
        })       
    });



</script>
halfer
  • 19,824
  • 17
  • 99
  • 186

1 Answers1

0

If you want to insert the items individually, iterate over the array of items and insert each one, and redirect after they have finished inserting:

    app.post('/myForm', (req, res) => {
        const itemPromises = req.body.items.map(item => {
            items.push(item);
            return itemsCollection.insertOne(item); // returns a promise
        });
        Promise.all(itemPromises)
            .then(() => res.redirect('/result')
            .catch(console.error);
    });

Also, you will have to change your $.ajax call so that the data is being sent in the format you expect:

$.ajax({
    method: 'POST',
    contentType: 'application/json',
    url:'/myForm',
    data: JSON.stringify({
        items: items
    })
})

Finally, change your form element's attributes so that the form itself does not try to submit and only the ajax call is made:

<form method="post" action="javascript:void(0)">
    <div class="table table-bordered" id="item_field">
        <h1>Todo Item 1</h1>
        <input type="text" id="item1" class="task" cols="22" rows="2">
        <button type="button" id="add" class="addButton">+</button></td>
    </div>
    <input type="submit" id="submit" value="Submit"/>
</form>

Also, as you noted, this line <span><%= items[i].items %></span> should instead be <span><%= items[i] %></span>

awarrier99
  • 3,628
  • 1
  • 12
  • 19
  • Thank you for your prompt answer! I have tried using map but it gives me "TypeError: Cannot read property 'map' of undefined" and I don't understand why. because the data is for sure stored but those data cannot be read for some reason..by the way I'm surprised you answered so fast. Thank you again! –  May 14 '20 at 00:48
  • @buzzy no problem. Can you update your answer showing the output of `console.log(req.body)` in that function so we can see what's being included? – awarrier99 May 14 '20 at 00:52
  • @buzzy actually, I just added an update that should help solve this issue – awarrier99 May 14 '20 at 00:59
  • it prints { items: [ 'item 1', 'item 2', 'item 3' ] } when i do console.log(req.body). –  May 14 '20 at 01:03
  • I typed in item 1 item2 and item 3 –  May 14 '20 at 01:03
  • I tried your updated version too but it still doesn't solve the issue :/... –  May 14 '20 at 01:07
  • @buzzy can you include the full stack trace of the error? Based on your `console.log` output, it should work just fine since `req.body.items` is defined. Although, is `req.body` printing out as a string or as an object? – awarrier99 May 14 '20 at 01:12
  • @buzzy actually just realized yet another thing haha, try with the latest update and see if that works for you – awarrier99 May 14 '20 at 01:18
  • when i do typeof(req.body) it prints "TypeError: Cannot read property 'map' of undefined" this error. –  May 14 '20 at 01:27
  • I do have app.use(express.json()) inside my mongoclient connectionString. But, i added app.use(express.json()) outside of my mongoclient connectionString too, but it still gave me same error :/.. –  May 14 '20 at 01:32
  • @buzzy can you upload this code to GitHub or something and share the link so I can take a look? – awarrier99 May 14 '20 at 01:32
  • TypeError: Cannot create property '_id' on string 'item2' (btw item2 is what i typed in ) –  May 14 '20 at 01:34
  • @buzzy yup that's the issue right there. If you can share a link to a code sandbox or GitHub repository I can try debugging the issue, but there are just too many possibilities of what it could be to mention in comments – awarrier99 May 14 '20 at 01:35
  • https://github.com/maryyu97/assignments.git this is the link to my assignment github repo. –  May 14 '20 at 01:49
  • I can't find why req.body is read as a string, not as an object.. however, when I switched from items[i].items to items[i] in "result.ejs" page, req.body was read as an object and printed [object object]. –  May 14 '20 at 01:54
  • @buzzy Ah I think I discovered the issue. Your form was double submitting to the `/myForm` endpoint, because the `form` element also has a `method="post"` attribute, so the ajax call would happen and then the form would also submit. I added an update which should fix the issue (I tested it out on my computer and it seems to work fine) – awarrier99 May 14 '20 at 02:08
  • 1
    I tested with your latest update but only the first object in the array is read and printed. also, when I click on submit from myForm.ejs page to test out, it throws "TypeError: Cannot read property 'map' of undefined" and doesn't redirect to result.ejs. When I manually go to result.ejs, only the first object was printed :( I am almost giving up now haha.. thank you so much though.. you helped me so much and I appreciate your time! –  May 14 '20 at 02:33
  • @buzzy no problem. Sorry you couldn't get it fully working though I'm wondering why because most of it seemed to work when I run it on my machine (at least the multiple objects being printed). I had the issue with the redirect not occurring either but it seems that that is a known issue when using ajax: [relevant question](https://stackoverflow.com/questions/27202075/expressjs-res-redirect-not-working-as-expected) – awarrier99 May 14 '20 at 02:59
  • it is okay! Thank you again :) I am still trying to figure out why it doesn't work. I tried on a different machine too but it still doesn't work.. –  May 14 '20 at 04:14
  • when you go to localhost:3000/myForm and add multiple items and submit, do you see any errors? –  May 14 '20 at 04:14
  • does it redirect to result page without showing you any errors? I had to go to result page manually to see if things work fine. but still..only first item gets added in result.ejs page :( –  May 14 '20 at 04:15
  • thank you for your help!!!! :) I hope you have a good day/night :D –  May 14 '20 at 04:16