Why can't you append to an element that you use to wrap another - see example below?
var $test = $('.test'),
$test1 = $('.test1'),
$move = $('.move'),
$testWrapper = $('<div class="test-wrapper"></div>'),
$test1Wrapper = $('<div class="test1-wrapper"></div>');
$test.wrap($testWrapper);
// move item and return to wrapper
$move.append($test);
$testWrapper.append($test); // this is the line that does not work?
console.log($testWrapper); // still seems to be a jquery object?
$test1.after($test1Wrapper); // if you place the element after instead of using it to wrap, then it works?
$move.append($test1);
$test1Wrapper.append($test1);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test">test</div>
<div class="test1">test 1</div>
<div class="move"></div>
wrap() seems to clone the markup of the provided element for wrapping, not the actual element itself. You can see it in the developer tools when you use console.log($testWrapper) and hover over that line in your browser console: normally, the DOM element should be highlighted, but it's not. So what is referenced by the variable $testWrapper after wrapping is still (a jQuery collection of) a node that is not attatched to the DOM.
var $test = $('.test'),
$test1 = $('.test1'),
$move = $('.move'),
$testWrapper = $('<div class="test-wrapper"></div>');
$test.wrap($testWrapper);
// move item and return to wrapper
$move.append($test);
console.log($testWrapper); // <= if you hover this element in the browser console, it doesn't highlight the actual DOM element either; that's how you can visully detect that it's not the same element!
$testWrapper = $('.test-wrapper'); // select the actual DOM element that has been created for wrapping
$testWrapper.append($test); // now it will work!
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test">test</div>
<div class="move"></div>
Related
I made a jquery filter function, that filtering the results by data-tags. like this:
<div class="resultblock" data-tag="ios">
<img src="images/osx.jpg" class="itemimg">
<div class="desc">
<div class="desc_text">
lorem ipsum
</div>
</div>
i just want to insert in the data-tag another tags to filter. like this:
data-tag="ios,android,windows"
How can i do that?
I am not sure I fully understand the question you are asking, but I think you could accomplish this via JS.
In your html add a script tag and then you just write some JS to edit or add html tags. Here is an example:
<script>
var para = document.createElement("p");
var node = document.createTextNode("This is new.");
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
Now to sort the data-tag:
just add this code to your HTML file.
<div id="div1">
</div>
<script>
var tag ="ios,android,windows"; //initialize variable
var data = tag.split(","); //this makes an array of ios,andrid,windows
var i = 0;
while (i < 3){
alert(i);
var para = document.createElement("p");
var node = document.createTextNode(data[i]);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
i++;
}
</script>
The best way doing this is to use classes. Adding classes and removing them is much easier than other attributes. The classes should not overlap with other classes used for CSS for example. Adding a prefix to them is even better. Like this:
$(".filter-ios").hide(); // hide all ios elements
$("something").addClass("filter-windows"); // add the class windows to an element
$(".filter-ios").addClass("filter-apple"): // add the apple filter class to the ios filter class elements
$("something").hasClass("filter-samsung"); // check if an element has the filter class samsung
// ...
The classes .filter-* should be used for filtering only, they must not have any CSS attached to them, if there is already classes like that, then just change the prefix filter to something else!
I've just created a little object with two methods .add and .remove. It works like classList DOM method for adding and removing classes. If you add one value twice, it's added only once, also if you remove some not existing class, any error will occure. Hope you'll find it helpful.
var el = document.getElementById('myElem');
multiValues = {
add: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) elem.setAttribute('data-tag');
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
var isExist = parsed.some(function(a){
return a === val;
});
if(!isExist) parsed.push(val);
elem.setAttribute('data-tag',parsed.join(','));
},
remove: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) return;
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
parsed.some(function(a,b){
if(a===val){
parsed.splice(b,1);
}
elem.setAttribute('data-tag',parsed.join(','));
});
}
};
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'android');
multiValues.remove(el,'a');
multiValues.remove(el,'b');
multiValues.add(el,'something');
console.log(el.attributes['data-tag'].value);
<div class="resultblock" data-tag="ios" id="myElem"></div>
I am modifying an elements innerHTML property inside a $.each() loop. Now if my stack of elements contains childrens of the element where I update the innerHTML, the DOM reference of that children will get lost.
Example:
$(function(){
$stack = $(".myelement, .myelement *");
$stack.each(function(){
var $this = $(this);
var element = $(this)[0];
console.log(element.innerHTML = element.innerHTML + " modified");
});
});
Fiddle: https://jsfiddle.net/b0ux0v5e/
What happens is that I first modify the innerHTML of .myelement. This includes the children p. Therefore the DOM reference of this element is get lost and "modified" will not be appended.
How can such an scenario be solved without building a function that creates a unique selector for the element and re-catches it in each loop?
Note: I am not asking for specifically appending some text to nodes. This is just an example. In a real project I am replacing text in the innerHTML.
I guess you want to modify the text content. in this case you would like to know about .contents() method, which lets you loop through with text nodes as well:
$(function() {
$(".myelement").contents().each(function(i, el) {
el.textContent += " 'modified'";
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="myelement">
I am the myelement
<p>
Hello world
</p></div>
Don't modify innerHTML, it will destroy/recreate all the elements inside and force a re-render. You can use insertAdjacentHTML or jQuery's append to add to an element.
Also you do not need to do:
element = $(this)[0];
this will already be a reference to the element.
$(function(){
$stack = $(".myelement, .myelement *");
$stack.each(function(){
var $this = $(this);
//this.insertAdjacentHTML("beforeend"," modified");
//Or
$this.append(" modified");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="myelement">
<span>A span</span>
<div>A div</div>
<div>
<p>a paragraph in a div</p>
</div>
</div>
EDIT
As it seems you want to replace word(s) and not append a word, you could do a replace on the html and then reset it, but again this will destroy/recreate the elements inside, so if any of them have something like event listeners attached they will be lost
var modified = $".myelement").html().replace(/yourword/g,"modified");
$(".myelement").html(modified);
Or you could just loop over all the Text nodes and replace the word from there, this will keep the elements, their event listeners, and so on intact.
$(".myelement, .myelement *").contents().filter(function() {
return this.nodeType == 3;
}).each(function(){
this.textContent = this.textContent.replace(/A/g,"modified");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="myelement">
Inside A element <br>
<span>A span</span>
<div>A div</div>
<div>
<p>a paragraph in A div</p>
</div>
</div>
just change
$stack = $(".myelement, .myelement *");
to
$stack = $(".myelement");
And you will see in your console
I am the myelement
<p>
Hello world
</p> modified
I have the following code,
$(document.getElementById('messages_message-wysiwyg-iframe').contentWindow.document).keydown(function() {
var iFrame = document.getElementById('messages_message-wysiwyg-iframe');
var iFrameBody;
if ( iFrame.contentDocument )
{ // FF
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0];
}
else if ( iFrame.contentWindow )
{ // IE
iFrameBody = iFrame.contentWindow.document.getElementsByTagName('body')[0];
}
console.info(iFrameBody.innerHTML);
});
What I am trying to do if get the content of an iframe, but remove all the html tags that are not,
b, strong, i, a, u, img
However I do not want to remove any of the of the text, for example if the in the iframe there is the following,
<div class="box segment panel">
<a href="http://www.google.com>hello world</a>
click this link and go far.
<img src="http://placehold.it/100x100" alt="Placeholder"/>
</div>
What would be return would be the following,
hello world
click this link and go far.
</a>
<img src="http://placehold.it/100x100" alt="Placeholder" />
Is this even possible?
Here's my pure JS solution:
function sanitize(el) {
if (el.nodeType !== 1) return;
if (!/^(B|STRONG|I|A|U|IMG)$/.test(el.tagName)) {
var p = el.parentNode;
// move all children out of the element, recursing as we go
var c = el.firstChild;
while (c) {
var d = c.nextSibling; // remember the next element
p.insertBefore(c, el);
sanitize(c);
c = d; // look at the next sibling
}
// remove the element
p.removeChild(el);
}
}
demo at http://jsfiddle.net/alnitak/WvJAx/
It works by (recursively) moving the child nodes of restricted tags out of their parent, and then removing those tags once they're empty.
With a regex:
iFrameBody.innerHTML=iFrameBody.innerHTML.replace(/<[^(b|strong|i|a|u|img)]\b[^>]*>/gi,"").replace(/<\/[^(b|strong|i|a|u|img)]>/gi,"");
The first replace removes the start tags, the second removes the end tags.
Note that there are a couple traps when using regex to match html. But in this specific case it seems like a reasonable choice (cf. my comments on the other answers).
For the record, this is what I use to access an iframe's content document:
var doc=ifr.contentWindow||ifr.contentDocument;
if (doc.document) doc=doc.document;
var iFrame = document.getElementById('messages_message-wysiwyg-iframe');
var iFrameDoc = iFrame.contentDocument || iFrame.contentWindow.document;
$(iFrameDoc).keydown(function() {
var iFrameBody = $("body", iFrameDoc);
var cleared = iFrameBody.clone();
cleared.find("*:not(b,strong,i,a,u,img)").each(function() {
var $this = $(this);
$this.replaceWith($this.contents());
});
console.log(cleared.html());
});
Demo at jsfiddle.net
I think you're a little confused about how to describe what you're trying to do. When you talk about "text", you're referring to the innerHTML/text node inside of a tag. What you're really looking to do, I think, is grab all of the specific content and the structure of the content, aka the children elements of the iFrame.
You can use jQuery's .text() method to get the text content of each element individually and save that before removing the actual tag from the DOM, if you want to lets say, get the text content of a span but you don't want the span to be in the DOM anymore, or you want to place it somewhere else in your document.
var elemText = $('span#mySpan').text();
$('span#mySpan').remove();
For what it looks like you're trying to do based on your sample HTML, you may want to look into jQuery's detach method: http://api.jquery.com/detach/
This will allow you to store the returned children elements to be appended somewhere else later.
How does one select DOM elements in javascript?
Like for example:
<div class="des">
<h1>Test</h1>
<div class="desleft">
<p>Lorem Ipsum.</p>
</div>
<div class="Right">
<button>Test</button>
</div>
</div>
Now how do i select h1? This is just a part of a bigger Page, so cannot use getElementsByTagName(), since others might get selected. Also since there might be other h1's in the document later, i cannot attach the index(body's) to above.
Is there a simple way to select, say <h1> tag which is under the classname of desleft?
I cannot use jQuery or any other libraries.
You can use this to get to your H1:
var des = document.getElementsByClassName('des')
var fc = des[0].getElementsByTagName('h1')
alert(fc[0].innerHTML)
w3.org has selectors now (http://www.w3.org/TR/selectors-api/#examples). Here are 2 different ways that worked for me on Chrome. You may want to use querySelectorAll function that returns a list.
<script type="text/javascript">
//looks for <h1> tag under <div> with className "des"
showOff1 = function() {
var x = document.querySelector(".des h1");
alert(x.innerHTML);
}
//looks for <div> tag with className "desleft" and then use previousSibling to traceback <h1> tag
showOff2 = function() {
var y = document.querySelector("div.desleft");
var z = y.previousSibling.previousSibling;
alert(z.innerHTML);
}
</script>
<body onload="showOff2();">
Use querySelectorAll
You can use querySelectorAll:
// Will return a NodeList even if there is only one element found
var heading = document.querySelectorAll('.des > h1');
heading[1].style.color = 'red'; // NodeList is similar to an array
This will return a NodeList.
or
Use querySelector to return the first element found:
var first_heading = document.querySelector('.des > h1');
first_heading.style.color = 'blue';
Commonly used with an id selector #single-header-id.
Here's a demo
getElementsByTag()
Would be a function that you can start with, and then you can filter for the DOMElements that have the class.
var h1_array = document.getElementsByTag('h1');
var h1_class_array = [];
for (var i=0, len=h1_array.length; i < len; i++) {
if (h1_array[i].className.indexOf('classname') !== -1) {
h1_class_array.push(h1_array[i]);
}
}
The .indexOf function returns -1 if the needle is not found in the haystack.
Now re-reading your question, why not just give your h1's id's ?
DOM traversal is one of javascript's glaring issues (enter jQuery).
a simple getElementById() would save you a headache, and ids on all your h1's would be much cleaner in the end than trying to formulate an algorithm to select them by other means.
If you mean to select a h1 that is before the first element of class desleft, you could always do this:
document.getElementsByClassName("desleft")[0].previousSibling.previousSibling
Example: http://jsfiddle.net/Xeon06/ZMJJk/
previousSibling needs to be called twice because of the empty text node between the two. That's why using libraries to do this stuff is really the best way to go.
var h1 = document.querySelector('.desleft').previousElementSibling;
Find element with className='desleft' using selector '.desleft'
Just move back to previous element (not to previous node!)
So I want to get the first <a> tag in this <div>. This is really driving me nuts. Thanks for any help.
HTML
<div id="PGD" class="album" onmouseover="load(this)">
<a class="dl" href="#">DOWNLOAD</a>
</div>
Javascript
function load(dl)
{
var ID = $(dl).attr('id');
var elemnt = $('ID:first').attr('id');
}
Non-jQuery: (was not tagged with jQuery before, so I included this)
If you want to get the first child element only:
var element = document.getElementById('PGD').children[0];
If you want to get the first anchor element:
var element = document.getElementById('PGD').getElementsByTagName('a')[0];
With jQuery:
var element = $('#PGD').find('a:first');
// or, to avoid jQuery's pseudo selecors:
// var element = $('#PGD').find('a').first();
and actually your function can just be
function load(dl)
{
var element = $(dl).find('a:first');
}
Update:
As you are using jQuery, I suggest to not attach the click handler in your HTML markup. Do it the jQuery way:
$(function() {
$("#PGD").mouseover(function() {
$(this).find('a:first').attr('display','inline');
alert($(this).find('a:first').attr('display'));
});
});
and your HTML:
<div id="PGD" class="album">
<a class="dl" href="#">DOWNLOAD</a>
</div>
​See for yourself: http://jsfiddle.net/GWgjB/
$("#PGD").children("a:first")
This will give you the first child "a" tag, but not the descendents. E.g.
<div id="log">
<p>Foo</p>
Hello
Hello
</div>
Will give you : Hello
$(ID).find(':first')
See find jQuery command.
$('#PGD').find('a:first')
Actualy I've not understanding problem, so I'm trying correct your function, to make it clear for you:
function load(dl)
{
// var ID = $(dl).attr('id');
// var elemnt = $('ID:first').attr('id'); // Here is error-mast be like $(ID+':first')
var ID = $(dl).attr('id');
var elemnt = $(ID).find('*:first').attr('id');
}
I supose dl that is $('#PGD'). But child element A have not attribute id, what are you trying to find?
Also See: http://api.jquery.com/category/selectors/