Chrome InvalidStateError while using SessionStorage - javascript

I have several expandable divs in a project I am creating and am saving their state between pages. My code is as follows and works perfectly in Firefox and IE.
On page load, get the existing saved dashboard state and open the divs that were previously saved:
$(function () {
//Load the saved dashboard state
var dashState;
if (!sessionStorage.getItem("dashState")) {
dashState = new Object({
saved: []
});
sessionStorage.setItem("dashState", JSON.stringify(dashState));
} else {
dashState = JSON.parse(sessionStorage.getItem("dashState"));
}
for (var i = 0; i < dashState.saved.length; i++) {
var currClient = $(dashState.saved[i]);
$(currClient.selector).css("display", "block");
var parent = $(currClient.selector).parent();
$(parent[0].children[0]).attr("src", "/Content/minus.ico");
$(parent[0].children[0]).attr("alt", "minus");
}
});
When a user clicks the expand button, save which div was expanded (or minimized) and add/remove it from the currently saved session.
function expandClick(clicked, target) {
var dashState = JSON.parse(sessionStorage.getItem("dashState"));
if (clicked.attr("src") == "/Content/minus.ico") {
target.css("display", "none");
clicked.attr("src", "/Content/plus.ico");
clicked.attr("alt", "plus");
//Remove from dashboard saved state
dashState.saved.pop(target);
} else {
target.css("display", "block");
clicked.attr("src", "/Content/minus.ico");
clicked.attr("alt", "minus");
//Add to dashboard saved state
dashState.saved.push(target);
}
sessionStorage.setItem("dashState", JSON.stringify(dashState));
}
Like I said, works great in Firefox and IE. My problem is Chrome. When the very last line of code executes, sessionStorage.setItem("dashState", JSON.stringify(dashState)); I get the error "Uncaught InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable." I'm confused because in the debugger, dashState has been initiated. Is this a scope problem I'm missing?

Most likely an issue occurs when you push the jQuery objects to the list and try and stringify them. It is possible that parts of the object are cleaned up by the browser as once you stringify them, they fall out of scope (though usually stringifying DOM elements results in a circular reference exception). I'd suggest trying assigning a unique ID to each element and storing that in your saved list:
dashState.saved.pop(target[0].id);
dashState.saved.push(target[0].id);

Related

How can I create a dynamic product page using HTML, CSS, and Javascript

I currently only know javascript. But the thing is I looked up how to do it and some people talk about something called localStorage. I have tried this and for some reason when I jump to a new page those variables aren't kept. Maybe I am doing something wrong? I jump to a new page via
and all I want do do is select a certain image. take that image to a new page and add it to that page.
I tried using the localStorage variables and even turning it into JSON.stringify and doing JSON.parse when trying to call the localstorage to another script. It didn't seem to work for me. Is there another solution?
This is some of my code. There are two scripts.
document.querySelectorAll(".card").forEach(item => {
item.addEventListener("click", onProductClick);
})
var div;
var productImg;
var ratingElement;
var reviewCount;
var price;
function onProductClick(){
// This took a week to find out (this.id)
// console.log(this.id);
div = document.getElementById(this.id);
productImg = div.getElementsByTagName('img')[0];
ratingElement = div.getElementsByTagName('a')[2];
reviewCount = div.getElementsByTagName('a')[3]
price = div.getElementsByTagName('a')[4];
console.log(div.getElementsByTagName('a')[4]);
var productData = [div, productImg,ratingElement,reviewCount,price];
window.localStorage.setItem("price", JSON.stringify(price));
}
function TranslateProduct(){
console.log("Hello");
}
This is script 2
var productPageImage = document.getElementById("product-image");
var myData = localStorage['productdata-local'];
var value =JSON.parse(window.localStorage.getItem('price'));
console.log(value);
// function setProductPage(img){
// if(productImg != null){
// return;
// }
// console.log(window.price);
// }
To explain my thought process on this code in the first script I have multiple images that have event listeners for a click. I wanted to Click any given image and grab all the data about it and the product. Then I wanted to move that to another script (script 2) and add it to a dynamic second page. yet I print my variables and they work on the first script and somehow don't on the second. This is my code. in the meantime I will look into cookies Thank you!
Have you tried Cookies
You can always use cookies, but you may run into their limitations. These days, cookies are not the best choice, even though they have the ability to preserve data even longer than the current window session.
or you can make a GET request to the other page by attaching your serialized object to the URL as follows:
http://www.app.com/second.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using JavaScript.
you can check this answer for more details Pass javascript object from one page to other

Toggle Jquery button: it is possible to avoid that at the reload / change of the page you have to click again the button [duplicate]

