When a user changes the theme, I use mainWindow.webContents.send to change a class in the DOM. I also save it in the store, under the key theme.
mainWindow.webContents.send('theme:change', theme);
store.set('theme', theme);
Then in renderer.js:
ipcRenderer.on('theme:change', (event, theme) => {
document.querySelector('body').className = `${theme}`;
});
This successfully changes the theme and saves it in the store. However, now I want that theme to load up when starting the application rather than going back to the default. To do this, in app.on('ready') I am doing this:
mainWindow.webContents.send('theme:change', store.get('theme'));
However, nothing is happening. It's like it isn't being sent. Where am I going wrong? Essentially what needs to be done is for the class in body to be changed when the application loads to the one in the store.
Figured it out. I had to put:
mainWindow.webContents.once('dom-ready', () => {
mainWindow.webContents.send('theme:change', store.get('theme'));
})
I was trying mainWindow.on('dom-ready') which is why it wasn't working.
Related
I am trying to toggle a view between grid and list view mode on my frontend HTML page. I am able to do this fine with dom and HTML classes manipulation by toggling "display: none" between two containers. However, when I go to the next product page(through pagination) or when I reload the page, the default view is the one that appears and not the one that was last toggled. Is there a way to persist the view in case a page reload or product pagination changes? thank you.
here is the dom code that achieves this :
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
});
So far I found that I have to use localStorage to achieve this. but is there a better way to do this?
Essentially what is happening is when you request something from the server, the server responds with an HTML document, and whichever scripts associated with that document is run, So whatever JS executed in the first request is not in context when the second request(paginate or reload) is made.
So you need a way to persist information across these page loads, For that, you have 3 options.
Use sessionStorage.
Use localStorage
Use Cookies.
Of the 3 above the easiest would be to use either option 1 or 2.
Replying to your comment,
Also, If I am using localStorage, What am I using to store the view state?
I'm not quite clear as to what you mean by "What you are using to store the state" If your question is about where your data is stored, you need not worry about it as this is handled by the browser. If your question is about "How" to store it you can go through the MDN docs attached in option 1 or 2. This is simply storing a key-value pair as shown in the docs
localStorage.setItem('preferedView', 'grid'); You can add this to your on click handlers as follows,
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
localStorage.setItem('preferedView', 'grid');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
localStorage.setItem('preferedView', 'list');
});
Then when loading a new page at the top of your script you can get the users preferedView(if existing) via const preferedView = localStorage.getItem('preferedView');
Here is a complete example from MDN
In order for anyone to find an answer for a similar task, thanks to #Umendra insight, I was able to solve this by using this :
function viewToggeler(viewBtn1, viewBtn2, view1, view2, viewStord) {
viewBtn2.classList.add('view__active');
viewBtn1.classList.remove('view__active');
view1.classList.add('hidden');
view2.classList.remove('hidden');
sessionStorage.setItem('preferedView', viewStord);
}
viewList.addEventListener('click', () => {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
});
viewGrid.addEventListener('click', () => {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
});
if (sessionStorage.getItem('preferedView') === 'grid') {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
} else if (sessionStorage.getItem('preferedView') === 'list') {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
}
I ended up using sessionStorage over localStorage because it empties itself on window/tab closing which might be the most desirable result. localStorage persists even after exiting the browser and opening it back.
Also, at any point someone wants to empty the sessionStorage on exit, I used :
window.addEventListener('onbeforeunload', () => {
sessionStorage.removeItem('preferedView');
});
I'm looking for a way to set the color theme of my site as the preset 'theme-dark-purple' until visitors select their preferred color theme from a menu I've created. Right now, everything works except for the piece below, that is meant to set the theme without a visitor doing it (when you load my page for the first time, the color theme disappears and everything but the images are white). I've had to put a popup warning directing new visitors to chose their theme, and it's terrible for user experience.
<script>
(function () {
const themes = ['theme-dark-purple', 'theme-light-purple', 'theme-dark-blue', 'theme-light-blue', 'theme-dark-green', 'theme-light-green', 'theme-black-gold', 'theme-light-yellow', 'theme-dark-orange', 'theme-light-orange', 'theme-dark-red', 'theme-light-red'];
if (!themes.includes(localStorage.getItem('theme'))) {
setTheme('theme-dark-purple');
}
})();
</script>
https://jsfiddle.net/emrysmayell/4av9uo2w/1/#&togetherjs=3bqlb26HNN
Your code set theme to default only if nothing is stored in the localStorage. This will set it to saved otherwise to default:
(function () {
const themes = ['theme-dark-purple', 'theme-light-purple', 'theme-dark-blue', 'theme-light-blue', 'theme-dark-green', 'theme-light-green', 'theme-black-gold', 'theme-light-yellow', 'theme-dark-orange', 'theme-light-orange', 'theme-dark-red', 'theme-light-red'];
setTheme(themes[themes.indexOf(localStorage.getItem('theme'))] || 'theme-dark-purple');
})();
The following code snippet, as provided by Snipcart's documentation for v3, does not seem to override their default text label: Continue shopping
document.addEventListener('snipcart.ready', () => {
Snipcart.api.session.setLanguage('en', {
actions: {
continue_shopping: "Go back to store"
}
});
});
I have placed the above code segment directly underneath the following...
<div hidden id="snipcart" data-api-key="[Testing API Key]"></div>
<script src="https://cdn.snipcart.com/themes/v3.0.6/default/snipcart.js"></script>
When I click to activate Snipcart's checkout modal, the default label Continue shopping remains (instead of, Go back to store).
The issue mentioned has been fixed in V3.0.10. The sample code from the question will work as-is.
There was an issue with older releases of Snipcart: if localizations are applied too early with the JS API, they'll get overridden when the localization file is loaded.
To ensure everything loads in order, you can update your code to use the Snipcart.ready promise:
document.addEventListener('snipcart.ready', () => {
Snipcart.ready.then(function() {
Snipcart.api.session.setLanguage('en', {
actions: {
continue_shopping: "Go back to store"
}
});
});
});
I have a function that grabs an element and adds the class "is-open" in order to toggle an accordion. I have put this function in my "main.js".
In my FAQ component, this function needs to be called when a user clicks the accordion bar.
My question is: How do I import this main.js file within my Gatsby.js / React project?
I tried in the index or the component itself. But it is only called once I make changes to the main.js file. Obviously, I want it to be called right away when the page loads up.
This is the function within my main.js file:
const accordionEl = document.getElementsByClassName("faq-module--accordion-title--2zVOe")
if (accordionEl.length) {
for (let i = 0; i < accordionEl.length; i++) {
accordionEl[i].addEventListener("click", function() {
this.parentNode.classList.toggle("is-open")
const panel = this.nextElementSibling
if (panel.style.maxHeight) {
panel.style.maxHeight = null
} else {
panel.style.maxHeight = `${panel.scrollHeight}px`
}
})
}
}
Like I said, I have tried to add it like so in my FAQ component:
import "../js/main..js"
I have also tried to add it in index.html with tags.
You can put this in your footer (or some place that always loads):
<script src={`path/to/main.js`}></script>
Use the path to the file of the BUILT version. So you should probably put the script in "static/js/", and you should be able to import it from there.
But this is not really how you want to use Gatsby. Gatsby is built upon React, so for the reactive JavaScript, you should really be using React. It can't predict what the state of the DOM is if you start updating it behind its back. Furthermore this should be really easy to recreate in React with a simple onClick handler.
I'm making a very basic client (ie, essentially a website) using Router5. I have my code set so that when the user clicks a button, the elements that I don't want are hidden (the class hidden is added). The elements that I want to appear have the hidden class removed. Works great. However, when I am in the non-index state and I refresh, an element from the index state reappears.
I looked in the console for debugging purposes. When I refresh, the hidden class from the index view is indeed removed, and I'm not sure why.
I'm relatively new to coding, so any help that I could get on this would be greatly appreciated.
This is my transition code. As I've said, it works when I'm going from one view to the other, but when I refresh a view that isn't index, one of the index elements reappears:
const transition = function() {
return (toState, fromState, done) => {
if (fromState) {
$(`#${fromState.name}`).addClass('hidden');
}
$(`#${toState.name}`).removeClass('hidden');
done();
};
};
Other relevant code:
const routes = router.rootNode.children.map((route) => {
return route.name;
});
const registerPaths = () => {
routes.forEach((route) => {
$(`a[href="#${route}"]`).on('click', (event) => {
event.preventDefault();
router.navigate(route);
});
});
};
$(document).ready(function () {
require('./router/index').start();
require('./router/events').registerPaths();
});
I think that's everything. Please let me know if you need to see other code in order to help.
Thanks!
The issue was that even the DEFAULT view state needed to have .hidden class in the HTML. I'm still learning more about Router!