fluffy82 Posted April 19, 2023 Share Posted April 19, 2023 Hi all, I'm trying to write a page for my genealogy website, which eventually will show a French Republican calendar, a Gregorian calendar, and highlight corresponding dates between them when selected. My PHP knowledge is limited, but I'm trying to learn as I go. Some things really don't seem clear to me. Which is why I'm asking you for any hints or tips. First step is trying to get the calendar to show as I want it to. I've included three months with 5 days each for testnig purposes. The months show up correctly, the days are "calculated" correctly, but the display won't toggle when clicking on a month. The .days div is standard "display: none", and when I select a month, the corresponding .days div should be changed into "display: block". But it doesn't. Clicking a month has no result. Any ideas why? I'm quite sure there's something wrong with the <script> but I can't figure out what... <!DOCTYPE html> <html> <head> <title>French Republican Calendar</title> <meta charset="UTF-8"> <style> .month-container { margin: 10px; } .month { display: inline-block; margin: 10px; padding: 10px; background-color: #EEE; cursor: pointer; } .days { display: none; margin-top: 10px; padding: 10px; background-color: #DDD; } .day { margin: 5px 0; font-weight: bold; } .name { margin-left: 10px; font-style: italic; } </style> </head> <body> <h1>French Republican Calendar</h1> <?php $months = array( "Vendémiaire" => array( array("1", "Raisin"), array("2", "Safran"), array("3", "Châtaigne"), array("4", "Colchique"), array("5", "Cheval") ), "Brumaire" => array( array("1", "Pomme"), array("2", "Céleri"), array("3", "Poire"), array("4", "Betterave"), array("5", "Oie") ), "Frimaire" => array( array("1", "Raiponce"), array("2", "Turneps"), array("3", "Chicorée"), array("4", "Nèfle"), array("5", "Cochon") ), ); foreach ($months as $month => $days) { echo "<div class='month-container'>"; echo "<div class='days' id='" . htmlentities($month, ENT_QUOTES, "UTF-8") . "'>"; foreach ($days as $day) { echo "<div class='day'>" . $day[0] . "<span class='name'>" . $day[1] . "</span></div>"; } echo "</div>"; echo "<div class='month' onclick='toggleDays(this)'>$month</div>"; echo "</div>"; } ?> <script> function toggleDays(el) { var days = null; var sibling = el.nextElementSibling; while (sibling) { if (sibling.classList.contains("days")) { days = sibling; break; } sibling = sibling.nextElementSibling; } if (days.style.display === "none") { days.style.display = "block"; } else { days.style.display = "none"; } } var months = document.querySelectorAll(".month"); months.forEach(function(month) { month.addEventListener("click", function() { toggleDays(this); }); }); </script> </body> </html> Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/ Share on other sites More sharing options...
cyberRobot Posted April 19, 2023 Share Posted April 19, 2023 Are you familiar with the Developer Console in your browser? The console is a good place to check for JavaScript errors. Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/#findComment-1607467 Share on other sites More sharing options...
fluffy82 Posted April 19, 2023 Author Share Posted April 19, 2023 2 hours ago, cyberRobot said: Are you familiar with the Developer Console in your browser? The console is a good place to check for JavaScript errors. Yes. The code syntax is correct. I think the problem is which code I'm using. Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/#findComment-1607476 Share on other sites More sharing options...
cyberRobot Posted April 19, 2023 Share Posted April 19, 2023 In case you're not aware, the console can also be used for debugging purposes. For example, you could add console.log() in different parts of your script to see if things are executing as expected. More information can be found here:https://developer.mozilla.org/en-US/docs/Web/API/Console/log You can also watch your "days" elements to see if they're changing to "block" or "none", as intended. 1 Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/#findComment-1607497 Share on other sites More sharing options...
gizmola Posted April 19, 2023 Share Posted April 19, 2023 18 minutes ago, cyberRobot said: In case you're not aware, the console can also be used for debugging purposes. For example, you could add console.log() in different parts of your script to see if things are executing as expected. More information can be found here:https://developer.mozilla.org/en-US/docs/Web/API/Console/log You can also watch your "days" elements to see if they're changing to "block" or "none", as intended. Great advice. And there is also a built in debugger, where you can set breakpoints in your javascript code, and step through line by line to see how variables change (or not). You use the sources tab for that. Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/#findComment-1607498 Share on other sites More sharing options...
Solution kicken Posted April 19, 2023 Solution Share Posted April 19, 2023 (edited) The main issue with your code is how you're trying to find the days element. To explain a bit, lets look at how your HTML gets rendered: <div class='month-container'> <div class='days' id='Vendémiaire'> <div class='day'>1<span class='name'>Raisin</span></div> <div class='day'>2<span class='name'>Safran</span></div> <div class='day'>3<span class='name'>Châtaigne</span></div> <div class='day'>4<span class='name'>Colchique</span></div> <div class='day'>5<span class='name'>Cheval</span></div> </div> <div class='month'>Vendémiaire</div> </div> You are attaching your click handler to the div.month element. That means in your click handler, el is going to reference that element. To try and find the days element, you are looping over the nextElementSibling property until there are no more siblings. Think about that for a moment. nextElementSibling is going to find the elements that come after the current element. What comes after div.next? Nothing. You need to be looking at the previous siblings, using prevElementSibling. Now, once you find your days element, you have another problem. You are testing if it's style.display value is equal to "none". One might think this should be true since you have applied display: none; in your css, but it's not. The reason is that the style properties on the element only refer to styles applied directly to that element via a style="" attribute, not anything inherited via css selectors. Since no direct style was applied to your element, the style.display will be the empty string, fail your condition, and you'll set it to display. On a second click, it would pass and you'd set block and your toggle would start working. Reversing the conditional would fix this double-click issue. --- Now that the issues have been pointed out, there are other things of note and also general ideas that should be applied to make this better. You have both an onclick="" attribute and an addEventListener call on your month elements. You should only have one, and the preferred method is to use addEventListener in your code and stop using the on* attributes. It should be removed, notice I didn't include it in my example html above. Your loop to find the days element is unnecessary. The way your HTML is structured, the days element will be simply el.prevElementSibling, no looping required. If you want to add other elements between your month div and the days elements, a better approach would be to use querySelector on the parent element: el.parentElement.querySelector('.days'); Dealing with style properties directly should generally be avoided if possible. Changing the applied classes is a better approach. For something like this, create another class that sets display to block which can be applied to your days element. You can then use javascript to toggle this class on and off. .days.visible { display: block; } days.classList.toggle('visible'); You can view the above suggestions implemented in this demo fiddle. Edited April 19, 2023 by kicken 1 Quote Link to comment https://forums.phpfreaks.com/topic/316158-php-beginner/#findComment-1607499 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.