how to save slider value position on refresh (sessionstorage) - javascript

So here's simple version of my curren code
<script src="main.js"></script>
<script type="text/javascript">
wwr_start();
function onSliderChanged(slider) {
wwr_req(`SET/TRACK/${slider.id}/VOL/${slider.value}`);
}
<label class="drx"> Stax </label>
<input type=range min=0 max=3 value=1 step=any id="3"
oninput="onSliderChanged(this)"
So i have about 40 slides (range input) that looks like code above. But whenever i refresh the page, the slider value get backs to default. how do i save the lastes position of slider value even if page is refreshed?
i tried to use "sessionstorage" but, since i'm pretty new at coding world, i couldn't really figure out how to use that function.
tried to copy & paste how other people used sessionstorage but couldn't adopt to my current code

Here's a simple example of how you:
On window load (i.e. the browser has loaded your page and is ready to go) it attachs an event to the slider and retrieves the slider position from session storage if it exists.
If the value is changed, it updates the sessionStorage variable.
You'll need to copy it to your own project as it's likely this example won't work here due to cross side security.
window.onload = () => {
const slider1 = document.getElementById('slider1');
// Attach listener to each slider
slider1.addEventListener('input',storeSliderPosition);
//retrieve value from sessionStorage
if(sessionStorage.slider1) { //first check if a value exists
slider1.value = sessionStorage.slider1; //if so then set the value of the slider
console.log("The stored slider value is: "+sessionStorage.slider1);
}
}
function storeSliderPosition(event) {
const id = event.target.id; //get the id of the slider we're using
sessionStorage[id] = event.target.value; //set the session storage value of the slider. Note sessionStorage['slider1'] is the same as sessionStorage.slider1
console.log(`The slider ${id} has changed and the new value is: ${sessionStorage[id]}`);
}
<input type="range" min="1" max="100" value="50" id="slider1">

Related

mirror <details> and checkbox state across iframe

