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.
Related
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!
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
My company has a customer who needs some somewhat complex asset system of self referencing elements. Think of it like a building that has the walls, made of bricks, it has a heating system with a boiler and pipes and radiators and each of these are divided into components too. Each such component, the building, the wall and it's bricks, are stored separately as instances of the asset module.
When filling out the relationship between these assets, you can use the usual pop-up selector window doodad thing, but as soon as we try searching for anything, the system suddenly starts screaming about navigating away from the page.
Now I've traced down exactly what's going on here, there's a JS function defined in src_files\include\javascript\sugar_3.js called snapshotForm that records what the popup form contains on load and then it compares this recorded value with it's state on-close or navigate away to see if it's ok to just move on or if it should throw a tantrum.
Now I can't see anywhere in the module, either sugar/custom/module/udef_asset or sugar/module/udef_asset where anything would get in the way of this snapshot, so my question is simple:
Where can I update the snapshot in a way that ensures the whole page has loaded first? Does anyone have any alternative ideas?
I've figured out the solution to my problem, it was due to a dependant dropdown in the child Create form.
The dropdown had a blank default value and thus was being snapshotted with that blank value. However, once the Sugar systems got a second glance, they realised "hey, you can't be blank, that's not allowed value considering your dependencies!" and thus changed it.
Therefore, on searching for another record, it threw the confirmation.
To find the error I ran the following in the Chrome js console:
snapshotForm(document.getElementById("form_QuickCreate_udef_asset"))
which showed me what the current snapshot would be and:
editViewSnapshots[document.getElementById("form_QuickCreate_udef_asset").id]
which showed me the original snapshot taken. I spotted the error as being in the somewhat complex string ...s_1_nameasset_statusDraftasset_imagedescriptio... where we find the asset_status = Draft bit. In the original, it didn't have the Draft there.
To fix, I could have added blank as an option to the default dependant options, but instead I set the value as default away from blank so that it would load in with the appropriate value.
This question is based on a misconception, please see this question instead.
Subject
I am trying to create some context menu options via a Google Chrome extension that allow you to modify the contents of editable fields on certain web pages. My extension works perfectly on StackOverflow, where the DOM is nice and simple, but Youtube has been giving me trouble for some time now.
Problem
Many of the editable fields on Youtube are hidden in Iframes, so if I try to access document.activeElementfrom the top frame, I get the Iframe itself.
I am trying to get around this by injecting chrome.runtime.onMessage() listeners into every page.
Then, I can presumably compare the value returned by info.frameURL in the chrome.contextMenus.onClicked() event listener in the event page, with window.location.href in the content scripts to see if the message is addressing the correct frame or not. (See this question)
The problem is that the value returned by info.frameURL does not seem to be consistent.
For example, if you go to the home page and use the main search box as the test element, sometimes the value is simply, www.youtube.com...., but other times it is plus.google.com..... or apis.google.com..... or accounts.google.com... and I am not sure why this is.
Can someone explain why the value returned by the info.frameUrl would not remain constant each time you click the same frame?
I'm making a game using JavaScript, currently I'm using window.location = "somepage.html" to perform navigation but I'm not sure if that is the correct way to do it. As I said in the title I've choosed Blank App Template so I do not have any navigator.js or something like.
Can you guys tell me the best way to do it?
Although you can use window.location to perform navigation, I'm sure you've already noticed a few of the downsides:
The transition between pages goes through a black screen, which is an artifact of how the underlying HTML rendering engine works.
You lose your script context between pages, e.g. you don't have any shared variables or namespaces, unless you use HTML5 session storage (or WinRT app data).
It's hard to wire up back buttons, e.g. you have to make sure each destination page knows what page navigated to it, and then maintain a back stack in session storage.
It's for these reasons that WinJS + navigator.js created a way to do "pages" via DOM replacement, which is the same strategy used by "single page web apps." That is, you have a div in default.html within which you load an unload DOM fragments to give the appearance of page navigation, while you don't actually ever leave the original script context of default.html. As a result, all of your in-memory variables persist across all page navigations.
The mechanics work like this: WinJS.Navigation provides an API to manage navigation and a backstack. By itself, however, all it really does is manage a backstack array and fire navigation-related events. To do the DOM replacement, something has to be listening to those events.
Those listeners are what navigator.js implements, so that's a piece of code that you can pull into any project for this purpose. Navigator.js also implements a custom control called the PageControlNavigator (usually Application.PageControlNavigator) is what implements the listeners.
That leave the mechanics of how you define your "pages." This is what the WinJS.UI.Pages API is for, and navigator.js assumes that you've defined your pages in this way. (Technically speaking, you can define your own page mechanisms for this, perhaps using the low-level WinJS.UI.Fragments API or even implementing your own from scratch. But WinJS.UI.Pages came about because everyone who approached this problem basically came up with the same solution, so the WinJS team provided one implementation that everyone can use.)
Put together then:
You define each page as an instance of WinJS.UI.Pages.PageControl, where each page is identified by its HTML file (which can load its own JS and CSS files). The JS file contains implementations of a page's methods like ready, in which you can do initialization work. You can then build out any other object structure you want.
In default.html, define a single div for the "host container" for the page rendering. This is an instance of the PageControlNavigator class that's defined in navigator.js. In its data-win-options you specify "{home: }" for the initial page that's loaded.
Whenever you want to switch to another page, call WinJS.Navigation.navigate with the identifier for the target page (namely the path to its .html file). In response, it will fire some navigating events.
In response, the PageControlNavigator's handlers for those events will load the target page's HTML into the DOM, within its div in default.html. It will then unload the previous page's DOM. When all of this gets rendered, you see a page transition--and a smooth one because we can animate the content in and out rather than go through a black screen.
In this process, the previous page control's unload method is called, and the init/load/processed/ready methods of the new page control are called.
It's not too hard to convert a blank app template into a nav template project--move your default.html/.css/.js content into a page control structure, add navigator.js to default.html (and your project), and put a PageControlNavigator into default.html. I suggest that you create a project from the nav app template for reference. Given the explanation above, you should be able to understand the structure.
For more details, refer to Chapter 3 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, where I talk about app anatomy and page navigation with plenty of code examples.