0

My AngularJS app displays data in a table using ng-repeat. AngularJS makes a GET request, which retrieves an array. The table correctly displays the elements of the array.

The page contains a button that calls a function to modify the array. However, the table is not updated to reflect the modified array.

I have tried the following:

  • Calling $scope.apply() after the update.
  • Enclosing the update within a function passed to $scope.apply() as in $scope.apply(function...). Link
  • Using $timeout Link

None of these attempts worked. Additionally, I believe that ng-repeat calls apply() itself.

AngularJS

<script>
    var app2 = angular.module('myApp2', []);

    app2.controller('StocksController', function ($scope, $http, $timeout) {
        // When the page loads...
        // Load myData with REST GET
        $http.get("http://example.com/exWebAPI/api/Ticker/").then(function (response) {
            $scope.myData = response.data;
        });

        // Update the array
        $scope.SendData = function () {
            alert('Hello from SendData.');
            $scope.myData.splice(0, 2);
            $scope.$apply();
        };

    });
</script>

HTML

<div ng-app="myApp2" ng-controller="StocksController">
    <h2>Reportable Tickers</h2>

    <p>
        <a href="#" ng-click='AddTicker()'>Add Ticker</a>
    </p>

    <table class="table">
        <tr>
            <th>
                Symbol
            </th>
            <th></th>
        </tr>

        <tr ng-repeat="x in myData">
            <td>
                {{ x.Ticker }}
            </td>
            <td>
                <a href="#" ng-click='EditTicker(x.Ticker)'>Edit</a> |
                <a href="#" ng-click='DetailsTicker(x.Ticker)'>Details</a> |
                <a href="#" ng-click='DeleteTicker(x.Ticker)'>Delete</a>
            </td>
        </tr>

    </table>

    <hr />
    <div>

        <div ng-controller="StocksController">
            <button ng-click="SendData()">Submit</button>
            <button ng-click="QueryData()">Query Data</button>
            <hr />
        </div>
    </div>
</div>
Community
  • 1
  • 1
Jacob Quisenberry
  • 1,131
  • 3
  • 20
  • 48
  • What's your goal with splice? – Shannon Hochkins Aug 16 '16 at 23:30
  • 2
    why are you using `ng-app="myApp2" ng-controller="StocksController"` in the buttons's div – Kaushal Niraula Aug 16 '16 at 23:32
  • @KaushalNiraula I intend to remove two elements from the array, which starts with seven elements. In my example, I intend for splice to represent an arbitrary change to my model. The actual change may be more complex. – Jacob Quisenberry Aug 16 '16 at 23:32
  • @KaushalNiraula, I thought I needed to specify the `ng-app` and the `ng-controller` to ensure the functions called are the once in the specified application and controller. Removing them appears to solve the problem. Could you please explain why this might be the case in an answer, so I can accept it? – Jacob Quisenberry Aug 16 '16 at 23:43
  • You might also have defined ng-app and ng-controller somewhere in a root div which includes the table and the button. By using another ng-app and ng-controller inside the one you already defined, you are creating another instance. So, the button inside the div is inside a different instance of the module and hence different $scope. So even if you modify the data of $scope by clicking the button, it doesnt modify the $scope which is used to display the table. – Kaushal Niraula Aug 16 '16 at 23:53
  • @KaushalNiraula, I think that is exactly right. I did have `ng-app` and `ng-controller` in a root div. – Jacob Quisenberry Aug 16 '16 at 23:55

2 Answers2

5

Your issue is that you have the controller defined twice.

If you're calling the controller twice it will call a new instance of the same controller.

Meaning that the $scope you're manipulating on the button isn't the same as the $scope on the ng-repeat.

Demo of your issue: https://jsfiddle.net/U3pVM/26753/ (showing different scopes)

Remove the ng-controller attribute around the parent of the button, and wrap your whole template.

<div ng-app="myApp2" ng-controller="StocksController">
  <table class="table">
    <tr>
      <th>
        Symbol
      </th>
      <th></th>
    </tr>

    <tr ng-repeat="x in myData">
      <td>
        {{ x.Ticker }}
      </td>
      <td>
        <a href="#" ng-click='EditTicker(x.Ticker)'>Edit</a> |
        <a href="#" ng-click='DetailsTicker(x.Ticker)'>Details</a> |
        <a href="#" ng-click='DeleteTicker(x.Ticker)'>Delete</a>
      </td>
    </tr>

  </table>

  <hr />
  <div>

    <div>
      <button ng-click="SendData()">Submit</button>
      <hr />
    </div>
  </div>
</div>

Working example: https://jsfiddle.net/U3pVM/26752/

Note: I've removed the $http request inside just for demo purposes.

Additionally, seeing as you're using ng-click to with SendData there's no need to run scope.$apply(); as ng-click will trigger a new digest cycle internally.

Shannon Hochkins
  • 11,763
  • 15
  • 62
  • 95
  • Got assigned some maintenance work in Angular JS and instantiating the controller twice in the HTML bit me in the butt, thank you for this! – Sven E Feb 15 '22 at 23:01
0

You just have defined your myData variable in myApp2 module and its controller scope, However the displaying array table is out of your module scope ng-app. Surround your table html code with ng-app, It may work correctly.

Ramin Esfahani
  • 190
  • 1
  • 6