Gianmarco F.
Gianmarco F.

Reputation: 800

Cannot read property 'data' of undefined on a not-even started $http.get request

I have a web application, started by a previous company, written in Angular.JS.
The application exposes a request towards the back-end (written in Node.JS+Express) to gather some data required to fill a table.
Specifically, this is the request that the application sends everytime the user enters in the page that holds the table (The config variable holds the access token).

define(['app'], function (app) {

    app.factory('AdvService', AdvService);

    AdvService.$inject = ['BasicService'];
    function AdvService(BasicService) {

      var service = angular.extend(BasicService, {});
      var $http = service.$http;
      var API = service.API
      var handleSuccess = service.handleSuccess;
      var handleError = service.handleError;
      var config = {
        params: {
            'token': JSON.parse(window.sessionStorage.getItem('session')).token
        }
      };

      service.searchByCriteria = function (criteria) {
        debugger;
        config.params.pageNumber = criteria.pageNumber;
        config.params.pageSize = criteria.pageSize;
        return $http.get(API + '/api/v2/admin/ads/getAdsByCriteria', config).then(handleSuccess, handleError);  
      };

      service.createAd = function (ad) {
        debugger;
        return $http.post(API + '/api/v2/admin/ads/insertNewAd', ad, config).then(handleSuccess, handleError);
      };

      return service;      
    }

});

handleSuccess and handleError are so defined

define(['app'], function (app) {

    app.factory('BasicService', BasicService);

    BasicService.$inject = ['CONF', '$http', '$window', '$q'];
    function BasicService(CONF, $http, $window, $q) {

        $http.defaults.headers.common['x-access-token'] = JSON.parse($window.sessionStorage.getItem('session')).token;

        return {
            $http: $http,
            API: CONF.API_URL,

            handleSuccess: function (res) {
                debugger;
                var deferred = $q.defer();
                res.data.success ? deferred.resolve(res.data) : deferred.reject(res.data.message);
                return res.data;
            },

            handleError: function (error) {
                debugger;
                return {
                    success: false,
                    message: error
                };
            }
        }

    }
})

and this is the only point of the application that calls that service

    ($scope.search = function () {
        debugger;
        AdvService.searchByCriteria($scope.searchCriteria).then(function (res) {
            debugger;
            $scope.searchRes = res.data.docs;
            //$scope.gridOptions.totalItems = res.data.total;
        }, function (err) {
            console.log(err);
        });
    })();

Being a CORS request (the front-end is at port 8010 and the back-end in another one), I see from Chrome's Network Monitoring System that the $http.get part gets executed twice, but here's my problem: even before starting handling on the back-end the first call, the front-end generates the error

angular.js:14961 TypeError: Cannot read property 'data' of undefined
    at Object.<anonymous> (ui-grid.js:3291)
    at Object.invoke (angular.js:5117)
    at $controllerInit (angular.js:11139)
    at nodeLinkFn (angular.js:10002)
    at angular.js:10410
    at processQueue (angular.js:17330)
    at angular.js:17378
    at Scope.$digest (angular.js:18515)
    at Scope.scopePrototype.$digest (hint.js:1495)
    at Scope.$apply (angular.js:18903)

and even tough the request does return data, having crashed, Angular cannot correctly render everything.
The only thing I tried was to use the Await/Async mechanism to try to wait and see what could have happened but this always resolves in the above error.
Does anybody have any clue of what's going on? I'm 100% positive that the code that I've posted here is the only one that gets called during this process and I can't honestly understand why should the process fail if both requests return data

Upvotes: 1

Views: 274

Answers (1)

Gianmarco F.
Gianmarco F.

Reputation: 800

So, as correctly pointed out by Alon Eitan in the comments, the error was somehow related with ui-grid and that, probably, it might have been that the gridOptions were not correctly called like the HTML was excepting.
IN FACT ...

HTML

<div class="alerts container-fluid" ng-controller="AdsController">
        <div class="row">
            WORK IN PROGRESS!
            <!--  <span>Pubblicità attive: <b>{{activeAdsCounter}}</b> - </span>-->
            <!-- <span>Pubblicità totali: <b>{{totalAdsCounter}}</b> - </span>-->
        </div>
        <button ng-click="openCreateNewAdModal()"><i class="material-icons">library_add</i></button>
        <div class="row">
            <div class="col-md-12">
                <h3>Pubblicità Nel Sistema</h3>
                <div class="grid" ui-grid="adsGridOptions" ui-grid-pagination
                    ui-grid-auto-resize></div>
            </div>
        </div>
    </div>


Controller

define(['app', 'moment'], function (app, moment) {

    app.controller('AdsController', AdsController);
    AdsController.$inject = ['$scope', '$mdDialog', 'AdvService'];

    function AdsController($scope, $mdDialog, AdvService) {
        debugger;
        $scope.rowHeight = 30;
        $scope.gridOptions = {
            data: 'searchRes',
            paginationPageSizes: [25, 50, 75],
            paginationPageSize: 25,
            enableSorting: true,
            enablePaginationControls: true,
            enableColumnMenus: false,
            useExternalPagination: true,
            rowHeight: $scope.rowHeight,
            columnDefs: [
                 {
                    name: 'Cliente',
                    field: 'customerName',
                }, {
                    name: 'Durata',
                    field: 'duration',
                },  {
                    name: 'Euro Spesi',
                    field: 'spentEuros',
                },  {
                    name: 'Data inserimento',
                    field: 'createdAt',
                    type: 'date',
                    width: '130',
                    cellFilter: "date:'dd-MM-yyyy'",
                },  {
                    name: 'Email Referente',
                    field: 'referralEmail',
                },  {
                    name: 'Nome Referente',
                    field: 'referralPerson',
                },  {
                    name: 'Numero Referente',
                    field: 'referralNumber',
                },
            ],
            onRegisterApi: function (gridApi) {
                $scope.gridApi = gridApi;
                $scope.gridApi.core.on.sortChanged($scope, function (grid, sortColumns) {
                    if (sortColumns[0]) {
                        console.log(sortColumns[0].sort);
                        $scope.searchCriteria.sort = {};
                        $scope.searchCriteria.sort[sortColumns[0].field] = sortColumns[0].sort.direction;
                    }
                });
                $scope.gridApi.pagination.on.paginationChanged($scope, function (pageNum, pageSize) {
                    $scope.searchCriteria.pageNumber = pageNum;
                    $scope.searchCriteria.pageSize = pageSize;
                    $scope.search();
                });
            }
        };

The controller had the options called as "gridOptions", while the HTML had them called "adsGridOptions". Changing the name to "gridOptions" to both sides solved the issue.

Thank you, Alon Eitan!

Upvotes: 1

Related Questions