0

The pen is here: https://codepen.io/BradCoffield/pen/WEWXqO

I have a getJSON and inside of it I'm processing returned data and building what should get sent to the HTML using 2 .forEach

I want to pull the results of each .forEach, concatenate them and append them to an ID. But the variables aren't accessible to the outer area of the function and I don't know what to do.

$(document).ready(function () {

$.getJSON("https://api3.libcal.com/api_hours_grid.php?iid=000&format=json&weeks=1&systemTime=0&callback=?", function (json) {

    var day0 = (json.locations[0].weeks[0].Sunday);
    var day1 = (json.locations[0].weeks[0].Monday);
    var day2 = (json.locations[0].weeks[0].Tuesday);
    var day3 = (json.locations[0].weeks[0].Wednesday);
    var day4 = (json.locations[0].weeks[0].Thursday);
    var day5 = (json.locations[0].weeks[0].Friday);
    var day6 = (json.locations[0].weeks[0].Saturday);

    var days = [day0, day1, day2, day3, day4, day5];
    var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];


    dayNames.forEach(function (foo) {
        var someContent = "<li id='" + foo + '-hours'+"'><span class='day-of-week'>" + foo + ", "


    });

    days.forEach(function (element) {

        var dayDate = element.date
        var dayDay = element.rendered

        if (dayDate[5] === '0') {
            dayDate = dayDate.substr(6)
        } else {
            dayDate = dayDate.substr(5)
        }

        var moreContent = "" +  dayDate + ":</span> " + "<span class='dates'>" + dayDay + "</li>"

    });


    var forHTML = someContent + moreContent;


    $('#this-weeks-hours').append(forHTML);


});});
Brad
  • 311
  • 1
  • 4
  • 12
  • Maybe this can be done using Array.map() instead? – William Sep 05 '17 at 15:41
  • 1
    *"The pen is here"* A Stack Snippet (the `[<>]` toolbar button) **here on site** would be much better. – T.J. Crowder Sep 05 '17 at 15:41
  • 2
    At least related: [*How do JavaScript closures work?*](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) Declare the variable *outside* the callback, append to it *inside* the callback. (Also: William's point, `map` may be the better tool.) – T.J. Crowder Sep 05 '17 at 15:43
  • Didn't know about the Stack Snippet and will use it in the future. – Brad Sep 05 '17 at 15:55
  • Will definitely check out map. Especially since now that the below answer worked for me it revealed my code isn't as I'd planned lol – Brad Sep 05 '17 at 15:55

3 Answers3

2

Not 100% sure if that is what you aim for, but just declare & init the variables in the same scope as your rendering call. I modified your code to do that.

$(document).ready(function () {

    $.getJSON("https://api3.libcal.com/api_hours_grid.php?iid=587&format=json&weeks=1&systemTime=0&callback=?", function (json) {

        //content variables declared here
        ///////////////////////////////////////////
        var someContent = '';
        var moreContent = '';
        ///////////////////////////////////////////


        var day0 = (json.locations[0].weeks[0].Sunday);
        var day1 = (json.locations[0].weeks[0].Monday);
        var day2 = (json.locations[0].weeks[0].Tuesday);
        var day3 = (json.locations[0].weeks[0].Wednesday);
        var day4 = (json.locations[0].weeks[0].Thursday);
        var day5 = (json.locations[0].weeks[0].Friday);
        var day6 = (json.locations[0].weeks[0].Saturday);

        var days = [day0, day1, day2, day3, day4, day5];
        var dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];


        dayNames.forEach(function (foo) {
            someContent += "<li id='" + foo + '-hours'+"'><span class='day-of-week'>" + foo + ", "


        });

        days.forEach(function (element) {

            var dayDate = element.date
            var dayDay = element.rendered

            if (dayDate[5] === '0') {
                dayDate = dayDate.substr(6)
            } else {
                dayDate = dayDate.substr(5)
            }

            moreContent += "" +  dayDate + ":</span> " + "<span class='dates'>" + dayDay + "</li>"

        });


        var forHTML = someContent + moreContent;
        $('#this-weeks-hours').append(forHTML);


    });

});
Liam
  • 27,717
  • 28
  • 128
  • 190
