0

I have the following jquery/javascript function that gets values from json data and adds them to a variable:

function get_class_classes(data) {
   var terms = data.terms, // setup shortcut data path
   classList = '';         // setup blank var to add string values to

   for (child = 0; child < terms.day.length; child++) {
       classList += terms.day[child].slug + ' ';
   }
   for (child = 0; child < terms.medium.length; child++) {
       classList += terms.medium[child].slug + ' ';
   }
   for (child = 0; child < terms.term.length; child++) {
       classList += terms.term[child].slug + ' ';
   }
   for (child = 0; child < terms.type.length; child++) {
       classList += terms.type[child].slug + ' ';
   }

   return classList;
}


Question:

Is there a cleaner way for me to set this up, meaning, condense all of those for loops into something more succinct?

Here is what I have tried:

function get_class_classes(data) {
    var terms = data.terms, // setup shortcut
    termsArray = ['day', 'medium', 'term', 'type'],
    classList = '';         // setup blank var

    for ( i=0; i < termsArray.length; i++ ) {
        var currentTerm = termsArray[i];

        for (child = 0; child < terms.currentTerm.length; child++) { // loop through each day, add term slug to daylis
            classList += terms.currentTerm[child].slug + ' ';
        }
     }

  return classList;
}

This returns the error: Uncaught TypeError: Cannot read property 'length' of undefined

I also moved the var terms = data.terms to the loop, which allowed the function to work, but classList returned filled with 'undefined' rather than the real value.

Sample of data

data is a json object, loosely formatted something the following, which I copied from the console:

terms: Object
    day: Array[2]
        0: Object
            ID: 197
            name: "Thursday"
            slug: "thursday"
        1: Object
     medium: Array[1]
        0: Object
            ID: 200
            name: "Painting"
            slug: "painting"
        /* Continues for variable amount of objects. Same is true for `term` and and `type` */

If you happen to answer and know why my method did not work, an explanation would be great to have for future reference/thought processes.

Thanks!

7
  • Can you show a sample of what data.terms looks like? Commented Dec 17, 2014 at 22:42
  • 4
    unrelated to your problem, but you are defining i and child as global variables, which is usually not what you really want to do. use var i = 0; and var child = 0; as the first statements in your for loops to declare them in the local scope. Commented Dec 17, 2014 at 22:43
  • Have you looked at underscore library? It cleans up repetitive code pretty well when used right Commented Dec 17, 2014 at 22:47
  • 3
    try terms[currentTerm].length; instead of terms.currentTerm.length Commented Dec 17, 2014 at 22:48
  • 1
    Updated with a sample of data @ChrisBaker. Commented Dec 18, 2014 at 15:14

2 Answers 2

5

Change the access of terms.currentTerm.length to be terms[currentTerm].length. That should fix your error.

Explanation

In the first iteration of the first for loop, for example, terms.currentTerm does not access terms.day. It instead accesses the property named currentTerm on your terms object. This property does not exist—terms has no property named currentTerm—and trying to access length on an object that does not exist produces an error.

If you want to access a property on terms with the same name as the value of your currentTerm variable, use bracket notation so the value of currentTerm gets used instead: terms[currentTerm]. The interpreter "reads" this as terms['day'], which is what you really want.

Sign up to request clarification or add additional context in comments.

7 Comments

This is the correct answer. As for the explanation: You can access attributes of javascript objects in two ways, either with object['key'] or with object.key. When you use terms.currentTerm is assumes 'currentTerm' is the key, which is undefined. By using terms[currentTerm] instead, it uses the variable currentTerm wich resolves to the correct key string and returns the array you are expecting.
No, it doesn't say terms.'day'. Really not. It just says terms.currentTerm which is equivalent to terms['currentTerm'].
@Bergi I thought I was the only one to notice this answer explanation makes no sense.
What is the value of currentTerm? It is 'day'. So you are in essence using 'day' as the access key by saying terms.currentTerm which is not a valid way to access the property. If you want to use 'day' as the access key you need to access it using the bracket notation. How does this not make sense?
Yes, as I wrote in my first comment it is not terms.'day' but instead terms.currentTerm with 'currentTerm' being the key that returns an undefined value. At the time I wrote this first comment there was no explanation on the answer at all, which is why I did not refer to the wrong explanation above.
|
0

Try this but I can't really test it because I have no idea what data.terms is besides an array?

function get_class_classes(data){
        var terms = data.terms,
        termsArray = ['day', 'medium', 'term', 'type']
        classList = '';

        for(var term of terms){
            for(var termType of termsArray){
                for(var child of terms[termType]){
                    classList += child.slug + ' ';
                }
            }
        }

        return classList;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.