2

I need to make a data binding to an array of strings.. I need an array of directions.

I module it this way:

JS

function ShoppingCartCtrl($scope) {
    $scope.directions = ["a", "b", "c"];
    $scope.addItem = function (item) {
        $scope.directions.push(item);
        $scope.item = "";
    };
    $scope.removeItem = function (index) {
        $scope.directions.splice(index, 1);
    };
}

HTML

<div ng-app>
    <div ng-controller="ShoppingCartCtrl">
        <br />
        <table border="1">
            <thead>
                <tr>
                    <td>directions</td>
                    <td>Remove Item</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="item in directions">
                    <td>
                        <input ng-model="item" />{{$index}}
                    </td>
                    <td>
                        <input type="button" value="Remove" ng-click="removeItem($index)" />
                    </td>
                </tr>
            </tbody>
        </table>
        <br />
        <table>
            <tr>
                <td>
                    <input type="text" ng-model="item" />
                </td>
                <td colspan="2">
                    <input type="Button" value="Add" ng-click="addItem(item)" />
                </td>
            </tr>
            <tr>
                <td>{{directions}}</td>
            </tr>
        </table>
    </div>
</div>

Everything works as it was expected, but I have a bug that I can't find. When you try to modified the values directly from the inputs, you are not allow. You write and nothing happened (THIS WAS SOLVED WITH PUTTING THE LAST VERSION OF ANGULAR IN JSFIDDLE).

Continue: Now you can modify the values, but they are not updated in the model. If anyone can help me, it would be awesome!!

You can see it working in this jsfiddle

Juan Manuel Masud
  • 684
  • 1
  • 7
  • 15

2 Answers2

6

Solution #1: bind an object's property instead of a string

You shouldn't edit item directly, but instead update an attribute of item.

See a working example here: http://jsfiddle.net/ray3whm2/15/

If you want more information you should read this article: http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/

Basically, never bind a property by itself, instead always have a dot in your bindings, i.e. item.name instead of item. This is a restriction due to javascript itself and not angularjs.

Solution #2: manually update your model

If you really need to, you can actually keep your array up to date manually by using the ng-change directive. See a working example here: http://jsfiddle.net/ray3whm2/16/

floribon
  • 19,175
  • 5
  • 54
  • 66
5

There was a problem with older versions of Angular when binding to primitives. See this SO question

So first update the version to a newer version of Angular.

ng-repeat creates a child scope. Because your item in ng-repeat="item in directions" is a primitive (i.e. a string), <input ng-model="item"> modifies the child scope. That's why you won't see the changes in the parent.

One way to address it is to create an array of objects instead of strings for this to work properly:

$scope.directions = [{d: "a"}, {d: "b"}, {d: "c"}];

Then your <input> would be:

<input ng-model="item.d" />

(Another way, I thought, would be to use ng-model=directions[$index], but for some reason it would lose focus after every keypress.

UPDATE: @PSL showed that this could work if you add track by $index)

Community
  • 1
  • 1
New Dev
  • 48,427
  • 12
  • 87
  • 129
  • It actually let me modify the inputs now, but the values in the model did not update. The data binding is not working. I've just updated the jsfiddle – Juan Manuel Masud Oct 22 '14 at 23:28