I'll start off by saying that as an avid browser (but having never posted), thanks in advance for any insight.
I am making a page for my employers code department, which needs to use dynamic dropdowns, since the amount of dropdowns fluctuates per page.
Context:
Originally we were using standard Bootstrap dropdowns, but some of the web providers our clients deal with aren't loading in bootstrap. My initial thought was to side-load it in, however, we work on templates that must work across the board for all of our clients and all of their web providers. Long story short, there were stability issues with bootstrap CSS files overriding various websites that weren't built with bootstrap in mind.
Onto the problem:
Here is my CodePen for you to view.
dropdown = () => {
const dropdown = document.getElementsByClassName("dropdown");
for (let i = 0; i < dropdown.length; i++) {
const activeDropdown = dropdown[i].id,
down = "#downChev-" + activeDropdown,
up = "#upChev-" + activeDropdown,
downIcon = document.querySelector(down),
upIcon = document.querySelector(up),
dropdownNumID = "#" + activeDropdown,
dropdownID = "#dropdown-" + activeDropdown;
if (event.target.matches(dropdownNumID)) {
if (upIcon.classList.contains("show-icon")) {
upIcon.classList.remove("show-icon");
downIcon.classList.add("show-icon");
} else if (downIcon.classList.contains("show-icon")) {
downIcon.classList.remove("show-icon");
upIcon.classList.add("show-icon");
}
document.querySelector(dropdownID).classList.toggle("dropdown-show")
}
}
}
Currently I've built out a dynamic dropdown system that utilizes ID's specific to each dropdown. The problem is that in the first loop that goes through the dropdowns to create the supporting variables, it doesn't create the activeDropdown variable and instead returns a blank variable when logged.
I've troubleshooted in multiple scenarios and have come up with the following:
On localhost and in the CodePen, the code seems to work fine. Once added to the live sites, it breaks at initializing the activeDropdown variable within the loop, returning a blank variable when logged.
If I remove the if condition right after the variables are set in the loop, and log the activeDropdown variable. It logs fine. This leads me to believe that it may be a synch issue. I then turned the if condition into its own function and added a settimeout, allowing the variables to be initialized prior to running the execution items within the new delayed function. Once that was added, the activeDropdown variable was no longer setting properly. It just returns blank when logged.
I'm not sure if my logic of execution is off, or if I've overcomplicated the entire thing. The only real goal here is to make a dynamic structure that allows my front-end dev team to add or remove model divs at will, with a simple modification to the ID's as the list grows.
It's also possible that other scripts that we don't have access to are creating the issue on the live site. However, I assume you guys will be able to find something wrong with my code lol.
It's difficult to know what's going on since your production environment is likely very different from the code pen, but I think a couple things could be happening.
1) Could be that the JavaScript is running before the entire page has loaded. Make sure your JavaScript code that is equivalent to the CodePen is loaded last on the page. (i.e. put the <script></script> tag at the very end of the document).
2) Some variables could be conflicting, since you are loading the JavaScript directly in the body of the document in the global scope. I have some general stylistic recommendations that may help you solve your problem:
From looking at your CodePen, you're using two different methods to react to click events: You have setup an event listeners with a callback on window.onclick, as well as 2) a function called dropdown that you are attaching to an onclick attribute in the HTML.
I would recommend staying away from the inline onclick attributes, and instead added an event listener to the container of the dropdown. That way your markup is not coupled to the dropdown JS, and you are listening to clicks within that container and not the whole application. You can use the same event listener for opening the dropdowns and closing dropdowns. See this stackoverflow post for more information about this.
In addition, I recommend adding a wrapping function around your code to prevent you from polluting the global scope. This function can be immediately invoked when the page loads, and will add the event listener on the container. You can read more about IIFE's here.
Here a CodePen demonstrating these two recommendations. While I don't know if this will help you solve your problem, hopefully at least you'll learn something new!
Related
I'm trying to pass the innerHTML from an event from one js file to another js file that's on a different html page. Essentially I'm trying to create that site location you see on websites. home or home > some-other-page-after-home.
My initial html has about six links. They all go to different pages that are structured exactly the same but have different names and will have different info in them. So I'm trying to use the same html for all of them and not have to make six different html pages.
So what I did was, made an event listener that grabs the word of whatever link you are on. I've logged it to the console and it works fine. This is the home of this site. The next layer of the site is one of these six pages that all look the same.
I want the page to say home > page1 or home > page2 on the next page when you click on one of the six links and I want that page1/page2 value to be the value that I get from this event listener.
I don't know if this is a practical way to approach this type of problem but it was the first idea I thought of. I have my event listener pass it's value to an object and then I have that object imported in another js file that the other html is linked to.
The problem is that when I get to the next page the object property {name: e.target.innerHTML} doesn't have a value anymore because in the context of that page e.target.innerHTML doesn't mean anything anymore. Or at least I think that's what the problem is.
Here are the scripts.
choose-forum.js
let forum = document.querySelector('.column');
export let forumInfo = {
name: ""
};
const getForumName = (e) => {
forumInfo.name = e.target.innerHTML;
console.log(forumInfo.name);
}
forum.addEventListener('mouseover', getForumName);
page2.js
import { forumInfo } from "./choose-forum.js";
let forumNav = document.querySelector('.forumNav');
const onLoad = () => {
forumNav.innerHTML = forumInfo.name;
}
window.addEventListener('load', onLoad);
logging forumInfo.name says
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener'.
I'm assuming that's because forumInfo.name is equal to the event target that is triggered by the listener on the other file.
Any one know a way around this? I also thought about making the location bar a react component but I've just recently started working with react and I haven't learned routes or how to pass info to different pages with react so I figured I'd see if I could come up with something by myself.
I figured it out. My thought as to why it wasn't working was correct. HTML is stateless and that. I found these nifty things called front end storages after trying an absurd amount of extremely convoluted things to make it work lol. I just had to rephrase my question in google to not mention imports and exports because the solution doesn't have anything to do with imports and exports.
Edit:
So basically I just stored the value that was generated by my mouseover event target in local storage. Which allowed me to access its value in another html file without using imports and exports which don't keep event information from other pages. The mouse over gets the innerHTML value of whatever it's hovering over and stores that value in local storage and then I set the site location bar in the next html page to that value in another js file. This causes problems if you just put the url into the search bar instead of clicking into it though since nothing is set to local storage. Or possibly the wrong value is set to local storage at the time that you navigate there. So I found another way that doesn't require local storages. I just put all the href values in my html to '/whatever' and then I create a get route for that path that sends the html file I have as sort of a template for all these pages. I then change the site location bar at the top of the page based on window.location by doing some manipulation and extracting just the part I need after local:host5000 and I set the value to that.
I am adding the scroll event in javascript for one of my pages. The code is like this:
document.getElementById("myProject").addEventListener("scroll", myFunction);
function myFunction() {
document.getElementById("scrollEvent").innerHTML = "These are all my projects so far";
}
So, when users start scrolling, they will see a text "These are all my projects so far".
My problem is how to stop showing this text when users move to another page.
Please help ( I am a verrrry fresh developer)
Thanks so much
A few thoughts.
Without knowing your dev environment (e.g. are you using MVC with a framework?), I will assume you are simply talking about separate/individual HTML pages.
Each HTML page can have its own javascript. Just like HTML and CSS, there is no need to have the same javascript functions on every page. (You don't have the same HTML content on every page, right?) Usually, we divide up the javascript into multiple files - some files are added to every page, some are specific to a certain page. It is easiest to have one (external) javascript file that you reference on every page, and then specific javascript code for each page - either in a second external file that is referenced, or on the HTML page inside <script>//js here</script> tags.
If the DIV with ID myProject is not on the other page, then the javascript won't do anything. However, it is not good to have broken javascript on a page, so make sure it is not included on other pages.
If you are using a framework, like CodeIgniter or ReactJS or Angular, please tell us so we can adjust our answers accordingly.
If the case is a switching between browser tabs, you can use two different events like below.
$(window).blur(function(e) {
// stop scroll event, when switching to another tab
document.getElementById("myProject").removeEventListener("scroll");
});
$(window).focus(function(e) {
// start scroll event
document.getElementById("myProject").addEventListener("scroll", myFunction);
});
I am not sure what you are actually looking for, because when user switch between tabs, he can not see the text anymore no matter there is a scroll event or not. If you are concern about performance, then the above solution would help.
I do not have any code to display as code would not help towards my question. I am wondering if there is a advanced JavaScript technique that can allow my plugin be called and ran against all items needed but without having to initialize it on every view in mb. Now the layout shared method is not what I mean. So fir example if I placed said plugin in a global scope in one he file and did a regular
$(document).ready(call plugin unit here)
Would that then be bound to every page and view so I do not need it to be added on every view or is thee some kind of event I can bind to when i initialize my plugin within the global.js file so it will be ran on any view or HTML page that the user goes to working on its elements? Kind of how using the older method event binding ".live" would handle all current items and future ones.
I am trying to find this out or find out if possible how to handle it. My plugin I'm testing with is proprietary so cannot post code here but uses the regular concept of a each loop on on elements affected. Hopefully my question has been stated with a clear goal.
Now understanding that it needs to run against any new target items that may not have been loaded prior but may come down the pipe a few page navigations away I'm not sure I can do this. Unless there is some kind of event in the global JavaScript scope I can bind to and during initialization of my plugin within the one section of code will then cause it to run against all items on what ever page is loaded. Please no rude downing with "we need to see code" as that would not affect an answer here and as mentioned the plugin cannot be publically displayed. Please helpful comments only and sorry if over complicating this and overlooking the answer. Thanks in advance.
I was working on an HTML block in Concrete5 located in the footer. I made a javascript call - can't quite remember it, but I think it was referencing either jQuery or the Google Maps API. Anyway, now the block won't display and oddly enough, I am completely unable to modify/add/remove blocks now. I'm pretty sure it is because of the javascript call it is making, but I can't modify or delete the block to fix the issue.
What am I supposed to now? I tried disabling javascript in my browser but of course that won't let me modify the blocks either.
I don't know 5.8+ that well yet, but this may be unfixable from within the UI.
If the error is in a global area, your best bet might be opening the template, changing the area name where the global area is used and displayed, and recreating it from scratch.
You'd be looking for something like this:
$a = new GlobalArea("Footer Nav");
and change the global area's name, thus creating a new one.
If that's not an option, you may have to resort to deleting (or altering) the faulty block through the API.
In my experience, the easiest way to get a blank page that has C5 bootstrapped is creating a custom Dashboard page:
It's a common task for a Concrete5 developer to create their own Dashboard pages. Dashboard pages are just single pages located inside the "single_pages/dashboard" directory. Once they're added within that location, they automatically show up in the Dashboard.
Now, as to how to edit or delete the block inside the area, I don't have a complete recipe, but this example page showing advanced area operations should get you started.
The API documentation for GlobalAreas is here, for Block here (notice the delete() / deleteBlock() methods.)
FYI although the solution marked as best works, it leaves data in the database that will stay there forever and forces you to change your area's name which might be ok once but not if it happens again and again.
Since that was an HTML block, the best way was to go to your database's interface, probably phpMyAdmin, go into the table "btContentLocal" and do a search for the faulty code you had entered in the HTML block then fix or delete it.
Like that you're back to normal, you don't leave stuff behind, and you can keep your area as it is
I was wondering if there is any way to find all the scripts associated with a particular element in web page.
That is if there is a photo, and there is two attached jquery function like on mouse over and on click, I need to get details of this functions without looking onto entire script.
One way is with a bookmarklet called Visual Event
There isn't really an easy way. I spent a few days trying to write an augmentation wrapper/extension that would track all even assignment in page and thus allow for inspection of such - the problem is that it requires tweaking for each library, and iirc wasn't useful if any native event assignment was used.
This is exactly the reason there needs to be well organized code, and remembering that "unobtrusive" doesn't mean "incomprehensible" - try to keep all your event assignments well organized and easily associated/found for a particular element.