Reputation: 143
I'm building a simple recipe app using Node/Express. User gets a 'new recipe' HTML form, where they can click an 'add ingredient' button and add as many ingredients to the form as they need. Using jQuery, every time the plus icon is clicked, a new text input for the new ingredient is generated:
var newIngredient = $('#newIngredient').val();
ingredientCount++;
//give each ingredient a unique name based on count
var ingredientID = "ingredient_" + ingredientCount
// reset input to blank
$("#newIngredient").val("");
// add ingredient to list for user to see or edit.
$("#ingredientsList").append(
'<input class="form-control" type="text" required
name=' + ingredientID + ' value="' + newIngredient + '">')
Each ingredient added is assigned a unique name via the counter. This all works fine and when the form is submitted I get:
{
name: 'Soup',
ingredient_1: 'carrots',
ingredient_2: 'salt',
ingredient_3: 'turnips',
method: 'Throw all these ingredients together and voila, you have a terrible soup.'
}
In the backend, I want to take each of these ingredients and add them to an 'ingredients' array (because I don't think I can send an array of ingredients from the HTML form). I obviously don't want to hard code ingredients.push(req.body.ingredient_1)
, ingredients.push(req.body.ingredient_2)
etc... because the number of ingredients for each recipe will vary.
Is there a way to increment variable names? This might illustrate what I'm trying to do, though I know it obviously does not work:
ingredientsList=[];
var counter=1;
while(req.body.**"ingredient_"+counter**){
ingredientsList.push(req.body.**'ingredient_'+counter**);
counter++
}
Alternative ideas for passing dynamically created name:value pairs from an HTML form to JS backend would be welcome, but I would also like to know if it is possibly to dynamically increment parameters in the way I have tried above - req.body.parameter[i]
Thanks!
Upvotes: 0
Views: 2597
Reputation: 8538
Edit: you can accomplish this pretty easily in one line:
const DATA = {
name: 'Soup',
ingredient_1: 'carrots',
ingredient_2: 'salt',
ingredient_3: 'turnips',
method: 'Throw all these ingredients together and voila, you have a terrible soup.'
}
let i = Object.keys(DATA).filter(k => k.startsWith("ing")).map(o => DATA[o]);
console.log(i);
Instead of adding properties to your object as ingredient1
, ingredient2
, etc.. why don't you just use an array called ingredients
?
Something like this demonstrates, at a very high level, how to accomplish what you are wanting.
var RECIPE = {
name: "",
ingredients: [],
method: "",
}
$("#add-ingredient").on('click', event => {
let ingredient = $("#ingredient").val();
if (ingredient) {
RECIPE.ingredients.push(ingredient);
$("#ingredient-list").append(`<li>${ingredient}</li>`);
$("#ingredient").val("");
} else {
alert("Please enter ingredient first");
}
});
$("#submit").on('click', event => {
let name = $("#recipe-name").val();
let method = $("#recipe-method").val();
let empties = [];
if (name) { RECIPE.name = name; }
else { empties.push("recipe name"); }
if (method) { RECIPE.method = method; }
else { empties.push("recipe method"); }
if (RECIPE.ingredients.length <= 0) { empties.push("ingredients"); }
if (empties.length) { alert(`Please fill out ${empties.join(" and ")}`); }
else { alert("This is what we would post:\r\n\r\n" + JSON.stringify(RECIPE,null,2)); }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="recipe-name" type="text" placeholder="Enter Recipe Name"/>
<br />
<textarea id="recipe-method" placeholder="Enter Recipe Method"></textarea>
<br />
<input id="ingredient" type="text" placeholder="Enter Ingredient" />
<button id="add-ingredient">Add Ingredient</button>
<ul id="ingredient-list"></ul>
<br /><hr />
<button id="submit">Submit Recipe</button>
Upvotes: 0
Reputation: 8146
because I don't think I can send an array of ingredients from the HTML form
That's not true. Can I suggest to send a JSON object to a server?
This way you will be able to:
From client:
var data = {
name: 'Soup',
ingredient_1: 'carrots',
ingredient_2: 'salt',
ingredient_3: 'turnips',
method: 'Throw all these ingredients together and voila, you have a terrible soup.'
};
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
success: function(data) {
//On success do something
alert(data);
},
error: function(xhr, ajaxOptions, thrownError) {
//On error do something
}
});
... and on the server side something like:
const bodyParser = require('body-parser')
app.use(
bodyParser.urlencoded({
extended: true
})
)
app.use(bodyParser.json())
app.post('/endpoint', (req, res) => {
console.log(req.body.name) // 'Soup'
})
I hope it helps! 🙂
Upvotes: 1
Reputation: 2530
You can use string literals:
const ingredientsList = [];
var counter=1;
while(yourCondition){
ingredientsList.push(`req.body.ingredient_${counter++}`);
}
Upvotes: 0
Reputation: 1503
You can dynamically check for keys like that, as long as you are sure they are numeric. If it's possible to have ingredient_1 and ingredient_3 but no ingredient_2, then you would need to remove the break statement.
var data = {
name: 'Soup',
ingredient_1: 'carrots',
ingredient_2: 'salt',
ingredient_3: 'turnips',
method: 'Throw all these ingredients together and voila, you have a terrible soup.'
}
var ingredientsList=[];
for(var num=1; num<10000;num++){
if(!data['ingredient_'+num]){break;}
ingredientsList.push(data['ingredient_'+num]);
}
console.log(ingredientsList);
Upvotes: 1