简体   繁体   中英

Angularjs: TypeError: Cannot read property _____ of undefined

I am creating a simple app to teach myself Angular, and I have the app broken into a main app.js as well as a services.js and a controllers.js.

From the services.js file, I am trying to grab data from JSON and pass it to my controller.js, and then simply spit out one of the values from the JSON into a console.log.

The weird thing is that putting in the entire data object from my service into the console spits out the entire object (sorry for the messed up formatting from the Chrome developer tools, hopefully this just gives an idea)...

console.log(questions); returns in the console:

Objectconfig: Objectdata: Array[4]0: Objectanswers: Array[4]correctAnswer: "question_1_answers_1"question: "What did Coltrane play?"__proto__: Object1: Objectanswers: Array[4]correctAnswer: "question_2_answers_2"question: "What did Miles play?"__proto__: Object__defineGetter__: function __defineGetter__() { [native code] }__defineSetter__: function __defineSetter__() { [native code] }__lookupGetter__: function __lookupGetter__() { [native code] }__lookupSetter__: function __lookupSetter__() { [native code] }constructor: function Object() { [native code] }hasOwnProperty: function hasOwnProperty() { [native code] }isPrototypeOf: function isPrototypeOf() { [native code] }propertyIsEnumerable: function propertyIsEnumerable() { [native code] }toLocaleString: function toLocaleString() { [native code] }toString: function toString() { [native code] }valueOf: function valueOf() { [native code] }get __proto__: function __proto__() { [native code] }set __proto__: function __proto__() { [native code] }2: Objectanswers: Array[4]correctAnswer: "question_3_answers_4"question: "What did Monk play?"__proto__: Object3: Objectanswers: Array[4]correctAnswer: "question_4_answers_3"question: "What did Ray Brown play?"__proto__: Objectlength: 4__proto__: Array[0]headers: function (name) {arguments: (...)get arguments: function ThrowTypeError() { [native code] }set arguments: function ThrowTypeError() { [native code] }caller: (...)get caller: function ThrowTypeError() { [native code] }set caller: function ThrowTypeError() { [native code] }length: 1name: ""prototype: Object__proto__: function Empty() {}<function scope>status: 200statusText: "OK"__proto__: Object__defineGetter__: function __defineGetter__() { [native code] }__defineSetter__: function __defineSetter__() { [native code] }__lookupGetter__: function __lookupGetter__() { [native code] }__lookupSetter__: function __lookupSetter__() { [native code] }constructor: function Object() { [native code] }hasOwnProperty: function hasOwnProperty() { [native code] }isPrototypeOf: function isPrototypeOf() { [native code] }propertyIsEnumerable: function propertyIsEnumerable() { [native code] }toLocaleString: function toLocaleString() { [native code] }toString: function toString() { [native code] }valueOf: function valueOf() { [native code] }get __proto__: function __proto__() { [native code] }set __proto__: function __proto__() { [native code] }

However, attempting to access an individual value, like:

console.log(questions[0].correctAnswer);

...gives me the following error:

TypeError: Cannot read property 'correctAnswer' of undefined at new <anonymous> (http://local.testingspace.com/js/global.js:49:33) at invoke (http://local.testingspace.com/js/lib.js:15265:17) at Object.instantiate (http://local.testingspace.com/js/lib.js:15276:23) at $get (http://local.testingspace.com/js/lib.js:18580:28) at link (http://local.testingspace.com/js/lib.js:34222:26) at nodeLinkFn (http://local.testingspace.com/js/lib.js:18010:13) at compositeLinkFn (http://local.testingspace.com/js/lib.js:17404:13) at publicLinkFn (http://local.testingspace.com/js/lib.js:17300:30) at $get.boundTranscludeFn (http://local.testingspace.com/js/lib.js:17424:21) at controllersBoundTransclude (http://local.testingspace.com/js/lib.js:18031:18) <ng-view class="ng-scope">

Taking a look at the code below, does anyone know why I might be having this issue?

Thanks!

-Doron

Here is the code in question:

app.js

(function() {

    var JazzQuiz = angular.module('JazzQuiz', ['JazzQuiz.services', 'JazzQuiz.controllers', 'ngRoute']);

    JazzQuiz.config(['$routeProvider', function($routeProvider) {

        $routeProvider
        .when('/', {
            templateUrl: '/partials/quiz.html',
            controller: 'QuizCtrl',
            resolve: {
                questions: function (quizFactory) {
                    return quizFactory.getQuestions();
                },
                responses: function (quizFactory) {
                    return quizFactory.getResponses();

                }
            }
        })
        .when('/score', {
            templateUrl: '/partials/score.html',
            controller: 'ScoreCtrl',
            resolve: {
                responses: function(quizFactory) {
                    return quizFactory.getResponses();
                }
            }
        });

        $routeProvider.otherwise({redirectTo: '/'});

    }]);

})();

services.js

var services = angular.module('JazzQuiz.services' ,[]);

services.factory('quizFactory', ['$http', function($http){
    var resp;
    resp = {
        getQuestions: function (){
            var promise = $http({
                method: 'GET',
                url: '../json/questions.json'
            })
            .success(function (data) {
                return data;
            });
            return promise;

        },
        getResponses: function (){
            var promise = $http({
                method: 'GET',
                url: '../json/submissionResponses.json'
            })
            .success(function (data) {
                return data;
            });
            return promise;
        }
    };

    return resp;
}]);

controllers.js

var ctrl = angular.module('JazzQuiz.controllers', []);

// controller that handles the display of questions and handling of answers
ctrl.controller('QuizCtrl', function ($scope, $http, $location, $rootScope, $timeout, questions, responses){

    $scope.quizContent = questions;
    $scope.quizResponses = responses;

    //this spits out the entire object in the console
    console.log(questions);

    //this gives me an error
    console.log(questions[0].correctAnswer);

    // more to come...
});

questions.json

[
        {
            "question": "What did Coltrane play?",
            "answers": [
                "saxophone",
                "trumpet",
                "guitar",
                "french horn"
            ],
            "correctAnswer": "question_1_answers_1"
        },
        {
            "question": "What did Miles play?",
            "answers": [
                "drums",
                "trumpet",
                "guitar",
                "french horn"
            ],
            "correctAnswer": "question_2_answers_2"
        },  
        {
            "question": "What did Monk play?",
            "answers": [
                "trombone",
                "tabla",
                "drums",
                "piano"
            ],
            "correctAnswer": "question_3_answers_4"
        },
        {
            "question": "What did Ray Brown play?",
            "answers": [
                "saxophone",
                "drums",
                "bass",
                "guitar"
            ],
            "correctAnswer": "question_4_answers_3"
        }                
]

Looking at your log output, I think your problem is that values returned from within a success handler of a $http request aren't returned in the promise chain, so your success handler isn't actually doing anything, and the promise value you are receiving in your controller is the entire $http response instead of just the resulting data. Try changing your service like so:

    getQuestions: function (){
        return $http({
            method: 'GET',
            url: '../json/questions.json'
        })
        .then(function (response) {
            return response.data;
        });
    },
    getResponses: function (){
        return $http({
            method: 'GET',
            url: '../json/submissionResponses.json'
        })
        .then(function (response) {
            return response.data;
        });
    }

and see if that makes the difference.

In the spirit of learning, observe that your error message is, in fact:

Cannot read property 'correctAnswer' of undefined

Note, that the expression you are evaluating is

questions[0].correctAnswer

Which means that questions is not the part that's undefined -- it's questions[0] , so either questions is:

  • an empty array (because having even a single defined element would mean that the index 0 would be populated -- disregarding some quirky corner cases)
  • an array that contains an undefined value as its first element (possible, but not likely in this case)
  • not an array at all

Armed with that and the knowledge that questions does have a defined value you can figure out the rest: your questions object has properties like "data", "headers" and "status", which indicate that it is the $http response object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM