简体   繁体   中英

How to make an Add/Remove Array of strings in AngularJS

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

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, ie 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/

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 (ie 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 )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM