Move elements to iframe's parent with data and events - javascript

this is the situation.
I have a complex UI inside an iframe in which a user can perform several actions before submitting. During the process, the user can switch to another page (in the iframe) and come back. That means 2 postbacks inside the iframe.
Obviously, I don't want the user to lose everything but since all the actions have been done on the client-side, I can't reload the previous state from the server.
So now, I'm trying to move the first page content to the iframe parent and put it back in place when we come back. I'm half way there since the elements show back in the page but they lose their data attributes and event handlers.
I'm using this to move the content on the parent :
$("#resp").clone(true).attr("id", "refillResp").appendTo(window.top.$("#global"));
And this to put it back :
window.top.$("#global").find("#refillResp").clone(true).attr("id", "resp").appendTo($("#tdResp"));
Is there anyone who knows a way to do this ?
PS: I've tested how the content react when simply moved on the parent and data and events are already gone.

It is more a comment, but it does not fit in there.
Moving DOM element around different documents around is alway a little bit risky. Because it could lead to unexpected behavior (memory leaks, elements that behave strange). In current browsers it most of the time works, but i would not recommend it.
If you use jQuery you have another problem. jQuery has a cache for storing informations about data and event that are assigned to an Object, this cache is stored with the documents window. For further details please read this answer, to another question:
How to set jQuery data() on an iFrame body tag and retrieve it from inside the iFrame?
So if you move element with jQuery between different document, you will currently on the one hand loose these informations, on the other hand it could result in memory leaks.
With events it is even more complicate. e.g. if you have delegated events it could be become completely messy.
If you need to exchange data between iframe and parent you should think of some other logic.
I also mention this in a comment to the other answer of me, where i referred to this post:
How to set jQuery data() on an iFrame body tag and retrieve it from inside the iFrame?

Related

Google tag manager single page app get element on history change

I have created a few variables for custom dimension on pageviews.
Pageview trigger: windowload or history change
The data is being pushed through, but it's only getting previous pages'
for example,
page/1 div class "page date" is 25th Jul, I would get undefined, but
when I click onto page/2, i would get the page/1's "page date"
function() {
return window.document.getElementsByClassName('page date')[0].innerText;
}
It seems that the history event is triggered before the corresponding page content is loaded into the DOM. This is nothing you can blame GTM for (GTM sees a history change, inspects the DOM, and grabs whatever it finds there, and that's the normal/expected behaviour).
Your solutions:
Make sure content is updated in DOM BEFORE the history event is triggered: this is something to sort out on the application side, and that may not be easily changed (if you use a framework like react it's probably best if you don't start hacking its core behaviour).
Delay the history event triggers: have a look at this solution which describes how to achieve this. Please note that solutions based on delays are never 100% reliable because there's a race condition between your delay and the loading of content, and you don't know for sure who will come first (and increasing the delay too much can cause the side effect of users changing pages in quick successions before analytics had a change to capture them).
Detect DOM changes: a more robust alternative would be to monitor the DOM for a particular element that is unique to each page (eg a <meta> element with the page ID or URL). You could use a tag to initiate the monitoring of this element when you receive the history change, and when the element actually changes it means the DOM has been updated, and you could fire your own trigger. This could be done via the MutationObserver or using a setInterval/setTimeout loop to check manually. However if the DOM is changed in several phases (blocks by blocks) this would not work (your <meta> element would have changed but not the div you're looking for), requiring you to start monitoring on a per-element or per-block level, which will be quite some work.
Push a dataLayer from your application: this would be my preferred option. I would hook into the logic of your application (you should be able to extend the routing method or the app framework should give you event listeners you can bind a custom function of yours with in which you can tell GTM that the page has been changed (eg dataLayer.push({'event': 'page_changed'});)

Why does the value attribute from an input[text] is different from what the browser renders?

I'm getting this strange behaviour in a very specific set of inputs on one my applications. I create some inputs and I can see them as I created them on the Elements panel (google chrome), but the way the browser renders it is different.
Note how the input is renders with comma instead of a point, but the value attribute uses a point
When I get a referente to that element using the selector API, I get this:
A direct reference to the Dom Element will return 11,00. The tag has 11.00 and jQuery returns the 11,00. I've removed all js that interacts with this element (masks, events, etc) and the issue still happens.
I've been swearing at the DOM for a day and a half, but I know this is most probably an issue with my application. What bothers me the most is that the browser does not honor what I see in the elements panel.
This is the small piece of code that creates the element, stopped right before the tag is created. Note the variables values in the right panel:
Could someone give me a hint about what could be causing this difference in between element, view and attributes? If possible, I'd like to know what/how this is happening in depth.
Thank you in advance

Fire event when browser parses/renders a DOM element

Assume that we know that an element (or a very specific selector) is going to appear on a page. Is it possible to set up beforehand, via JS or jQuery, an event that goes off when the browser gets to that element and parses it? This is NOT content loaded through AJAX but is present in the primary page's source.
The reason for this need is that I'm working with a hosted system that greatly limits where and when I can inject code to fix problems with the page. I can pretty much only place my code at the start and end of what is a really long page. Right now, the page has to load completely before it can inject any desired changes (yuck!). Plus, I cannot make the pages shorter in content.
This is basically the process I would like to happen:
Page begins loading
Listener set up to watch for .specialClass elements
...
.specialClass element gets parsed/added to DOM
Listener triggers function on that element
...
.specialClass element gets parsed/added to DOM
Repeat as before
...
Page finishes rendering
So, is this possible at all? Thanks in advance.

Use more specificity when binding javascript to elements?

I have a situation where I am working on a large site and what I have been doing is using one main .js file to store all my bound js code that I want to use on elements such as onclick, onchange etc etc.... these are all held within the one onDomReady method.
Now I'm wondering is it such a good idea to have each page have to go over these and "search" for each element to see if it has to bind anything?
..or should I perhaps use more specificity to prevent this such as the main page ID like #page1, #page2 etc OR should I store these in the specifics pages header (I don't really want to do that as I prefer to keep it all in one place).
Just trying to optimize things and get rid of unnecessary overhead! :)
If I understand correctly, you have one js file with all your event handlers.
This file is included i many pages.
So for example, if there are 100 event handlers in the file, each page may be using only 10 of these.
If thats the case, then its not efficinet, because you have lots of
document.getElementBy... that are not fnding the elements, because they belong to a different page, or worse, finding elements with same selector on multile pages that should not be binded to handlers on a specific page.
also, you are adding script to a page that it does not need.
Best to give each page only what it needs, be it in external js or if very little script, in doucment head.
js that you share across pages should be code that you intend to re-use often.
EDIT:
In response to comment:
regarding reducing http requests, you mean the one file will be in cache, for other pages to use? fair enough, that counts as a benefit. Though there are tradeoffs, such as increased memory usage due to javascript that you dont need in page.
using more specific selector will reduce the risk of attaching event handler to wrong element in a page that you did not mean to target, but there is a safer option:
If you insit on sharing one event handler file across pages,
Group them by wrapping them a function, one for each page. call that function from the page.
This way, you dont have to execute a bunch of code that you dont need, and don't risk adding wrong event handlers to simmilar elements accross pages.

How can we a get a tab element when the document is known?

Before explaining the question, I want to explain my main goal (If there is a better way than my approach):
I have the document element available with me and ideally I wanted to get a browser element such that it identifies a tab uniquely. In my previous approach I used
gBrowser.getBrowserForDocument(doc);
This returned the browser which was indeed unique to the tab (in the sense that attributes stored in it persisted across pages).
If instead, I don't store the browser element, and after moving to another page in the same tab I try the above command again, then the browser is no longer the same one as before (in the sense that it has lost all the stored attributes).
Therein lies my main problem. I want to get hold of the tab browser which I am able to refer to using different documents loaded in the same tab.
I read about a similar function:
gBrowser.getBrowserForTab(tab);
I have a feeling this might work. But again, I am not able to understand where I can get the parameter "tab" from (given a document).
Note: I am using GWT for the development of the extension
EDIT: To clarify the intent of the question, here's the use case as well as my approach:
In my extension, I am interested in monitoring user behaviour on particular websites. In a way it can be thought of as a session which remains active until the user stays on the same website. During the session, I am often required to store various attributes specific to user behaviour. One of the attributes concerning the question in "isSessionActive":"Y" or "" (blank string stands for no)
To make the code more optimal, I do not instantiate a browser for all the tabs in the beginning. Instead, I wait for the cue using an onLoad function. : if a relevant website is visited
Once that happens, I make a call to get the browser using the current document element, see if it has a non empty value for the attribute isSessionActive. If it does not, I set the attributes value to "Y" and instantiate my class which handles the profiling after that.
If it has value "Y", I know that the session is still active and that I don't need to initialize.
The problem which I'm facing is that after the first instantiation, when I move to another page within the same tab, I expected that the call to
gBrowser.getBrowserforDocument(doc);
would get me the browser instantiated previously since it is basically the same tab.
This is not happening. Each time I get a new Browser instance which does not have the attribute isSessionActive as "Y" (probably because the new page has a new document element). Thus, at present all my code instantiates over and over again which is what I do not want.
If you're only working with the current tab (and not any background tabs), then you could just use gBrowser.selectedTab https://developer.mozilla.org/en/XUL/tabbrowser#p-selectedTab

Categories