Detecting as the last child of the parent under class="cond" - javascript

contenteditable div
((grade >= passingMark) && (grade<101))
HTML
<span class="cond frag">(<span class="cond frag">(grade >= passingMark)</span> && <span class="cond frag">(grade<101)</span>)</span>
How would i know if i am the last child of cond or there is no next sibling following me (grade<101)
Something like (in a loop):
$elem = $('.frag').eq(fragNum);
if ($elem.nextAll('.cond').length === 0 ) {
alert('last child detected');
}

If by "How would i know ..." you mean "In JavaScript, how would I get..."
MooTools makes it easy:
var last = document.getElement('.cond').getLast('span');
In this case, document.getElement will get the first element that matches .cond in document.
There will be a simple jQuery equivalent too.
If you are using native JS, you run into problems as there is no native support for "getElemntByClassName" in IE<9. There are a bunch of frameworks and tools to bridge these browser gaps like MooTools, JQuery, Prototype, etc, but if you need native and know the index position of the span with class .cond within a specific container, you could try:
var conds = document.getElementsByTagName("span")[0].getElementsByTagName("span");
var last = conds[conds.length-1];
Where document is your specific container and 0 is the position (first in container).
If this is the only problem you would like to solve, there is this 2008 "getElementsByClassName" solution that still works nicely is IE<9 by Robert Nyman - http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/

Do you mean something like this?
http://jsfiddle.net/KyleMuir/nujr7/1/
var elements = document.getElementsByClassName('cond');
var totalElements = elements.length;
var lastElement = elements[totalElements -1];
Added console.logs to illustrate this clearer in the fiddle.
Hope this helps.

Related

Safely / completely remove element from DOM [duplicate]

