pyuntae
pyuntae

Reputation: 832

TypeError undefined when trying to get cookie object thru arrayList

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": enter image description here

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].getName() + " " + personList[i].getAge() + "<br/>";
                }
                document.getElementById("contacts").innerHTML = output + "<br/>";
            }

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

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

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

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

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


        // main program 
        var personList = []; // empty array
        personList[0] = new MakePerson("sally", 20);
        personList[1] = new MakePerson("abe", 40);
        personList[2] = new MakePerson("dave", 35);
        personList[3] = new MakePerson("frank", 55);
        personList[4] = new MakePerson("ellie", 15);
        personList[5] = new 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;
    }
    jsonString = "(" + jsonString + ")";
    var obj = eval(jsonString);
    return obj;
};

sort.js :

// 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;
}); 
}

Upvotes: 1

Views: 607

Answers (2)

Harun Diluka Heshan
Harun Diluka Heshan

Reputation: 1256

Instead of eval() try using JSON.parse() because eval() doesn't return the object. It just evaluates it.

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

And most importantly change your constructor's getAge(), getName() methods to properties.

        function MakePerson(newName, newAge) {
            var person = {};
            person.getAge = newAge;
            person.getName = newName;
            return person;
        }

I have tested entire code on the jsFiddle.

Solution

Upvotes: 1

Medet Tleukabiluly
Medet Tleukabiluly

Reputation: 11940

You have 2 problems

Problem 1

Your MakePerson is a class, and the instance doesn't have properties
So when storing Cookie.setCookieObj("myPerson", personList, 365)
It actually stores

myPerson [{},{},{},{},{},{}]    

You need to persist properties

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

Problem 2

You return null in Cookie.getCookieObj
But you are not checking the value in refreshPersonList function

function refreshPersonList() {
    var output = "";
    if (personList && personList.length) { // <== added check
        for (var i = 0; i < personList.length; i++) {
            // change getName()/getAge() to name/age
            output += personList[i].name + " " + personList[i].age + "<br/>";
        }
        document.getElementById("contacts").innerHTML = output + "<br/>";
    }
}

Problem 3

Also Harun Diluka Heshan made good point, you must JSON.parse, not eval

Upvotes: 1

Related Questions