0

I'm trying to tackle learning Angular in a fun project and ran into a issue where I haven't been able to find the solution.

When the page loads I get data from a Web API method and put the results in vm.Locations. These results end up being shown on the page using a repeater.

Later, createLocation get's called after Google's Places API returns back specific location data (a single record). That data get's posted to a Web API method and if it's successful I push the result of that into vm.Locations.

On the initial page load, everything loads properly. Later createLocation is called and the mc.locations.length binding shows the proper updated value, however the resulting elements in the repeater never update to show the new element.

I was thinking that $scope.$apply shouldn't be necessary since the array.length appears to be resolving correctly, but I am out of ideas for the moment.

Here are the main pieces:

Page:

<div ng-controller="MapController as mc">
    <h1>Locations ({{mc.locations.length}})</h1>
     <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Address</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="location in mc.locations">
                <td>{{location.Name}}</td>
                <td>{{location.FormattedAddress}}</td>
            </tr>
        </tbody>
    </table>
</div>

Controller:

function MapController($http) {
    var vm = this;      
    var dataService = $http;        
    vm.locations = [];

     vm.createLocation = function(location) {                
            var locationData = {
                Name: location.name,
                PlaceId: location.place_id,
                FormattedAddress: location.formatted_address,
                Latitude: location.geometry.location.lat(),
                Longitude: location.geometry.location.lng()
            }

            var config = {
                headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;' }
            }

            dataService.post("api/Location/AddLocation", locationData)
            .success(function (data, status, headers, config) {
                vm.locations.push(data);                    
            })
            .error(function (data, status, header, config) {                   
                alert(status);
            });

        }

    function getAllSavedLocations() {
        dataService.get("/api/Location/GetAllLocations")
        .then(function (result) {

            angular.extend(vm.locations, result.data);                

            vm.locations.forEach(function (place) {
                bounds.extend(new google.maps.LatLng(place.Latitude, place.Longitude));
                vm.addLocationToMap(place.Name, place.Latitude, place.Longitude);
            });
        },
        function (error) {
            handleException(error);
        });
    }

    ...

}
  • did you try $scope.$apply after getting the data.? – Shubhranshu Jan 23 '17 at 10:25
  • Yeah out of desperation I made the modifications to give it a shot and it results in the following error getting thrown: https://docs.angularjs.org/error/$rootScope/inprog?p0=$digest – Sean Bogert Jan 23 '17 at 10:46
  • @SeanBogert Where did you put your $scope.$apply() statement in your code? – CrazyMac Jan 23 '17 at 10:51
  • Right after the vm.locations.push(data) line. I also tried moving it outside of the success function at the end of createLocation, which causes the error to go away. However, the UI still isn't updated. – Sean Bogert Jan 23 '17 at 10:57
  • @SeanBogert Do you mind putting this in a plunkr? – CrazyMac Jan 23 '17 at 11:04
  • I gave it a shot, but after removing the unnecessary bits and switching to hardcoded data everything binds properly :( I went ahead and tried to isolate just the adding functionality by leaving the initial dataload calls but hardcoding the data when adding a new record and calling $scope.$apply. If I put a watch on the array I can see the new record get inserted. The binding that shows the count of array items updates, however the repeater still doesn't reflect the new record. – Sean Bogert Jan 23 '17 at 22:41
  • Prior to $scope.$apply being called there is no $$hashkey on that record, but it gets added successfully afterwards which I would have assumed would result in the repeater to update. Given this problem I wondered if I could circumvent everything by changing my repeater to specify the "track by" value to a unique Id on each record, however everything continues to work as it has previously. – Sean Bogert Jan 23 '17 at 22:41
  • The `createLocation` function creates a config object and then doesn't use it. So in fact the code is posting using the default of `application/json`. Is that intentional? – georgeawg Jan 23 '17 at 23:22
  • What is the rational for using `angular.extend`? If the `getAllLocations` API is getting everything, why not just assign the data to scope? – georgeawg Jan 23 '17 at 23:24
  • Woops, fair point. I was trying a few things out with the config and forgot to remove that. As far as using angular.extend, I ran across the following post http://stackoverflow.com/questions/29849293/ng-repeat-not-updating-on-update-of-array Which eventually led to someone suggesting to try extend. I've tried assigning the values directly, as well as pushing each element one by one with the same results :( – Sean Bogert Jan 24 '17 at 02:11

1 Answers1

0

In the success callback of createLocation and in the code:

vm.locations.push(data);

Ensure data returned by your API is in the correct format and have the Name and the FormattedAddress properties. Log this data or inspect it on debugger

Faly
  • 13,291
  • 2
  • 19
  • 37