0

i am trying to add a object in ng-repeat, as shown :

<div ng-controller="filtersController as datas">
    <table>
        <tr>
            <th>Names</th>
            <th>nos</th>
        </tr>
        <tr ng-repeat="data in datas.dataset">
            <td>{{data.name}}</td>
            <td>{{data.no}}</td>
        </tr>
    </table>

    <input type="text" ng-model="models.name" placeholder="enter name" />
    <input type="number" ng-model="models.no" placeholder="enter number" />
    <input type="button" ng-click="datas.add(models)" value="click me!!!!" />
 </div>

relevant javascript is :

    app.controller('filtersController', ['$scope', function ($scope) {
this.dataset = [{ name: "Vishesh", no: 1 },
                { name: "pqrst", no: 2 },
                { name: "uvwxyz", no: 3 }]
this.add = function (model) {
    this.dataset.push(model);
    $scope.$apply();
}}]);

Problem :

when i try to add new entries using textboxes, it will add first entry but after that i cannot add anymore entries in it, also the latest added entry changes when the values in the textboxes changes. Why is that?

Also if i change javascript like this :

app.controller('filtersController', ['$scope', function ($scope) {
this.dataset = [{ name: "Vishesh", no: 1 },
                { name: "pqrst", no: 2 },
                { name: "uvwxyz", no: 3 }]
this.add = function (names, nos) {
    this.dataset.push({ name: names, no: nos });
    $scope.$apply();
}}]);

and HTML :

    <input type="text" ng-model="name1" placeholder="enter name" />
    <input type="number" ng-model="no1" placeholder="enter number" />
    <input type="button" ng-click="datas.add(name1,no1)" value="click me!!!!" />

it adds as many entries i want and works as expected.

What is wrong with the first approach?

Vishesh
  • 112
  • 3
  • 14

2 Answers2

1

ng-model="models.name" creates an object on the scope named "models". Changes to models.name and models.no will change values within that object, but it's still a single object -- so datas.add(model) winds up pushing a reference to that single object onto this.dataset. Further changes to model will change that original object, which is already in this.dataset, because it's all references to the same object.

Your other approach works correctly because you're using separate primitives for ng-model="name1" and ng-model="no1". Here, each time datas.add(name1,no1) runs, it's pushing a newly constructed object onto this.dataset. Further changes to name1 and no1 now won't modify old data, because they're primitives, not object references, and each time you push to this.dataset you construct a new object out of those primitives.

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
  • here is some more information on this - http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs – Vishesh Feb 02 '16 at 15:49
  • How is that relevant? – Daniel Beck Feb 02 '16 at 15:50
  • it describes how prototypical inheritance works and how passing an object results in passing a reference and passing a primitive results in passing new copies to the controller. – Vishesh Feb 02 '16 at 15:52
  • I'm not sure I agree that a lengthy discussion of prototypal inheritance in the context of $scope management is a useful way to clarify that objects in javascript are passed by reference, but whatever floats your boat – Daniel Beck Feb 02 '16 at 16:13
0

When you push the model object that you pass to your add() method onto the array you are actually pushing the reference to that object and now Angular is going to use two-way data binding on it. What you need to do is first copy the model so it disassociates it from the ng-model directives in your HTML.

this.add = function(model) {
  var newModel = angular.copy(model);
  this.dataset.push(newModel);
}

Here's a Plunker: http://plnkr.co/edit/SdtSesYxb828yJyDFwws?p=preview

Lex
  • 6,758
  • 2
  • 27
  • 42