最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AngularJSRestangular routing "Cannot set property 'route' of undefined" - Stack O

programmeradmin5浏览0评论

I have a AngularJS-based frontend using restangular to fetch records from a Django backend I've built.

I'm making a call for a client list with the following:

var app;

app = angular.module("myApp", ["restangular"]).config(function(RestangularProvider) {
  RestangularProvider.setBaseUrl("http://172.16.91.149:8000/client/v1");
  RestangularProvider.setResponseExtractor(function(response, operation) {
    return response.objects;
  });
  return RestangularProvider.setRequestSuffix("/?callback=abc123");
});

angular.module("myApp").controller("MainCtrl", function($scope, Restangular) {
  return $scope.client = Restangular.all("client").getList();
});

Chrome is showing the backend returning data with an HTTP 200:

abc123({
    "meta": {
        "limit": 20,
        "next": "/client/v1/client/?callback=abc123&limit=20&offset=20",
        "offset": 0,
        "previous": null,
        "total_count": 2
    },
    "objects": [{
        "id": 1,
        "name": "Test",
        "resource_uri": "/client/v1/client/1/"
    }, {
        "id": 2,
        "name": "Test 2",
        "resource_uri": "/client/v1/client/2/"
    }]
})

But once that happens I'm seeing the following stack trace appear in Chrome's console:

TypeError: Cannot set property 'route' of undefined
    at restangularizeBase (http://172.16.91.149:9000/components/restangular/src/restangular.js:395:56)
    at restangularizeCollection (http://172.16.91.149:9000/components/restangular/src/restangular.js:499:35)
    at http://172.16.91.149:9000/components/restangular/src/restangular.js:556:44
    at wrappedCallback (.0.7/angular.js:6846:59)
    at .0.7/angular.js:6883:26
    at Object.Scope.$eval (.0.7/angular.js:8057:28)
    at Object.Scope.$digest (.0.7/angular.js:7922:25)
    at Object.Scope.$apply (.0.7/angular.js:8143:24)
    at done (.0.7/angular.js:9170:20)
    at completeRequest (.0.7/angular.js:9333:7) angular.js:5754

I did a breakpoint on line 395 in in restangular.js:

L394    function restangularizeBase(parent, elem, route) {
L395        elem[config.restangularFields.route] = route;

The first time it hits the breakpoint elem is just an object and route has the value of client.

The second time the breakpoint is hit elem is undefined and route has the value of client.

Any ideas why elem would be undefined the second time around?

I have a AngularJS-based frontend using restangular to fetch records from a Django backend I've built.

I'm making a call for a client list with the following:

var app;

app = angular.module("myApp", ["restangular"]).config(function(RestangularProvider) {
  RestangularProvider.setBaseUrl("http://172.16.91.149:8000/client/v1");
  RestangularProvider.setResponseExtractor(function(response, operation) {
    return response.objects;
  });
  return RestangularProvider.setRequestSuffix("/?callback=abc123");
});

angular.module("myApp").controller("MainCtrl", function($scope, Restangular) {
  return $scope.client = Restangular.all("client").getList();
});

Chrome is showing the backend returning data with an HTTP 200:

abc123({
    "meta": {
        "limit": 20,
        "next": "/client/v1/client/?callback=abc123&limit=20&offset=20",
        "offset": 0,
        "previous": null,
        "total_count": 2
    },
    "objects": [{
        "id": 1,
        "name": "Test",
        "resource_uri": "/client/v1/client/1/"
    }, {
        "id": 2,
        "name": "Test 2",
        "resource_uri": "/client/v1/client/2/"
    }]
})

But once that happens I'm seeing the following stack trace appear in Chrome's console:

TypeError: Cannot set property 'route' of undefined
    at restangularizeBase (http://172.16.91.149:9000/components/restangular/src/restangular.js:395:56)
    at restangularizeCollection (http://172.16.91.149:9000/components/restangular/src/restangular.js:499:35)
    at http://172.16.91.149:9000/components/restangular/src/restangular.js:556:44
    at wrappedCallback (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:6846:59)
    at http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:6883:26
    at Object.Scope.$eval (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:8057:28)
    at Object.Scope.$digest (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:7922:25)
    at Object.Scope.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:8143:24)
    at done (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:9170:20)
    at completeRequest (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:9333:7) angular.js:5754

I did a breakpoint on line 395 in in restangular.js:

L394    function restangularizeBase(parent, elem, route) {
L395        elem[config.restangularFields.route] = route;

The first time it hits the breakpoint elem is just an object and route has the value of client.

The second time the breakpoint is hit elem is undefined and route has the value of client.

Any ideas why elem would be undefined the second time around?

Share Improve this question edited Jun 25, 2013 at 8:16 Mark L asked Jun 25, 2013 at 8:04 Mark LMark L 13.4k4 gold badges29 silver badges42 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 19

When requesting lists, Restangular expects the data from the server to be a simple array. However, if the resulting data is wrapped with result metadata, such as pagination info, it falls apart.

If you are using Django REST Framework, it will return results wrapped like this:

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "name": "Foo"
        },
        {
            "id": 2,
            "name": "Bar"
        }
    ]
}

To translate this, you need to create a response extractor function. It's easiest to specify in the module config:

angular.module('myApp', ['myApp.controllers', 'restangular']).
config(function(RestangularProvider) {
    RestangularProvider.setBaseUrl("/api");

    // This function is used to map the JSON data to something Restangular
    // expects
    RestangularProvider.setResponseExtractor(function(response, operation, what, url) {
        if (operation === "getList") {
            // Use results as the return type, and save the result metadata
            // in _resultmeta
            var newResponse = response.results;
            newResponse._resultmeta = {
                "count": response.count,
                "next": response.next,
                "previous": response.previous
            };
            return newResponse;
        }

        return response;
    });
});

This rearranges the results to be a simple array, with an additional property of _resultmeta, containing the metadata. Restangular will do it's thing with the array, and it's objects, and you can access the _resultmeta property when handling the array as you would expect.

I'm the creator of Restangular.

The restangularizeBase function is called first for your collection and then for each of your elements.

From the StackTrace, the element is OK, but once the collection is sent to restangularizeBase, it's actually undefined. Could you please console.log response.objects? Also, please update to the latest version.

Also, for the default request parameter, you should be using defaultRequestParams instead of the requestSuffix. requestSuffix should only be used for the ending "/"

Let me know if I can help you some more!

发布评论

评论列表(0)

  1. 暂无评论