I have an iFrame that loads its parent page within itself. So, two copies of the same page; one in an iFrame, one not.
I'm trying to mirror the state of <input type="checkbox"> checked/unchecked and <details> open/closed between the main page and the iFrame.
I have solved each partway (see // comments for the problems), firing on click events:
For the checkboxes, I have
let boxes = document.querySelectorAll('input[type="checkbox"]');
for (let box of boxes)) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = document.getElementById(box.id).checked; // doesn't work
}
(the condition inIFrame above is just shorthand for a test checking whether the page is loaded in an iFrame)
And for the <details>
let detailEls = document.querySelectorAll('details');
for (let i = 0; i < detailEls.length; i++) {
myIFrame.querySelectorAll('details')[i].open = querySelectorAll('details')[i].open; // works, but 1-click behind
}
But strangely, this lags one click behind. So if I click, click, click to open details A,B,C on the main page, only A,B will open in the iFrame -- and the next click, C will open.
In case it wasn't clear, here's the summary of my questions:
Why does the <details> state lag? It seems like the same strategy as for checkboxes, but the result is different.
Why does the checked state only mirror from the main page to the iFrame, but not vice versa?
Thanks!
Here is a reproduction that demonstrates the behavior you want, generally following your patterns:
https://stackblitz.com/edit/so-mirror-iframe?file=lib/script.js
It's hard to tell without your full code, but here are some things to consider:
If you're using the click event on the details, that's probably giving you the "lagging" behavior. It turns out that for details, the click event comes before its open property is updated. The one you just clicked is always read in the wrong state when your synchronizer runs.
Use the toggle event instead, this fires after the open property is updated.
Assuming its not a typo in the first code block, parent is a reference to the parent window, not its document.
Use parent.document.getElementById instead.
Ok, the logic that you use will not be able to mirror vice-versa as you would like it to, so I will make it on click bases ON BOTH WINDOW AND IFRAME
Here's my repl and here's a link(please open this in new tab)
Here's the concept:
I make arrays of the elements I want mirrored on both iframe AND window. These arrays are made in the same way so that the keys/indexes each relate to their equivalent in the separate window(window.boxes[0] is the first box in window and childWindow.boxes[0] is the first box in iframe)
Now the most important part is the async part you would see in the addEventListener blocks. you would see me awaiting a promise of a timeout that lasts 0 ms but how asynchronous functions like that work is that it would wait until it isn't blocking anything and THEN RUN. That's why it ignores that lag effect the detail bars give
window.html
<html><h2>WINDOW</h2>
<iframe id="iframe" width="500" height="300" src="/"></iframe>
<details>.</details>
<details>..</details>
<details>...</details>
<details>....</details>
<details>.....</details>
<input type="checkbox">Hm</input>
<input type="checkbox">Hmm</input>
<input type="checkbox">Hmmm</input>
<input type="checkbox">Hmmmm</input>
<input type="checkbox">Hmmmmm</input>
<script>(async()=>{
window.iframe=document.getElementById('iframe') //iframe
window.childWindow=iframe.contentWindow //window to iframe
window.waitFinish=async function(){ //needful waiting
await new Promise(r=>setTimeout(r,0))
}
window.boxes = [...document.querySelectorAll('input[type="checkbox"]')] //checkboxes
window.details = [...document.querySelectorAll('details')] //details
//wait for iframe to finish loading(if you're doing this manually by the time you begin it'd be finished loading so no worries)
await new Promise(r=>{
let s=setInterval(()=>{
if(typeof childWindow.details=="object"){
clearInterval(s); return r(1)
}
},0)
})
//window to iframe
boxes.forEach((box,index)=>{
box.addEventListener("click",async(ev)=>{
await waitFinish()
childWindow.boxes[index].checked=box.checked
})
})
details.forEach((detail,index)=>{
detail.addEventListener("click",async(ev)=>{
await waitFinish()
childWindow.details[index].open=detail.open
})
})
//iframe to window
childWindow.boxes.forEach((box,index)=>{
box.addEventListener("click",async(ev)=>{
await waitFinish()
window.boxes[index].checked=box.checked
})
})
childWindow.details.forEach((detail,index)=>{
detail.addEventListener("click",async(ev)=>{
await waitFinish()
window.details[index].open=detail.open
})
})
})()</script>
</html>
iframe.html
<html><h2>IFRAME</h2>
<i><a target="_blank" href="https://iframe-mirror.paultaylor2.repl.co">Full Page</a></i>
<details>.</details>
<details>..</details>
<details>...</details>
<details>....</details>
<details>.....</details>
<input type="checkbox">Hm</input>
<input type="checkbox">Hmm</input>
<input type="checkbox">Hmmm</input>
<input type="checkbox">Hmmmm</input>
<input type="checkbox">Hmmmmm</input>
<script>
window.boxes = [...document.querySelectorAll('input[type="checkbox"]')] //checkboxes
window.details = [...document.querySelectorAll('details')] //details
</script>
</html>
You made a tiny mistake.
Your code was:
for (let box of querySelectorAll('input[type="checkbox"]')) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = getElementById(box.id).checked; // doesn't work
}
when it needs to be
for (let box of querySelectorAll('input[type="checkbox"]')) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = document.getElementById(box.id).checked; // works now that it's fixed
}
You forgot the document object as the parent.

How to remember open/closed state of div using cookie or localStorage?

I'm trying to keep a div closed until someone clicks it then remember if it is either open or closed. Here's what I have so far:
<input id="chk1" type="button" value="Click here"/>
<div id="box1" style="display:none">
<!-- HTML STUFF HERE -->
</div>
<script>
jQuery.noConflict();
jQuery(document).ready(function($) {
$('#chk1').click(function() {
$('#box1').slideToggle('200');
localStorage.setItem('show', 'true');
});
});
</script>
It works except it doesn't remember the div open/closed state.
I would like to do it without adding any more scripts if possible.
Your problem is you're not actually checking localStorage anywhere. You also shouldn't set show to 'true', since you're trying to toggle this setting.
<script>
jQuery.noConflict();
jQuery(document).ready(function($) {
$box1 = $('#box1');
const show = JSON.parse(localStorage.getItem('show'));
if (show) {
$box1.show();
} else {
// initialize value in case it hasn't been set already
localStorage.setItem('show', false);
}
$('#chk1').click(function() {
$box1.slideToggle('200');
// toggle the boolean by negating its value
const show = JSON.parse(localStorage.getItem('show'));
localStorage.setItem('show', !show);
});
});
</script>
Note that values retrieve from local storage have to be parsed as JSON, since they're given to you as a string.
And make your life easier by always properly indenting nested blocks. Much easier to read.

