TypeError: undefined is not an object


#1

I am making a page that sorts values in an array by name, and then when I click on a button “write to cookie” it should store it, then I click on sort by age and then click on a button “read from cookie” the new output should be the list that I stored when I clicked on “write to cookie” previously.

I keep getting an error when I click on “read from cookie”:

index.html :

<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            body {
                font-family: tahoma, sans-serif;
                padding: 1em;
            }
            div {
                padding: 1em;
            }

            h3 {
                margin-bottom: -0.5em;
            }

        </style>
    </head>
    <body>
        <input type="button" onclick ="sortByAge()" value="Age Sort"/>
        <input type="button" onclick ="sortByName()" value="Name Sort"/>
        <input type="button" onclick="writePerson()" value="Write List to Cookie" />
        <input type="button" onclick="readPerson()" value="Read List from Cookie" />

        <h3>Person List</h3>
        <div id="contacts"></div>

        <script src="sort.js"></script>
        <script src="CookiesWithObjects.js"></script>
        <script>

            // If you do not use this and you misspell a variable name, one is auto-declared. 
            "use strict";

            //debugger;

            function refreshPersonList() {
                var output = "";
                for (var i = 0; i < personList.length; i++) {
                    output += personList[i].name + " " + personList[i].age + "<br/>";
                }
                document.getElementById("contacts").innerHTML = output + "<br/>";
            }

            function sortByName() {
                console.log("to sort by name");
                sortByKey(personList, "name");
                refreshPersonList();
            }

            function sortByAge() {
                console.log("to sort by age");
                sortByKey(personList, "age");
                refreshPersonList();
            }

            function writePerson() {
                Cookie.setCookie("myPerson", personList, 365);
            }

            function readPerson() {
                personList = Cookie.getCookie("myPerson");
                refreshPersonList();
            }

            function MakePerson(newName, newAge) {
                var person = {};
                person.name = newName;
                person.age = newAge;
            }


            // main program 
            var personList = []; // empty array
            personList[0] = MakePerson("sally", 20);
            personList[1] = MakePerson("abe", 40);
            personList[2] = MakePerson("dave", 35);
            personList[3] = MakePerson("frank", 55);
            personList[4] = MakePerson("ellie", 15);
            personList[5] = MakePerson("debbie", 60);

            refreshPersonList();

        </script>

    </body>
</html>

CookieWithObjects.js :

var Cookie = {};

Cookie.setCookie = function (cname, cvalue, exdays) {
    if (!exdays) {
        exdays = 365;
    }
    var d = new Date();
    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
    var expires = "expires=" + d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
    console.log("cookie stored");
};

Cookie.setCookieObj = function (cname, cObj, exdays) {
    var jsonString = JSON.stringify(cObj);
    Cookie.setCookie(cname, jsonString, exdays);
};

Cookie.getCookie = function (cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) === 0) {
            return c.substring(name.length, c.length);
        }
    }
    console.log("cookie read");
    return "";
};

Cookie.getCookieObj = function (cname) {
    var jsonString = Cookie.getCookie(cname);
    if (!jsonString) {
        return null;
    }
    var obj = JSON.parse(jsonString);
    jsonString.push(obj);
    return obj;
};


#2

When we invoke a constructor we need to use the new keyword.


#3

Thank you, but now my values are showing up as undefined and when I click on the buttons it gives me an error:

TypeError: undefined is not a function (near '...array.sort...')

also when I run personList on console I get this:

> personList
< "[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"

Here is my sort.js in case:


// array is the array you want to sort
// key is the name of the property by which you want to sort (in quotes)

function sortByKey (array, getter) {
    
    /* .sort is a built-in array method provided by javaScript.
     * 
     * .sort expects you to provide a function (such as the unnamed function below)
     * that takes two elements of the array (a and b in the code below) and returns either 
     *    1 (if the first element is larger than the second) or 
     *   -1 if the second element is larger that the first, or 
     *    0 if both elements are equal.   */
    
    return array.sort(function (a, b) {  
        // a and b are two elements of the array to be compared

        /* These two lines of code extract the key property from the objects 
         * to be compared. 
         * 
         * These two lines of code use JavaScript's eval keyword that allows you 
         * to run (as code) whatever is stored inside of a string variable.     
         * Example: if the user invoked sortByKey(myList, "getName()")   then
         * the following line of code would execute a.getName() where a is an 
         * element of myList such as myList[3] */
        var akey = eval("a."+getter);
        var bkey = eval("b."+getter);

        // If the values to be compared are character, convert to lower case
        // so that it sorts characters as you would expect: "a" not larger than "A".
        if (typeof akey === "string") {
            akey = akey.toLowerCase();
        }
        if (typeof bkey === "string") {
            bkey = bkey.toLowerCase();
        }

        // If the values to be compared are numeric, make sure to compare them numerically
        // not treating the digits like characters.
        if (!isNaN(akey)) {
            akey = Number(akey);
        }
        if (!isNaN(bkey)) {
            bkey = Number(bkey);
        }

        // The meat of the function is to return -1 if the first element is < the second
        // or 1 if first element is > second element (or 0 if they are equal) - based on the 
        // key field by which you are comparing 
        var returnVal=0;
        if (akey < bkey) {
            returnVal = -1;
        } else if (akey > bkey) {
            returnVal = 1;
        } 
        
        // This is the badly documented code I replaced...
        //var returnVal = ((x < y) ? -1 : ((x > y) ? 1 : 0));
        console.log("comparing " + akey + " to " + bkey + " yields " + returnVal);
        return returnVal;
    });
}

#4

Your constructor is not returning the person object…

MakePerson

Compare to this…

MakePersonConstructor

            function MakePerson(newName, newAge) {
                var person = {};
                person.name = newName;
                person.age = newAge;
                return person;
            }

Would be the other approach but I would prefer the simple constructor approach, myself.


#5

oops I must’ve deleted the return person part but I still get the same error and when I read the cookie, the values are still undefined. Then when I click on sort again, it gives me an error. I have tried everything and I just can’t get it right…


#6

Not really sure where the issue is without delving further into the code. I’m still hung up on the use of MakePerson to return an object rather than an instance. Notice below that the constructor is Object and not MakePerson

Technically, your earlier code that did not use new was correct when there is a return value (an object) but it is a rather clunky way to create objects. At least with a constructor they will have a custom prototype object as an option going forward.


#7

Yes, that is because a constructor is able to return an object.
https://web.archive.org/web/20100216124827/http://www.gibdon.com/2008/08/javascript-constructor-return-value.html


#8

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.