Replace text in html and keep events - javascript

I need to replace one pattern like that : "{12345,abcd}" in html of body but i woludn't lose the events of children.
I have tried that code :
$("body").html($("body").html().replace(/[{]{1}([\d]+)[,]{1}(.*?)[}]{1}/g, "<span>Code:$1</span> - <span>Text:$2</span>"))
but that kill all events of elements.
How i can do?

You have 3 options:
Open the related view in your IDE, modify it and like a gentleman generate the desired markup. Modifying HTML using regex is a bad practice.
Select only the descendant elements than can have that string and replace their textContent instead of the resetting entire body contents.
$('.elements').text(function(_, oldText) {
return oldText.replace('foo', 'bar');
});
Replace the body' contents and delegate all the events:
$(document).on('event', 'element', fn);
You can also replace the body' contents before binding event handlers. This of course won't break future event handlers.

#BlackSeep
That not work if I would do something like angularJs parser, I have solved fetching all text items and searching into for the regex.
This is the solution for me :
$("body").find(":not(iframe)").addBack().contents().each(function() {
if(this.nodeType == 3)
{
$(this).first().replaceWith( $(this).text().replace(/[{]{1}([\d]+)[,]{1}(.*?)[}]{1}/g, "<span class='translator' data-code='$1' data-text='$2'>$2</span>"));
}
});
For information I had used this for have one mapper for webpages translation.
Where i print "{id,text}" i replace that with one span and then I handle one special event for launch the translation of that box.

this happens because html() method works with text (not dom elements) and text doesn't save event listeners, so u first read text, then do something with it (replace), then write it. In this situation you will loose as event listeners as they are attached to DOM objects (not to text)
i think the best way is to go through all Dome tree , find all textNode DOM elements, and to do replace separately in each of them

Related

How to store html element including its event listeners?

Using and html element's addEventListener has several advantages over using inline events, like onclick.
However, to store the element including its inline event is straight forward, for example, by embedding it in a parent element and storing the parent's innerHTML.
Is it possible to do something similar when using event listeners?
Edit:
I realized that my question is not sufficiently explained. So here some additions.
By "store" I mean a way to get the information holding the element and the event listener.
The analogue with inline events is easy: just embed in a parent element and save the parent's innerHTML (string) somewhere, for example in a database, and recreate the element later by loading the string and applying it to the innerHTML of some element.
But how would one do the analogue with elements when using event listeners? One cannot just use the innerHTML since then the events are not stored.
I hope this clarifies my question a bit.
Edit 2
With the help of comments I have made some unsuccessful attempts.
It is possible to get store the information of an element using createDocumentFragment() or element.cloneNode(true).
However, the first method does not work for external storage since, if I understood correctly, will contain only a pointer. Here is an example:
https://jsfiddle.net/hcpfv5Lu/
The second method does not work either. I am not fully sure why, but if I JSON.stringify the clone it "vanishes". Here is an example:
https://jsfiddle.net/3af001tq/
You could use a document fragment to store the DOM node in a JavaScript variable which can then be appended to a DOM element when required.
https://developer.mozilla.org/en/docs/Web/API/Document/createDocumentFragment
Yes.
You can use something like.
<ul>
<li id="list">Some data</li>
<li>Dumy</li>
</ul>
then in your javascript file,
document.getElementById("list").addEventListener("click", function(){
var htmlMarkUp = this.parentNode.innerHTML;
});
This would store the html content of ul in var htmlMarkUp.

Why is replace() disrupting onclick()?

I am using replace to search my dynamically loaded webpage for this symbol Æ and replace it with ®. I found the code to do so in this question:
Find and replace specific text characters across a document with JS
$("body").children().each(function () {
$(this).html( $(this).html().replace(/Æ/g,"®") );
});
However, after I added this code, this function stopped working.
document.getElementById("backToClasses").onclick = function() {
console.log("Clicked");
};
Can anyone tell me why this might happen?
In the second chunk of code (which I assume runs first) you are locating an element in the DOM and assigning a value to a property of it.
The first chunk of code goes over the DOM and converts large chunks of it into HTML source code, it then modifies that source code, then it generates new DOM elements from it and replaces whatever was there before with them.
So the element with the ID backToClasses:
Gets a click handler
Is converted to HTML
Is destroyed
Is replaced by a new version created from its old HTML
The click handler was only ever on the DOM, so the new element doesn't have it.
If you are going to take this approach, then you should look at looping over just the text nodes in the document and dealing in text rather than HTML. To do that you'll need to recursively loop over the DOM and test the node type of each element.
It would be better to fix the underlying problem that you are hacking around though. It is almost certainly down to an incorrectly specified character encoding somewhere.
The W3C has some material on character encodings that might be helpful.
By doing this:
$("body").children().each(function () {
$(this).html( $(this).html().replace(/Æ/g,"®") );
});
You re-create all the HTML elements, so any events that you might have bound before are lost. Don't use the .html() function to replace text. And still, I'm not sure that this is the best way to replace a character.
This replace should be done server-side, not client side. By doing it client-side (in JavaScript) you can get into different problems like SEO (Google indexing your site with your badly encoded characters). If the characters are like this inside a file, simply replace them in that file, make sure to save the file with the right encoding.

Javascript performance - Events on removed nodes

My question is simple: Do we have to remove Javascript events listeners from elements that we are removing dynamically from the DOM?
Let's take this example (fiddle with full code) using jQuery: we have a user action that changes the DOM content using jQuery html function:
$('wrapper').html(markup);
The markup variable has got a lot of elements with the class eventDiv, and on those elements we add some event listeners:
$(".eventDiv").mouseenter(function() {
$(this).css('background-color', 'red');
});
$(".eventDiv").mouseleave(function() {
$(this).css('background-color', 'white');
});
Does this way of changing html content lead to a memory leak? Do we have to unbind all the event listener? Or is the removing of the nodes from the DOM enough?
And second, there is an easy way to remove all the listener on child element of a container div? In my case something like
$('wrapper').unbindAllChildEventsListeners();
PS: this is a example, the real case scenario has got a lot of different events on the new markup that is loaded by the user action, and also a DOM tree much more articulated, the "markup" variable is coming from a dustjs template.
Consider this example:
http://jsbin.com/bunoyedabo/edit?html,js,console,output
First of all, use event delegation. $().on('eventName', 'targetSelector', cb);
Second is that you can unbind events using .off() or .unbind().

Append HTML-escaped text: jQuery

I'm used to using jQuery's .append() method to add text or HTML onto the end of a pre-existing element. I'm currently using jQuery's .text() to escape strings that could potentially contain HTML. Unfortunately, there doesn't seem to be a jQuery method that will append the results of the .text() method to an element instead of replacing its contents.
Is there a way to append, instead of replace, this escaped text to an element? Or is there a better way to escape strings containing HTML?
Thanks.
- EDIT -
A little more context: I'm building an HTML string dynamically, and so I'll need to be able to add multiple elements with escaped content programmatically.
As I have tried many ways, I think the following method is the cleanest way to add text to whatever node you want.
no stock tag needed, only plain text, which will help to avoid potential problems
$(document.createTextNode("SomePlainText")).appendTo(p);
You could create a dummy element to hold the result of .text() which can then be appended to your destination element:
$('<div/>').text('your <span>html</span> string').appendTo(...);
You could just use
$(whatever).text($(whatever).text() + whatever_you_want_to_append);
EDIT for the fiddle in my comment, try this:
for ( /* some looping parameters */ ) {
$('<li></li>') // create an li
.text(stringWithHtml) // pass it the text, as text not html
.appendTo('#thisIsWhatINeed'); // append it where you want it
}
jsFiddle

Jquery Class Selector Fails to Select new Class Instances Added with .append()

I'm semi-new to Javascript/jQuery so apologies in advanced if I'm missing something basic. I have a function that is triggered whenever a user types in an element with a specific class.
$('.relevantClass').keyup(function(){
//code...
});
Now this function may end up, depending on the situation, creating a good deal of new HTML including new instances of relevantClass through the .append() method.
var newHTML = <div class='relevantclass'>Content...</div>;
$('#wrapper').append(newHtml);
However, the jQuery selector does not seem to detect and execute the function when a user types in the newly created relevantClasses. I've checked the newly created Html and it has the correct class tags and old instances of the relevant class due work.
I'm guessing this has something to do with .append(); messing with the DOM and I need someway to "refresh" the selector and let it do its jQuery thing researching the DOM to find the new classes. Any thoughts on how to do this? Is there some jQuery method I can't find?
You have to use on() to attach events that work on dynamic content:
var $parent = $("selector"); //the element you're appending .relevantClass to
$parent.on("keyup",".relevantClass",function(){
//code...
});
Keep in mind that to work with dynamic content, you have to attach the event to relevantClass's closest parent that exists on page load.
Some people use body, but you should get used to using parent elements as close as you can get to the dynamic content. This is so that event delegation occurs on a smaller scale.
More info on on() here.
Also, I hope that newhtml variable is wrapped in quotes.
$('.relevantClass').on('keyup', function(){
//code...
});
Try something like
$('body').on('keyup', '.relevantClass', function() { ... }
The idea is that you use an existing root element and use your class selector as a filter. See the examples here.

Categories

Resources