whyceewhite
whyceewhite

Reputation: 6425

How to dynamically add input rows to view and maintain value in angularjs ng-model as array item

I have a situation where I want the user to dynamically add <input> rows when they want to enter a new item. As shown below, the user clicks the "Add Input Item" button and a new input element is added where the user may add text.

enter image description here

I'm trying to associate each input element value to the model $scope.items (an array) in app.js. In my index.html, I load the $scope.items using an ng-repeat. What I do not understand is how I can get each input/row to automatically be added to & managed by the model defined as $scope.items.

Is it possible to map each input element to an ng-model that relates to the items array and, if so, how? Or, should directives be used in this situation?

The full code and runtime is on Plunker here (so that you can view the weird output).

Snippet from index.html:

<body ng-controller="MainCtrl">
  <button ng-click="addInputItem()">+ Add Input Item</button>
  <div ng-repeat="item in items">
    <input ng-model="items" type="text" value="{{item}}" size="40">
  </div>
  <pre>items = {{items | json}}</pre>
</body>

The app.js code:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.items = ['First Item', 'Second Item'];
  $scope.addInputItem = function() {
    $scope.items.push('');
  };
});

Upvotes: 0

Views: 7275

Answers (2)

Jerrad
Jerrad

Reputation: 5290

The first problem is with the binding on the input boxes. Due to the ng-repeat surrounding the input box, each input box has an item value available to bind to, and that is what your ng-model should be. You shouldn't be assigning anything to the value attribute.

<input ng-model="item.value" type="text"  size="40">

Making that change will at least get the input boxes to display the items. But typing in the boxes won't update the underlying array. That's the second problem.

The ng-repeat directive prototypically inherits the scope from your controller (read more about scope here). Since your items are primitive strings, the elements in your ng-repeat effectively get copies of the data from the controller, and typing in the boxes updates those copies, not the actual data in the controller.

To fix this, just make your items an array of objects instead of an array of strings.

$scope.items = [
  {value:'First Item'},
  {value: 'Second Item'}
];

Then you would bind your textboxes like this:

<input ng-model="item.value" type="text"  size="40">

Here's a Plunker showing how it works.

Upvotes: 2

Brocco
Brocco

Reputation: 64973

This certainly is possible, check out this updated plnkr

I updated your array to be an array of objects (not strings) with a property of text and changed your inputs to this:

<input ng-model="item.text" type="text" size="40">

Upvotes: 1

Related Questions