When removing an element with standard JavaScript, you must go to its parent first:
var element = document.getElementById("element-id");
element.parentNode.removeChild(element);
Having to go to the parent node first seems a bit odd to me, is there a reason JavaScript works like this?
I know that augmenting native DOM functions isn't always the best or most popular solution, but this works fine for modern browsers.
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = this.length - 1; i >= 0; i--) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
And then you can remove elements like this
document.getElementById("my-element").remove();
or
document.getElementsByClassName("my-elements").remove();
Note: this solution doesn't work for IE 7 and below. For more info about extending the DOM read this article.
EDIT: Reviewing my answer in 2019, node.remove() has come to the rescue and can be used as follows (without the polyfill above):
document.getElementById("my-element").remove();
or
[...document.getElementsByClassName("my-elements")].map(n => n && n.remove());
These functions are available in all modern browsers (not IE). Read more on MDN.
Crossbrowser and IE >= 11:
document.getElementById("element-id").outerHTML = "";
You could make a remove function so that you wouldn't have to think about it every time:
function removeElement(id) {
var elem = document.getElementById(id);
return elem.parentNode.removeChild(elem);
}
Update 2011
This was added to the DOM spec back in 2011, so you can just use:
element.remove()
The DOM is organized in a tree of nodes, where each node has a value, along with a list of references to its child nodes. So element.parentNode.removeChild(element) mimics exactly what is happening internally: First you go the parent node, then remove the reference to the child node.
As of DOM4, a helper function is provided to do the same thing: element.remove(). This works in 96% of browsers (as of 2020), but not IE 11.
If you need to support older browsers, you can:
Remove elements via the parent node
Modify the native DOM functions, as in Johan Dettmar's answer, or
Use a DOM4 polyfill.
It's what the DOM supports. Search that page for "remove" or "delete" and removeChild is the only one that removes a node.
For removing one element:
var elem = document.getElementById("yourid");
elem.parentElement.removeChild(elem);
For removing all the elements with for example a certain class name:
var list = document.getElementsByClassName("yourclassname");
for(var i = list.length - 1; 0 <= i; i--)
if(list[i] && list[i].parentElement)
list[i].parentElement.removeChild(list[i]);
you can just use element.remove()
You can directly remove that element by using remove() method of DOM.
here's an example:
let subsWrapper = document.getElementById("element_id");
subsWrapper.remove();
//OR directly.
document.getElementById("element_id").remove();
The ChildNode.remove() method removes the object from the tree it belongs to.
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
Here is a fiddle that shows how you can call document.getElementById('my-id').remove()
https://jsfiddle.net/52kp584L/
**
There is no need to extend NodeList. It has been implemented already.
**
According to DOM level 4 specs, which is the current version in development, there are some new handy mutation methods available: append(), prepend(), before(), after(), replace(), and remove().
https://catalin.red/removing-an-element-with-plain-javascript-remove-method/
You can simply use
document.getElementById("elementID").outerHTML="";
It works in all browsers, even on Internet Explorer.
Having to go to the parent node first seems a bit odd to me, is there a reason JavaScript works like this?
The function name is removeChild(), and how is it possible to remove the child when there's no parent? :)
On the other hand, you do not always have to call it as you have shown. element.parentNode is only a helper to get the parent node of the given node. If you already know the parent node, you can just use it like this:
Ex:
// Removing a specified element when knowing its parent node
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);
https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild
=========================================================
To add something more:
Some answers have pointed out that instead of using parentNode.removeChild(child);, you can use elem.remove();. But as I have noticed, there is a difference between the two functions, and it's not mentioned in those answers.
If you use removeChild(), it will return a reference to the removed node.
var removedChild = element.parentNode.removeChild(element);
console.log(removedChild); //will print the removed child.
But if you use elem.remove();, it won't return you the reference.
var el = document.getElementById('Example');
var removedChild = el.remove(); //undefined
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
This behavior can be observed in Chrome and FF. I believe It's worth noticing :)
Hope my answer adds some value to the question and will be helpful!!
Functions that use ele.parentNode.removeChild(ele) won't work for elements you've created but not yet inserted into the HTML. Libraries like jQuery and Prototype wisely use a method like the following to evade that limitation.
_limbo = document.createElement('div');
function deleteElement(ele){
_limbo.appendChild(ele);
_limbo.removeChild(ele);
}
I think JavaScript works like that because the DOM's original designers held parent/child and previous/next navigation as a higher priority than the DHTML modifications that are so popular today. Being able to read from one <input type='text'> and write to another by relative location in the DOM was useful in the mid-90s, a time when the dynamic generation of entire HTML forms or interactive GUI elements was barely a twinkle in some developer's eye.
Shortest
I improve Sai Sunder answer because OP uses ID which allows to avoid getElementById:
elementId.remove();
box2.remove(); // remove BOX 2
this["box-3"].remove(); // remove BOX 3 (for Id with 'minus' character)
<div id="box1">My BOX 1</div>
<div id="box2">My BOX 2</div>
<div id="box-3">My BOX 3</div>
<div id="box4">My BOX 4</div>
Having to go to the parent node first seems a bit odd to me, is there
a reason JavaScript works like this?
IMHO: The reason for this is the same as I've seen in other environments: You are performing an action based on your "link" to something. You can't delete it while you're linked to it.
Like cutting a tree limb. Sit on the side closest to the tree while cutting or the result will be ... unfortunate (although funny).
From what I understand, removing a node directly does not work in Firefox, only Internet Explorer. So, to support Firefox, you have to go up to the parent to remove it's child.
Ref: http://chiragrdarji.wordpress.com/2007/03/16/removedelete-element-from-page-using-javascript-working-in-firefoxieopera/
This one actually comes from Firefox... for once, IE was ahead of the pack and allowed the removal of an element directly.
This is just my assumption, but I believe the reason that you must remove a child through the parent is due to an issue with the way Firefox handled the reference.
If you call an object to commit hari-kari directly, then immediately after it dies, you are still holding that reference to it. This has the potential to create several nasty bugs... such as failing to remove it, removing it but keeping references to it that appear valid, or simply a memory leak.
I believe that when they realized the issue, the workaround was to remove an element through its parent because when the element is gone, you are now simply holding a reference to the parent. This would stop all that unpleasantness, and (if closing down a tree node by node, for example) would 'zip-up' rather nicely.
It should be an easily fixable bug, but as with many other things in web programming, the release was probably rushed, leading to this... and by the time the next version came around, enough people were using it that changing this would lead to breaking a bunch of code.
Again, all of this is simply my guesswork.
I do, however, look forward to the day when web programming finally gets a full spring cleaning, all these strange little idiosyncracies get cleaned up, and everyone starts playing by the same rules.
Probably the day after my robot servant sues me for back wages.
// http://javascript.crockford.com/memory/leak.html
// cleans dom element to prevent memory leaks
function domPurge(d) {
var a = d.attributes, i, l, n;
if (a) {
for (i = a.length - 1; i >= 0; i -= 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
domPurge(d.childNodes[i]);
}
}
}
function domRemove(id) {
var elem = document.getElementById(id);
domPurge(elem);
return elem.parentNode.removeChild(elem);
}
This is the best function to remove an element without script error:
function Remove(EId)
{
return(EObj=document.getElementById(EId))?EObj.parentNode.removeChild(EObj):false;
}
Note to EObj=document.getElementById(EId).
This is ONE equal sign not ==.
if element EId exists then the function removes it, otherwise it returns false, not error.

Get all elements with `position:fixed` in an HTML page?

Reason for doing that: I'm debugging css of my webpage.. some elements appeared and they're not supposed to appear. I suspect it is the issue with element positioning.. therefore I want to find these positioned element and check one by one.
This one is using jQuery. I hope you are find with it.
var find = $('*').filter(function () {
return $(this).css('position') == 'fixed';
});
I think this one works using a pure javascript:
var elems = document.body.getElementsByTagName("*");
var len = elems.length
for (var i=0;i<len;i++) {
if (window.getComputedStyle(elems[i],null).getPropertyValue('position') == 'fixed') {
console.log(elems[i])
}
}
Here is an ES6 version that gives you an array of these elements for further processing:
let fixedElements = [...document.body.getElementsByTagName("*")].filter(
x => getComputedStyle(x, null).getPropertyValue("position") === "fixed"
);
document.querySelector('*[style="position:fixed"]')
The * item specifies all tag names. The [] indicate that you're looking for an attribute. You want your style attribute to have position:fixed.
If you aren't using jQuery, this is probably going to be your simplest option.
Warnings that apply to all answers:
This is a slow operation. On a large-enough page, this operation can take 100ms or more, which is a lot for a single operation. You shouldn't need this unless you're developing a browser extension.
Now sticky elements can act as fixed elements in some cases
Having said that, here's the shortest and most efficient version to do this:
const fixed = [].filter.call(document.all, e => getComputedStyle(e).position == 'fixed');
Here's a version that includes sticky elements, but they're not exactly equivalent, it depends on what you're looking for:
const all = [].filter.call(
document.all,
e => ['fixed', 'sticky'].includes(getComputedStyle(e).position)
);
If you're feeling modern, replace document.all with document.querySelectorAll('*'), but the former will likely work forever.
Try this:
var elements = $('*').filter(function () {
return this.style.position == 'fixed';
});
It will give you all elements having position fixed.

Find any form element

I am trying to find if a class exists and if not just find the first form element. How do I write :input? This does not seem to work.
$('.focus:not(:hidden):first, :input:not(:hidden):first').focus();
Comma-separated selectors are not hierarchical in the manner you seem to indicate. Your selector will yield the first visible .focus and the first visible input element. You'll need to break this up in two selectors:
var focusElement = $('.focus:visible:first');
if(focusElement.length == 0)
focusElement = $(':input:visible:first');
focusElement.focus();
Or I suppose you could write
$('.focus:visible:first, body:not(:has(.focus:visible)) :input:visible:first').focus();
Your code actually worked for me. Take a look at this jsfiddle. Try removing my class='focus' and it then falls back to selecting the first input field.
I would go for the easy to understand model:
var finder = $('.focus:not(:hidden):first');
finder = finder.length ? finder: $(':input:not(:hidden):first');
finder.focus();
Same result, but likely better given the right to left sizzle re: performance
var finder = $('.focus').not(':hidden').eq(0);
finder = finder.length ? finder: $(':input').not(':hidden').eq(0);
finder.focus();

Find last child of specific element

The question is really confusing but I'll try to explain here.
In CSS I know you can say "if this DIV has x and y and z inside it in any way" then apply this style. Like
div.class id class { style }
I was wondering how I would go about doing this in Javascript for detecting the last child.
Such as getting if
div div:nth-child(2) span a
is the last child of a certain div in Javascript.
I hope this is not too confusing because it sure looks confusing to me... If you need clarification please ask.
I am going to post an answer despite the previous one, because I refuse to use (and intend to try to convince others to stop using) w3schools.
So, a much better resource: MDN - lastChild
And inline:
var tr = document.getElementById("row1");
var corner_td = tr.lastChild;
As a bonus, and in sync with the above w3fools
1) Try this by jquery
$(document).ready(function () {
var list = $("#containerId").children();
var lastElement = list[list.length - 1];
});
OR
2) pure javascript
var list = document.getElementById('containerId').children;
var lastElement = list[list.length - 1];
I think you are loking for lastChild property

Calculating text selection offsets in nest elements in Javascript

The Problem
I am trying to figure out the offset of a selection from a particular node with javascript.
Say I have the following HTML
<p>Hi there. This <strong>is blowing my mind</strong> with difficulty.</p>
If I select from blowing to difficulty, it gives me the offset from the #text node inside of the <strong>. I need the string offset from the <p>'s innerHTML and the length of the selection. In this case, the offset would be 26 and the length would be 40.
My first thought was to do something with string offsets, etc. but you could easily have something like
<p> Hi there. This <strong>is awesome</strong>. For real. It <strong>is awesome</strong>.</p>
which would break that method because there are identical nodes. I also need the option to throw out nodes. Say I have something like this
<p>Hi there. This <strong>is blowing my mind</strong> with difficulty.</p>
I want to throw out an elements with rel="inserted" when I do the calculation. I still want 26 and 40 as the result.
What I'm looking for
The solution needs to be recursive. If there was a <span> with a <strong> in it, it would still need to traverse to the <p>.
The solution needs to remove the length of any element with rel="inserted". The contents are important, but the tags themselves are not. All other tags are important. I'd strongly prefer not to remove any elements from the DOM when I do all of this.
I am using document.getSelection() to get the selection object. This solution only has to work in WebKit. jQuery is an option, but I'd prefer to it without it if possible.
Any ideas would be greatly appreciated.
I have no control over the HTML I doing all of this on.
I think I solved my issue. I ended not calculating the offset like I originally planned. I am storing the "path" from the chunk (aka <p>). Here is the code:
function isChunk(node) {
if (node == undefined || node == null) {
return false;
}
return node.nodeName == "P";
}
function pathToChunk(node) {
var components = new Array();
// While the last component isn't a chunk
var found = false;
while (found == false) {
var childNodes = node.parentNode.childNodes;
var children = new Array(childNodes.length);
for (var i = 0; i < childNodes.length; i++) {
children[i] = childNodes[i];
}
components.unshift(children.indexOf(node));
if (isChunk(node.parentNode) == true) {
found = true
} else {
node = node.parentNode;
}
}
return components.join("/");
}
function nodeAtPathFromChunk(chunk, path) {
var components = path.split("/");
var node = chunk;
for (i in components) {
var component = components[i];
node = node.childNodes[component];
}
return node;
}
With all of that, you can do something like this:
var p = document.getElementsByTagName('p')[0];
var piece = nodeAtPathFromChunk(p, "1/0"); // returns desired node
var path = pathToChunk(piece); // returns "1/0"
Now I just need to expand all of that to support the beginning and the end of a selection. This is a great building block though.
What does this offset actually mean? An offset within the innerHTML of an element is going to be extremely fragile: any insertion of a new node or change to an attribute of an element preceding the point in the document the offset represents is going to make that offset invalid.
I strongly recommend using the browser's built-in support for this in the form of DOM Range. You can get hold of a range representing the current selection as follows:
var range = window.getSelection().getRangeAt(0);
If you're going to be manipulating the DOM based on this offset that you want, you're best off doing so using nodes instead of string representations of those nodes.
you can use the following java script code:
var text = window.getSelection();
var start = text.anchorOffset;
alert(start);
var end = text.focusOffset - text.anchorOffset;
alert(end);
Just check if your selected element is a paragraph, and if not use something like Prototype's Element.up() method to select the first paragraph parent.
For example:
if(selected_element.nodeName != 'P') {
parent_paragraph = $(selected_element).up('p');
}
Then just find the difference between the parent_paragraph's text offset and your selected_element's text offset.
Maybe you could use the jQuery selectors to ignore the rel="inserted"?
$('a[rel!=inserted]').doSomething();
http://api.jquery.com/attribute-not-equal-selector/
What code are you using now to select from blowing to difficulty?

Categories