5

I have a JSON object like so:

{
  "workouts":
  [
    {
      "title": "Full Body",
      "exercises":
      [
        {
          "name": "Push Ups",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Running in Place",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "God Legs",
      "exercises":
      [
        {
          "name": "Running in Place (High Knees)",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Clams",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "Morning Stretch",
      "exercises":
      [
        {
          "name": "Downward Dog",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Face Plant",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Warrior",
          "duration": 3,
          "break": 3
        }
      ]
    }
  ]
}

I am looping through this object and creating info cards containing the title of each workout ("Full Body", "God Legs" etc).

Upon clicking one of the cards, I would like to be able to store the exercises associated with each title into a variable for further use. For example, If I click on "God Legs", I want the variable to store: "[{'name':'Running in Place (High Knees)', 'duration':3, 'break':3},{'name':'Squats', 'duration':3, 'break':3},{'name': 'Clams', 'duration':3, 'break':3}]"

Here is the code I am using to loop through the JSON data, which is stored on Firebase realtime database, and create the info cards.

JavaScript:

// Initialize Firebase.
firebase.initializeApp(config);
// Reference data.
var dbRef = firebase.database().ref().child("workouts");
// Sync with Firebase in real time.
dbRef.on("value", snap =>
{

  var workouts = snap.val();

  for (var i = 0;  i < workouts.length; i++)
  {
    //display.innerHTML = exercises[0].name;
    var routine = workouts[i].title;
    var id = "card" + i;

    var $card = ("<li><div class='card' id=" + id + "><a class='startIt' href='timer.html'>\n\
    <div class='cardInfo'><h3>" + routine + "</h3><p>10 min.</p>\n\
    </div></a><a class='cardOptions' href='overview.html'>\n\
    </a></div></li>");

    $("#cardList").append($card);
  }
});

HTML:

<ul id="cardList" class="cards"></ul>

Thanks for any help and ideas!

1
  • 2
    Possibly using underscore.js where() method - underscorejs.org/#where Commented Oct 30, 2017 at 12:01

1 Answer 1

1

You can use find

Relevant Code

workouts.find(workout => workout.title === [insert title you are looking for])

Example

const json = {
  "workouts": [{
      "title": "Full Body",
      "exercises": [{
          "name": "Push Ups",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Running in Place",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "God Legs",
      "exercises": [{
          "name": "Running in Place (High Knees)",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Clams",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "Morning Stretch",
      "exercises": [{
          "name": "Downward Dog",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Face Plant",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Warrior",
          "duration": 3,
          "break": 3
        }
      ]
    }
  ]
}

function createButton(value) {
  const button = document.createElement('button')
  button.textContent = value
  return button
}

function append(parentQuery, childNode) {
  document.querySelector(parentQuery).append(childNode)
}

// log the right object on click
function handleButtonClick(event) {
  if (event.target != event.currentTarget) {
    console.log(json.workouts.find(workout => workout.title === event.target.textContent))
  }
}

// display the buttons
json.workouts.forEach(workout => append('#workout_section', createButton(workout.title)))

// eventlistener
document.querySelector('#workout_section').addEventListener('click', handleButtonClick)
<section id="workout_section"></section>

Edit - search by HTML-Attribute

You can add HTML element an custom attribute like data-workout. Now you can use find by searching by this attribute.

// add attribute
button.setAttribute('data-workout', value)

// find attribute
json.workouts.find(workout => workout.title === event.target.dataset.workout)

const json = {
  "workouts": [{
      "title": "Full Body",
      "exercises": [{
          "name": "Push Ups",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Running in Place",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "God Legs",
      "exercises": [{
          "name": "Running in Place (High Knees)",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Clams",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "Morning Stretch",
      "exercises": [{
          "name": "Downward Dog",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Face Plant",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Warrior",
          "duration": 3,
          "break": 3
        }
      ]
    }
  ]
}

function createButton(value) {
  const button = document.createElement('button')
  button.textContent = value
  button.setAttribute('data-workout', value)
  return button
}

function append(parentQuery, childNode) {
  document.querySelector(parentQuery).append(childNode)
}

// log the right object on click
function handleButtonClick(event) {
  if (event.target != event.currentTarget) {
    console.log(json.workouts.find(workout => workout.title === event.target.dataset.workout))
  }
}

// display the buttons
json.workouts.forEach(workout => append('#workout_section', createButton(workout.title)))

// eventlistener
document.querySelector('#workout_section').addEventListener('click', handleButtonClick)
<section id="workout_section"></section>

Edit - for loop

I add data-workout="${routine}" to the div

<li>
    <div class="card" id="${id}" data-workout="${routine}">`
    [...]
</li>

and add the eventlistener on every card

$(".card").on('click', handleButtonClick)

const routines = {
  "workouts": [{
      "title": "Full Body",
      "exercises": [{
          "name": "Push Ups",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Running in Place",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "God Legs",
      "exercises": [{
          "name": "Running in Place (High Knees)",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Squats",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Clams",
          "duration": 3,
          "break": 3
        }
      ]
    },
    {
      "title": "Morning Stretch",
      "exercises": [{
          "name": "Downward Dog",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Face Plant",
          "duration": 3,
          "break": 3
        },
        {
          "name": "Warrior",
          "duration": 3,
          "break": 3
        }
      ]
    }
  ]
}

// log the right object on click
function handleButtonClick(event) {
  if (event.target != event.currentTarget) {
    console.log(routines.workouts.find(workout => workout.title === event.currentTarget.dataset.workout))
    console.log(routines.workouts)
  }
}

function appendElement(htmlString, parentQuery) {
  $(parentQuery).append(htmlString)
}

function createCardsHtmlString(id, routine) {
  return `
    <li>
      <div class="card" id="${id}" data-workout="${routine}">
        <a class="startIt" href="#">
          <div class="cardInfo">
            <h3>${routine}</h3>
            <p>10 min.</p>
          </div>
        </a>
        <a class="cardOptions" href="#"></a>
      </div>
    </li>
  `
}

for (var i = 0; i < routines.workouts.length; i++) {
  var routine = routines.workouts[i].title;
  var exercises = routines.workouts[i].exercises
  var id = "card" + i;
  $("#cardList").append(createCardsHtmlString(id, routine));
}

$(".card").on('click', handleButtonClick)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="cardList"></ul>

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

9 Comments

That's hella gorgeous. Thank you so much! Will integrate.
I was wondering if it is possible to extend your answer to cover other event targets. Like, if I click on the ".cardOptions" part, I would still like to be able to do the same thing, even though that part of the card contains no text. Is this possible?
@Brian - I add an example. Feel free to ask questions if you have to :)
that works but I am having trouble integrating it in my existing loop: It would seem that unless I use a function that passes in "value" as a parameter to create my cards (buttons in your case) that "value" does not become defined and therefore breaks my existing loop. Is there any way of defining and attaching that attribute to the cards without using that function?
The reason for this is that I rely on my existing for loop's index to add unique ids to my cards and attach other functions and attributes to them, so rewriting my entire code so far might prove problematic.
|

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.