I'm trying to update a web app that uses the jQuery.data() function to store information. The update involves refactoring the interface so that there are separate windows for different types of information rather than using just divs on the same page. Because of the way some plugins work the code that calls them has been moved into different windows to run in the window where they are needed. However, many of the callbacks used by these plugins use .data() to find stored information, but then code that sets the data stored by .data() is in the parent window, and it does not seem to attach the data to the DOM, it stores it somewhere attached to the window, so in the child window the callbacks can no longer find the data they are looking for.
Will it work using call(parent, DOMelement.data);? And is there possibly a tidier way of dealing with this?
Thanks in advance!
Thanks for all the suggestions. This wasn't using cookies because the information doesn't need to be stored beyond the current session. All of the interaction is done via javascript, there are no server requests until you save at the end. The windows that have to communicate are all open at the same time, hence the call() suggestion. I ended up solving this using .prop in place of .data as the syntax and functionality was almost identical. This directly associates the data with the DOM on the relevant window. $_SESSION only works when each page is requested from the server.
So, if you are trying to store information that needs to be accessed by multiple windows simultaneously or without a page refresh you can use the jQuery .prop() function to attach data to the DOM. .attr() could also work, but .prop() allows you to directly access values using . notation.
The .data functions are designed to prevent circular references but they store the information somewhere that means you can't access it without using .data which stores info separately for each context.
Related
I use LocalStorage to persist some content of my Vue3 app. Today, I just write to LocalStorage any changes in the content I want to preserve and read from that contact in specific cases (an interval, or some other trigger).
The last part is not optimal because I need to have complex logic about how to make the LocalStorage → app update (LocalStorage can be updated by "something else", and this update should reflected in the app)
The solution would be to bind the content of LocalStorage with a reactive variable, which would natively bring two advantages:
any change in the variable or LocalStorage is reflected in the other one
changes are naturally persistent
Question 1: Is this something that is possible (Vue3 and a modern browser)?
Question 2: I recently heard about FileSystem which seems to be a possible alternative to LocalStorage, but I do not know it enough to assess whether it could be more suited to solve my problem?
Note: there is a similar question (How to make data from localStorage reactive in Vue js) but it does not cover Vue3 and the possible use of FileSystem. The answer is basically "it is not possible natively. I will mark it as a duplicate if this is still the case.
If I understand your question right, if you are updating localStorage at one place, it should also update on other pages.
I never tried this, but I can think of two approaches.
where you can listen to storage event https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
this has some limitations, please check.
Create an Event and attach it to the window & whenever you are updating localStorage dispatch the custom event and on listening to the custom event, fetch the data from localStorage.
As you may or may not be aware as of jQuery 1.7 the whole event system was rewritten from the ground up. The codebase is much faster and with the new .on() method there is a lot of uniformity to wiring up event handlers.
One used to be able to access the internal events data and investiate what events are registered on any given element, but recently this internal information has been hidden based on the following scenario...
It seems that the "private" data is ALWAYS stored on the .data(jQuery.expando) - For "objects" where the deletion of the object should also delete its caches this makes some sense.
In the realm of nodes however, I think we should store these "private" members in a separate (private) cache so that they don't pollute the object returned by $.fn.data()"
Although I agree with the above change to hide the internal data, I have found having access to this information can be helpful for debugging and unit testing.
What was the new way of getting the internal jquery event object in jQuery 1.7?
In jQuery 1.7, events are stored in an alternate location accessible through the internal $._data() method (but note that this method is documented as for internal use only in the source code, so use it at your own risks and be prepared for it to change or disappear in future versions of the library).
To obtain the events registered on an element, you can call $._data() on that element and examine the events property of the returned object. For example:
$("#yourElement").click(function() {
// ...
});
console.log($._data($("#yourElement")[0]).events);
I often use data-attributes to store configuration that I can't semantically markup so that the JS will behave in a certain way for those elements. Now this is fine for pages where the server renders them (dutifully filling out the data-attributes).
However, I've seen examples where the javascript writes data-attributes to save bits of data it may need later. For example, posting some data to the server. If it fails to send then storing the data in a data-attribute and providing a retry button. When the retry button is clicked it finds the appropriate data-attribute and tries again.
To me this feels dirty and expensive as I have to delve into the DOM to then dig this bit of data out, but it's also very easy for me to do.
I can see 2 alternative approaches:
One would be to either take advantage of the scoping of an anonymous Javascript function to keep a handle on the original bit of data, although this may not be possible and could perhaps lead to too much "magic".
Two, keep an object lying around that keeps a track of these things. Instead of asking the DOM for the contents of a certain data-attribute I just query my object.
I guess my assumptions are that the DOM should not be used to store arbitrary bits of state, and instead we should use simpler objects that have a single purpose. On top of that I assume that accessing the DOM is more expensive than a simpler, but specific object to keep track of things.
What do other people think with regards to, performance, clarity and ease of execution?
Your assumptions are very good! Although it's allowed and perfectly valid, it's not a good practice to store data in the DOM. Sure, it's fine if you only have one input field, but, but as the application grows, you end up with a jumbled mess of data everywhere...and as you mentioned, the DOM is SLOW.
The bigger the app, the more essential it is to separate your interests:
DOM Events -> trigger JS functions -> access Data (JS object, JS API, or AJAX API) -> process results (API call or DOM Change)
I'm a big fan of creating an API to access JS data, so you can also trigger new events upon add, delete, get, change.
I want to pass javascript object from one page to other page so anyone can tell me how to do it?
Is that possible to do so using jQuery?
Few ways
Server side postback
Have a POST form on your page and save your serialized object inside a hidden input then post it to the other page. You will be able to process that data on the server and most likely put it back somehow into the page. Either as javascript object or anything else.
Client side URL examination
Make a GET request to your other page by attaching your serialized object to URL as:
http://www.app.com/otherpage.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using Javascript.
What's in a window.name = local cross-page session
This is a special technique that's also used in a special javascript library that exposes window.name as a dictionary, so you can save many different objects into it and use it as local cross-page-session. It has some size limitations that may affect you, but check the linked page for that and test your browsers.
HTML5 local storage
HTML5 has the ability of local storage that you can use exactly for these purposes. But using it heavily depends on your browser requirements. Modern browsers support it though and data can be restored even after restarting browsers or computers...
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 current window session.
Javascript object serialization
You will of course have to use some sort of a (de)serializer on your client side in some of the upper cases. Deserializers are rather easy to find (jQuery already includes a great function $.getJSON()) and are most likely part of your current javascript library already (not to even mention eval()).
But for object to JSON string serialization I'd recommend json2.js library that's also recommended by John Resig. This library uses in-browser implemented JSON (de)serialization features if they exist or uses it's own implementation when they don't. Hence recommendation.
That is only possible if the pages exist at the same time, and one page is opened from the other so that you have a reference to the other pages windows object.
If you navigate from one page to another, they don't exist at the same time, so you can't communicate like that. You would have to serialise the object into a string that you can send along in the request, for example sending JSON in the query string.
There are different ways of persisting data, like in the query string, post data, cookies, window name or HTML5 local storage, but all those methods can only persist string values, not Javascript objects.
This is possible to do, and you have a couple of options.
Local Storage
Can be added/eddited/removed at any stage and accessed across a domain. (doesn't work natively in ie6 and ie7 however there are work arounds for that)
The Window Object
I would put a massive cavet around this not being the best solution, it's not at all secure, so only use it for things that don't need to be kept private. window.name = { "json" : "object"} which is then available in the following page in the window.name property.
I believe that the only way to pass a javascript object from one page to another is to serialize it into string and pass it in url. For example if you have object
var temp = { id: 1, value: 'test' }
you may want to use JSON-js to serialize it and pass it in for example http://mysite.com/?data=serialization. Then after you load the page you need to deserialize it via for example $.parseJSON().
If your application uses sessions, you could serialize it (as per other answers) then POST it to the server where it is stored in a session variable. In the next page, you retrieve it from the session variable.
In Javascript, normally all variables only exist in a scope that is unique to that page load. They don't persist between different pages if there is a new page load.
The exceptions to this are
Cookies.
Local storage.
Cookies are truly cross-browser but are extremely limited in terms of size. You shouldn't expect to be able to store more than 4kB of cookies for a page reliably; in fact you probably shouldn't be using any more than 1kB. Cookie data slows down the loading of every page and other request, so it should be used sparingly.
There are various types of local storage available to Javascript, but the only practical cross-browser implementation of this is HTML5 webstorage which is implemented in all modern browsers (IE8+, FF, Chrome, Safari, etc), but is notably not implemented in IE6 or IE7, if that matters.
Both these approaches store a value in the user's browser which can be made to be persistent so that it can be written to and read from by pages from the same site, even between page views (and even, often, between browser sessions or computer reboots).
I wrote a library some time ago, that can store most js objects to localstorage. For example instances of your prototype classes, with references to other objects, self references included. Bare in mind that IE support is lackluster.
Does anybody know if it is possible to serialize/deserialize dojo widget (dijit) objects to a string or some representation that can be persisted across browser sessions?
My scenario:
I have a webpage with various dijits that I would like to be able to take a "snapshot" of and restore in a new browser session so that everything is brought back up in the exact same state.
In order to do this I believe I need to serialize/restore the DOM tree of the page as well as the dijit objects. I've been able to serialize the DOM tree and am currently restoring it by replacing the contents of the HTML node of the page. When the page's DOM is restored, none of the dijits work - they are rendered correctly but you can't click any of them. I believe this is because the dojo parser has already run through the DOM when the page first loaded, and replacing the entire HTML DOM element destroys all the dijits in the dijit registry for that page.. which means the dijit classes have to be re-instantiated.
Ideally what I would like to be able to do is when I take a "snapshot", to serialize every dijit object that is contained in the dijit.registry for the page to a file, and when the session is restored, to re-construct those dijit objects and add them back to the dijit registry.
Something like:
dijit.registry.forEach(function(widget){
// Save the widget object so that it can be restored in a new browser instance?
});
Has anybody tried this or know if it's possible without writing a custom serializer?
I am not sure that I agree with the technique you are using. A better scenario would be to simply serialize the state of the data for each dijit. I know that this would be more work but you are trying to preserve the state of the data, bringing the UI along for the ride seems to be preserving unnecessary information.
That being said, the dojo parser can be called independently of page load. What you are looking for is
dojo.parser.parse();
Running that after you repopulate the innerHTML should re-parse and recreate the dijits
See this page for the full reference: http://docs.dojocampus.org/dojo/parser
Any javascript object (including dojo widgets) can be serialised into JSON using dojo.toJson(), e.g:
var deserialisedValue = dojo.toJson(myObject);
My guess is that, we can serialize and deserialize dojo widgets, but the stores (and also the type of store) on which these widgets were built, should also be serialized and deserialized.
This may involve usage of eval statements, which is considered evil. Also i think the event handlers, topics to which these widgets subscribed may not be serialized and deserialized.
If the recipient page (where the dijits will be deserialized) has the same number of widgets, the simplest solution would be to wrap everything up inside a dijit/form/Form and call valueJSON = form.get('value') to serialise and form.set('value', valueJSON) to deserialise.
For widgets inside of forms like dgrid and charts, it gets trickier. You would have to take a widget specific approach. Eg: you can easily serialise a dgrid whose values have changed, by calling a grid.save() and then a JSON.stringify (grid.get('store')).
Incase the deserialisation page can have arbitrary number of widgets, I agree with #treaint You could go about getting the type of widget via widget.get('declaredClass') \\Returns TextBox etc.
We had a similar problem, but we solved it quite easily with the form's get/set value! Its quite ingenious, it iterates over all its children, calling child.get('value') on every one of them and mixining it with it's own value.