i.terrible
  • 157
  • 7
  • This answer would be better if your explained exactly what you changed rather than having to play spot the difference – Liam Sep 05 '17 at 15:48
  • 2
    I've updated to show you what I mean. You change is easily missed without some kind of higlighting. Feel free to roll back if you wish – Liam Sep 05 '17 at 15:52
  • This did what I asked! But, I see now, that the output doesn't look how I'd hoped it would look. It's clear to me now why (It's outputting all of someContent and then all of moreContent) when what I wanted was a cascade someContent + moreContent over and over again. I'll think about if I can make the existing code work with some additions or if I'll have to look into some other way to do it. .map was mentioned above. Regardless, thanks. – Brad Sep 05 '17 at 15:53
  • In this case you'd need one loop, that combines and outputs both contents in each iteration. @Liam thanks for the highlight, now I get it. – i.terrible Sep 05 '17 at 15:56
2

I know this question already has an answer, but since you were not quite pleased with your own result, maybe the following is still interesting to you?

Assuming that jsn holds the response from your JSONP request, the code can be shortened to essentially the following lines:

var dates=Object.entries(jsn.locations[0].weeks[0]).map(function(val,key)
          {
             return '<li>'+key+' '+val[0]+' '+val[1].date
                    +': '+val[1].rendered+'</li>';
          })
$('#this-weeks-hours').append('<ul>'+dates.join('\n')+'</ul>');

The above code of course needs to be placed within the callback function of your getJSON() call.

See here for a working demo (without Ajax):

var jsn={"locations":[{"lid":558,
 "name":"Today's Hours:&nbsp;&nbsp;",
 "category":"library",
 "desc":"",
 "url":"http:\/\/library.francis.edu",
 "contact":"<p>For questions concerning your registration for Workshops, please email refli1@francis.edu<\/p>\r\n\r\n<p>&nbsp;<\/p>",
 "fn":"",
 "lat":"",
 "long":"",
 "color":"#980326",
 "weeks":[{"Sunday"   :{"times":{"currently_open":false,"status":"open","hours":[{"from":   "1pm","to":"11pm"}]},"date":"2017-09-03","rendered":   "1pm - 11pm"},
           "Monday"   :{"times":{"currently_open":false,"status":"open","hours":[{"from":"7:30am","to":"11pm"}]},"date":"2017-09-04","rendered":"7:30am - 11pm"},
           "Tuesday"  :{"times":{"currently_open":true, "status":"open","hours":[{"from":"7:30am","to":"11pm"}]},"date":"2017-09-05","rendered":"7:30am - 11pm"},
           "Wednesday":{"times":{"currently_open":false,"status":"open","hours":[{"from":"7:30am","to":"11pm"}]},"date":"2017-09-06","rendered":"7:30am - 11pm"},
           "Thursday" :{"times":{"currently_open":false,"status":"open","hours":[{"from":"7:30am","to":"11pm"}]},"date":"2017-09-07","rendered":"7:30am - 11pm"},
           "Friday"   :{"times":{"currently_open":false,"status":"open","hours":[{"from":"7:30am","to": "4pm"}]},"date":"2017-09-08","rendered":"7:30am - 4pm"},
           "Saturday" :{"times":{"currently_open":false,"status":"open","hours":[{"from":  "12pm","to": "5pm"}]},"date":"2017-09-09","rendered":  "12pm - 5pm"}}]
 }]};


var dates=Object.entries(jsn.locations[0].weeks[0])
          .map(function(val,key){return '<li>'+key+' '+val[0]+' '+val[1].date+': '+val[1].rendered+'</li>';})
$('#this-weeks-hours').append('<ul>'+dates.join('\n')+'</ul>');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>This week's opening hours</h2>
<div id="this-weeks-hours"></div>

No need to set up the extra arrays days or dayNames.

Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
  • This is amazing, thank you so much. Your code is currently above my paygrade lol and serves as something I can analyze and learn from. If you wouldn't mind would you speak to why you used ```Object.entries``` the way you did? Also, why not just map the whole json return? Lastly, why ```.join``` and ```(/n)``` Thank you! – Brad Sep 05 '17 at 17:16
  • I used `Object.entries()` because the Array prototype method `.map()` does not work on objects. However, you could just as well use the jquery utiliy `$.map()` with a slightly different syntax instead. The `'\n'` in the `.join()` method only serves a 'cosmetic' function. It makes the generated markup slightly easier to read for the human eye. You could just as well replace it with an empty string (`''`). – Carsten Massmann Sep 05 '17 at 19:17
0

you can use reduce to concatenate all vars. some like this:

days.reduce(function (out, element) {

    var dayDate = element.date
    var dayDay = element.rendered

    if (dayDate[5] === '0') {
        dayDate = dayDate.substr(6)
    } else {
        dayDate = dayDate.substr(5)
    }

    return out += "" +  dayDate + ":</span> " + "<span class='dates'>" + dayDay + "</li>"

}, '');

for more info check: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce?v=b

MR0
  • 164
  • 7