I have this HTML toggle button for my menu:
<a href="#" id="toggle_nav" class="sidebar-toggle" data-toggle="offcanvas" role="button">
How can i save the toggle state to reload it on page load
I have started off with:
$(document).ready(function() {
$("#toggle_nav").toggle(function() {
});
});
but im not sure what to use to keep the state
Like people are saying in the commends you can use html 5 web storage.
You have 2 types:
- localStorage - stores data with no expiration date
- sessionStorage - stores data for one session
how to set:
localStorage.setItem("name", "value");
How to get the value
localStorage.getItem("name");
So now can you do a simple check like:
if (localStorage.getItem("toggle") === null) {
//hide or show menu by default
//do not forget to set a htlm5 cookie
}else{
if(localStorage.getItem("toggle") == "yes"){
//code when menu is visible
}else{
//code when menu is hidden
}
}
More information here
Use a hidden field. Use JS to set this hidden field value whenever the panel is opened or closed, and to check the hidden field on pageload.
Example-
In your JS, I use one function to set which panels are open/closed and a 2nd to arrange them. This example is based on having multiple panels on your page but you can quickly change it to handle just one panel if needed.
function init() {
if ($("#hdnOpenPanels").val()) {
$(".fixPanels").click();
}
}
// Ensures that the correct panels are open on postback
$(".checkPanels").click(function () {
var checkPanel1= $("#Panel1").hasClass("in");
var checkPanel2 = $("#Panel2").hasClass("in");
var checkPanel3 = $("#Panel3").hasClass("in");
$("#hdnOpenPanels").val(checkPanel1 + "|" + checkPanel2 + "|" + checkPanel3);
});
$(".fixPanels").click(function () {
if ($("#hdnOpenPanels").val().split('|')[0] === "true") {
$("#Panel1").collapse('show');
} else {
$("#Panel1").collapse('hide');
}
if ($("#hdnOpenPanels").val().split('|')[1] === "true") {
$("#Panel2").collapse('show');
} else {
$("#Panel2").collapse('hide');
}
if ($("#hdnOpenPanels").val().split('|')[2] === "true") {
$("#Panel3").collapse('show');
} else {
$("#Panel3").collapse('hide');
}
});
Now you have two easy classes available to add to any items that will require the page to know which panels are open (.checkPanels) and also to "fix" which panels should be open (.fixPanels). If you have modals on the page they'll need to "fixPanels" when they closed (even though there may not have been a postback).
On your code-behind:
Add this to your PageLoad:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["sPanels"] != null)
{
hdnOpenPanels.Value = Session["sPanels"].ToString();
Session.Remove("sPanels");
}
if (IsPostBack){...}
else {...}
}
Finally, on any code-behind functions that will be causing a post-back affecting the panels, add this line at the bottom of the function(s):
Session["sPanels"] = hdnOpenPanels.Value;
There are any number of ways to accomplish this, including local storage, cookies, URL parameters, anchor fragments, and server-side storage.
If you need to persist the value for a user, regardless of browser, you'll need to store it on the server side as a user preference against an identified user's profile.
If you need to persist against a single browser instance, regardless of user, you can use a client-side solution like localStorage (for persistence across browser sessions) sessionStorage (for persistence within a single browser session) or cookies (which can be configured to do either).
For example, here is a solution that uses localStorage to persist the state of a toggle across page reloads and browser sessions.
This code does not run in an SO snippet, so see this Fiddle for a demo.
Javascript
var menuStateKey = "menu.toggle_nav.state";
$(document).ready(function() {
var $nav = $("nav");
var setInitialMenuState = function() {
// Note: This retrieves a String, not a Boolean.
var state = localStorage.getItem(menuStateKey) === 'true';
setNavDisplayState(state);
};
var toggleNav = function() {
var state = $nav.is(':visible');
state = !state;
localStorage.setItem(menuStateKey, state);
setNavDisplayState(state);
};
var setNavDisplayState = function(state) {
if (state) {
$nav.show();
} else {
$nav.hide();
}
};
$("#toggle_nav").click(toggleNav);
setInitialMenuState();
});
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>I am the nav</nav>
Toggle
You can extent toggle
$.prototype._toggle = $.prototype.toggle;
$.prototype.toggle = function() {
// save to localStorage
$.prototype._toggle.call(this)
}
And write code that use localStorage to start toggle
You can store toggle state in localStorage object.
// Check browser support
if (typeof(Storage) != "undefined") {
// Store
localStorage.setItem("toggleState", value);
// Retrieve
localStorage.getItem("toggleState");
} else {
"Sorry, your browser does not support Web Storage...";
}
Check out Local Storage - Dive Into HTML5
There are JQuery plugins available to facilitate this.
$.localStorage;
storage=$.localStorage;
storage.set('foo','value');
storage.get('foo');
Read more at Jquery Storage API.
Cheers !
As others explained we can use localStorage(HTML5) or else we can use cookies
Please refer this article on how to persist the data using cookies.
As this implementation requires less data to be stored in cookie. Using cookie would be the good approach for your implementation.

ReportViewer Web Form causes page to hang

I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.

Change is not displayed on page refresh while using IE8

