L Becker
L Becker

Reputation: 755

How to have an object with an array of objects from form in AngularJS

I'm trying to create a 'recipe' object that contains an array of 'ingredients' and their properties when a form is submitted. I created inputs with ng-models: recipe.name, recipe.servings, recipe.ingredients[0].name, recipe.ingredients[0].amount, recipe.ingredients[1].name, recipe.ingredients[1].amount, etc. But when the form is submitted, only recipe.ingredients[0]'s properties are recorded. In my controller, I have the following:

angular.module('recipeMavenApp')
  .controller('AddRecipeCtrl', function () {
  var vm = this;
  vm.ingredientCount = 1;
  vm.recipe = {
    name: '',
    servings: 0,
    ingredients: [],
 };

vm.appendIngredient = function() {
  var newIngredientInput = angular.element('<input type="text"' +
  'ng-model="recipe.ingredients[' + vm.ingredientCount + '].name" placeholder="Ingredient name" />' +
  '<input type="number" min="0.25" max="1000" step="0.25" ng-model="recipe.ingredients[' +
  vm.ingredientCount + '].amount" placeholder="Amount"/>');   
   angular.element(document.querySelector('#ingredients')).append(newIngredientInput);
  vm.ingredientCount++;
};

vm.addRecipe = function(recipe) {
  vm.recipe = recipe;
  console.log(vm.recipe); //Testing to see what is received.
};

The form:

<form novalidate >
<div class="form-group">
  <label for="recipeName">Name of Recipe</label>
  <input type="text" ng-model="recipe.name" id="recipeName" required/>
</div>
<div class="form-group">
  <label for="recipeServings">Number of Servings</label>
  <input type="number" min="1" max="50" ng-model="recipe.servings" id="recipeServings"/>
</div>
<div class="form-group" id="ingredients">
  <label for="recipeIngredients">Ingredients</label>
  <button class="btn btn-primary btn-xs" ng-click="add.appendIngredient()">Add Ingredient</button>
  <br />
  <input type="text" ng-model="recipe.ingredients[0].name" id="recipeIngredients" placeholder="Ingredient name" />
  <input type="number" min="0.25" max="1000" step="0.25" ng-model="recipe.ingredients[0].amount" placeholder="Amount"/>
  <br/>
</div>
  <button ng-click="add.addRecipe(recipe)" class="btn btn-primary"><span class="glyphicon glyphicon-share"></span> Add Recipe</button>
</form>

How do I capture all ingredients in the recipe.ingredients array on form submit?

Upvotes: 0

Views: 153

Answers (1)

OxyDesign
OxyDesign

Reputation: 754

I tried to rewrite your code there : JSFiddle

I used ng-repeat to generate the list of ingredients (where I uses the $index for the models) to avoid any DOM manipulation in the controller :

<div ng-repeat="ingredient in recipe.ingredients">
  <input type="text" ng-model="recipe.ingredients[$index].name" placeholder="Ingredient name" />
  <input type="number" min="0.25" max="1000" step="0.25" ng-model="recipe.ingredients[$index].amount" placeholder="0"/> 
</div>

Based on the model :

$scope.recipe = {
  name: '',
  servings: 0,
  ingredients: [{
    name: '',
    amount: null
  }]
};

In the $scope.recipe.ingredients you can add how many {name:'', amount:null} as you need to show by default (you can also add a prefilled name or amount, for instance : {name:'Ingredient 1', amount:5}).

Then when I need a new ingredient I just push a new object in the $scope.ingredients array :

$scope.appendIngredient = function() {
  $scope.recipe.ingredients.push({
    name: '',
    amount: null
  });
};

Feel free to let me know if it fulfills your requirements or if you have any question.

Thanks

Upvotes: 1

Related Questions