How do I update a form that has multiple values in ejs + mongoose? How do I update a form that has multiple values in ejs + mongoose? mongoose mongoose

How do I update a form that has multiple values in ejs + mongoose?


1st option:

Depending on how you use the application, you might not even care about updating - you could just delete the previous educations and save new ones instead.

2nd option:

To properly update you really need some kind of an ID that you can refer to when updating, right?

You'll still need to use your for loop, you just need to insert the id hidden field.

To do that you will need to pass an object and not an only-string value. I have made my object array look like this:

var education = [    {content:'Education 1',id:1},    {content:'Education 2',id:3},    {content:'Education 3',id:5},    {content:'Education 4',id:2},];

Then you can do something like that:

<% for(var i = 0; i < education.length; i++) { %><input type="hidden" type="hidden" name="education_id" value="<%= education[i].id %>"/><input type="text" class="form-control" name="education" id="education" value="<%= education[i].content %>"><% } %>

Array will always get passed the way you have sent it to the server. In my case, I'll get this (you can see that everything's in the order that it should be):

  {education_id: [ '1', '3', '5', '2' ],  education: [ 'Education 1', 'Education 2', 'Education 3', 'Education 4' ] }

Now, let's look at the POST backend, you will need to tie everything back to an object (you don't really need to, but you can and probably should for the sake of sanity):

var education_i;var education_req = [];for(education_i=0;education_i<req.body.education.length;education_i++) {    console.log(req.body.education[education_i]);    education_req.push({        content:req.body.education[education_i],        id:req.body.education_id[education_i]    });}

A few more notes:

  • You HAVE TO check for the user of every education record. You don't want to let anyone mess with the IDs and ruin someone else's profile.
  • You should probably save the array length variable separately, outside of the loops as it might cause performance issues on very large arrays because the length is parsed on every loop iteration.


This is the way I would do it:

The model:

var User = new Schema({  education: [{ content: String }]});

The EJS/HTML:

<form id="education">  <% user.education.forEach(function(item) { %>  <input type="text" data-id="<%= item.id %>" value="<%= item.content %>" />  <% }); %>  <button type="submit">Save</button></form>

The client side javascript (JQuery):

$('#education').on('submit', function(e) {  e.preventDefault();  var data = [];  $(this)    .find('input')    .each(function() {      var $this = $(this);      // Collect the data with the id and value      data.push({        id: $this.data('id'),        value: $this.val()      });    });  $.ajax({    url: '/update-resume',    type: 'post',    data: { data: JSON.stringify(data) }  })    .done(function(data) {      if (data.success) {         // Lazy: refresh window         window.location.reload();      }    })    .fail(function() {      // Show an error or something fancy    });});

The above javascript will read the data-ids from the input and the values and put them into an array of education objects. It will then stringify the object add and the string to the key 'data'. This means that you can pull the string in the route from req.body.data and parse it.

The server side javascript/in the route:

router.post('/update-resume', function(req, res, next) {  User.findById(req.user._id, function(err, user) {    var parsed = JSON.parse(req.body.data);    // update and remove    var results = user      .education      .filter(function(item) {        return parsed.some(function(input) {          return input.id === item.id;        });      })      .map(function(item) {        var related = getRelated(item.id, parsed);        return { content: related.value };      });    // Add new items    user.education = results      .concat(parsed.reduce(function(prev, curr) {        if (!getRelated(curr.id, results)) {          prev.push({ content: curr.value });        }        return prev;      }, []));    user.save(function(err) {      if (err) return next(err);      res.json({ success: true });    });  });});

Get related helper:

var getRelated = function(id, arr) {  for (var i = 0; i < arr.length; i++) {    if (String(arr[i].id) === String(id)) return arr[i];  }};

Mongoose will automatically give your education array items an id. The above will allow you to be able to add, remove and update existing education items on the page.