I have written some JavaScript functions that will do 2 things when a button is clicked:
It will change the label of the button to "Deactivate" from "Activate" and vice versa.
The value of the ActiveStatus property will change to 0 from 1 and vice versa.
The code works alright and the change is displayed perfectly in Mozilla Firefox, but whenever I try display the page in IE 8, change is not displayed, although in database, the value changes perfectly.
Here are the JavaScript codes for the button click:
$(function () {
var stat = document.getElementById("stat").value;
//alert(stat);
if (stat == 1)
document.getElementById("butt").value = "Activate";
else
document.getElementById("butt").value = "Deactivate";
});
function activeStatus(ActiveStatus) {
//alert(ActiveStatus);
if (ActiveStatus == 1) {
return "Activate";
}
else
return "Deactivate";
}
function change() {
var butt = document.getElementById("butt").value;
if (butt == 'Deactivate') {
document.getElementById("butt").value = "Activate";
document.getElementById("stat").value = 1;
}
else {
document.getElementById("butt").value = "Deactivate";
document.getElementById("stat").value = 0;
}
}
Also, an exception message I'm getting whenever I'm trying to view the page in IE 8 is:
Microsoft JScript runtime error: Object doesn't support this property or method
I'm getting this error at the Country.js JavaScript file. The place where I'm getting this exception is:
var url = "/Country/GetAllCountry";
var refresh = function () {
$.getJSON(url, {}, function (data) {
self.Countries(data);
});
};
More specifically, in this line:
self.Countries(data);
None of these happen, when I try to run my application in Firefox. All these happen when I try to run my application in IE 8.
Why am I facing this problem????
EDIT-1: I solved my problem partially. The exception:
Microsoft JScript runtime error: Object doesn't support this property or method
was displayed only because 'Countries' was undefined in Country.js. Countries must be a valid observable, but it has to be declared. I simply had to add this line of code next to it, doing the declaration:
self.Countries = ko.observableArray([]);
Now the exception has disappeared, still the page is not refreshed after the button click.
The answer to this problem is in these 5 simple steps:
Select Tools >> Internet Options.
Click the Settings button in Browsing History.
Select the Every time I visit the webpage radio button.
Click OK to close the Settings dialog.
Click OK to close the Internet Options dialog.
It works perfectly now.
Courtesy: Gonzalo (https://stackoverflow.com/users/203766/gonzalo)

"Can't execute code from a freed script" in IE8 using Javascript w/Prototype

This is my first question on here so here goes....
I've got an issue in IE8 where I have a popup form (window.showDialog()) used to edit receipt information in an accounting system.
This was working fine up until I had to add more content by adding a dynamically built table of input fields. I'm getting the information back in an array, however that's where my error seems to be occurring. var pinputs = []; is what seems to be causing the issue.
js function in the popup form:
function saveForm() {
if($('user_id')){
var user_id = $F('user_id');
} else {
var user_id = 0;
}
var payments = $$('.payment');
var pinputs = [];
for(var i=0; i<payments.length; i++){
pinputs.push($F(payments[i]));
}
window.returnValue = {received_of: $F('received_of'), user_id: user_id,
note: $F('note'), work_date: $F('work_date'), payment: pinputs};
window.close();
}
js function in the parent js file:
function modifyReceiptInformation(id) {
return window.showModalDialog('mod.php?mod=receipts&mode=receipt_edit_popup&wrapper=no&receipt_id=' + id, 'Modify Receipt',"dialogWidth:600px;dialogHeight:500px");
}
I found a similar situation already on here but that was involving the calling of functions from the child form which I'm not doing here. Perhaps I didn't understand the solution? I'm not an expert with JS so any input will be helpful.
--Edit--
Forgot to also add in here that the var payments = $$('.payment'); is the array of input fields in my template file.
You're probably trying to access methods on the array returned by the popup after the popup is closed. That returned array was constructed on the popup, and is dependent on the popup still existing to be usable.
So you have a few options:
don't close the popup from within the popup script. Get your parent handler to do what it needs with the array (such as cloning it in an array of its own with [].concat(popupArray) for example), then have it close the popup.
convert your array to a string to cross the popup/parent boundary. JSON.stringify()/JSON.parse() would do the job nicely if you don't care about IE6/7. That way, you can still close the popup from within the popup script (apparently, string objects don't get that particular problem with IE.)
I had the same problem, so I wrote this handy function to work around the issue.
// The array problem is when modalDialogue return values are arrays. The array functions
// such as slice, etc... are deallocated when the modal dialogue closes. This is an IE bug.
// The easiest way to fix this is to clone yourself a new array out of the remnants of the old.
//
// #param[in] ary
// The array, which has been passed back from a modal dialogue (and is broken) to clone
// #returns
// A new, unbroken array.
function cloneArray(ary) {
var i;
var newAry = [];
for(i=0; i<ary.length; i++){
if(Object.prototype.toString.call(ary[i]) == '[object Array]') {
newAry.push(cloneArray(ary[i]));
} else{
newAry.push(ary[i]);
}
}
return newAry;
}
Then you can use it thusly:
var selectedAry = window.showModalDialog("Window.jsp", inputAry, "dialogWidth:900px; dialogHeight:700px; center:yes; resizable: yes;");
var newAry = cloneArray(selectedAry);

Categories

Resources