Moving stripe which keeps changing value

I need to create moving stripe(I don't know how to name it) on my website. Something like this:
|--#---------|
And the # can be moved by the user from one side to another and when the bar is clicked it sends the value but it can't be done with manual requests so the user chooses the value to send. I just need some tips how I can do this. I think it can be done by flash but I don't even know what should I internet search keywords should be used to find more info about it.
As Wainage suggested, an <input> with type range is perhaps a simple solution. See an example below.
document.addEventListener('DOMContentLoaded', function() {
var slider = document.getElementById('rangeValue');
var output = document.getElementById('valueOutput');
function updateOutput() {
output.innerHTML = slider.value;
}
//set the value initially
updateOutput();
//subscribe to any change/drag - not supported by IE
slider.addEventListener('input', updateOutput);
//use change event for updates when drag is ended
slider.addEventListener('change', updateOutput);
});
<input id="rangeValue" type="range" name="rangeValue" value="3" max="10" />
<div>Value: <span id="valueOutput"></span></div>

Getting the contents of a span to change as I change a number input

I had a more complicated form working a couple of days ago, but suddenly it stopped working and I'm rubbish at saving versions, so I've taken it right back to basics, and I can't get it to work. What am I doing wrong? Am I using onInput incorrectly?
<input type="text" id="number-of-copies-value" onInput="quote()" value="500">
<span id="total-cost-value">0.00</span>
And here's the Javascript:
function quote() {
var totalcostvalue = document.getElementById("total-cost-value");
var numberofcopiesvalue = document.getElementById("number-of-copies-value").value;
var totalcost = (+numberofcopiesvalue);
totalcostvalue.innerHTML=totalcost.toFixed(2);
}
quote();
https://jsfiddle.net/tod0wusv/1/
Your HTML expects the quote() function to be globally available. Make sure that is the case.
If I change your fiddle to have quote() available on global window object like,
window.quote = function quote() {
// ...
};
the fiddle starts working again.
WORKING FIDDLE
If I create a local HTML file with your content, it works right away, which makes sense since quote() is defined on global scope.
Looks like JSfiddle executes the JavaScript in a function scope which breaks your quote() call.
If you care about browser compatibility I would suggest using the onkeydown event with a setTimeout function as described here Detecting "value" of input text field after a keydown event in the text field?
To make this work in JSFiddle, change the javascript "load type" setting in your JavaScript settings to one of the "no wrap" options.
HTML
<input type="text" id="number-of-copies-value" onkeydown="window.setTimeout(function() { quote(); }, 1)" value="500">
<span id="total-cost-value">0.00</span>
JavaScript:
function quote() {
var totalcostvalue = document.getElementById("total-cost-value");
var numberofcopiesvalue = document.getElementById("number-of-copies-value").value;
var totalcost = (+numberofcopiesvalue);
totalcostvalue.innerHTML = totalcost.toFixed(2);
}
quote();
I've updated your JSFiddle...
https://jsfiddle.net/tod0wusv/6/

reset input type=range when mouse is released

I want to make an easy shuttle-style control to control the playback speed of an external device with.
the idea: user can pull the knob to whatever speed he likes, every statuschange gets sent to the server.
and if i RELEASE the knob, i want it to go back to 0.
Should be pretty easy, so i thought.
everything works, except the release part.
how would you do that?
<input id="speed" type="range" min="-16" max="16" value="0" step="1" oninput="changeSpeed(this.value)" onmouseup="resetSpeed()"/>
function changeSpeed(speed) {
console.log(speed);
//emit to device
}
function resetSpeed() {
document.getElementById("speed").value = '0';
}
it doesn't work like this.
Am I missing something?
Thanks
You can use the onchange event-handler instead of onmouseup.

Categories