When I add text in my text field before and after the existing paragraphs the remove button functions perfectly. However, if I click the remove button before adding elements you have to click TWICE to remove the paragraphs that were not created by a function.
What could be wrong here? I watch the DOM in Firebug as I'm adding and removing, and before the new elements are added, my remove button does not target "firstDiv" on the first click, but does so on the second click.
Here is the problem function:
function removeIt() {
firstDiv.removeChild(firstDiv.lastChild);
}
Here is the fiddle: http://jsfiddle.net/nxpeD/2/
Thanks for the help!
That's because you have text nodes (spaces) at the end, so the last paragraph isn't the last child (it is the last element child).
Then, use
function removeIt() {
firstDiv.removeChild(firstDiv.lastElementChild);
}
Demo: http://jsfiddle.net/nxpeD/6/
Compatibility: To make it work on old browsers, you could also use
function removeIt() {
if (firstDiv.lastElementChild) {
firstDiv.removeChild(firstDiv.lastElementChild);
} else {
var last;
while((last = firstDiv.lastChild).nodeType !== 1) {
firstDiv.removeChild(last);
}
firstDiv.removeChild(last);
}
}
References
lastChild
lastElementChild
Use:
firstDiv.removeChild(firstDiv.lastElementChild);
Since there are formatting new line chars in your html, that will be considered as a child as well of the div. So you need to use lastElementChild to get the element and ignore the formatting and and other text nodes outside.
Demo
The last_child returned is a node. If its parent is an element, then the child is generally an Element node, a Text node, or a Comment node. Returns null if there are no child elements.
lastElementChild
Related
I am dynamically generating a table and after that I want to append it as a child to a div. The problem is every time i regenerate the table it gets appended in the same div without the old table removed.
if(context.children.length == 0){
context.appendChild(table);
}else{
context.replaceChild(table);
}
I tried with checking if the child already exists and if it does i replace it with the new element.
But I get the error The argument is not optional and I don't know how to do it otherwise. Any ideas?
That's not how replaceChild() works, You should, paremtElement.replaceChild(new element, element to be replaced) https://developer.mozilla.org/en-US/docs/Web/API/Node/replaceChild
You need to provide the second argument as the child to be replaced in Node#replaceChild method.
if(context.children.length == 0){
context.appendChild(table);
}else{
context.replaceChild(table, context.children[0]);
}
HTML Coded snippet is here
Using protractor, when am writing the following code, am only able to select the 3rd element from the first matching class
var items = element(by.css('.swatches.swatches_size.swatches_find-box')).all(by.tagName('label'));
items.get(2).click();
What would be the way to select 2nd element from the second matching class?
The code snippet is in the attached image
its element.all(by.css('.swatches.swatches_size.swatches_find-box')).each(function (element, index) {
You can just chain element() and all():
$$('.swatches.swatches_size.swatches_find-box').get(1).all(by.tagName("label")).get(1);
where $$ is a shortcut to element.all(by.css("...")).
Or, an alternative approach would be to use a single CSS selector with the help of nth-of-type and nth-child pseudo classes:
$(".swatches.swatches_size.swatches_find-box:nth-of-type(1) label:nth-child(1)")
Thanks for the responses. Here is what I did to select the third element of the second matching DIV:
element.all(by.css('.swatches.swatches_size.swatches_find-box label')).
each(function(element, index) {
element.getText().then(function(text) {
if (text === waist) {
element.click();
}
if (text === length) {
element.click();
}
});
});
Instead of .get(1), .get(2), .get(3), etc. now you can use more readable functions like .second(), .third(), .fourth() etc. - I developed a small package - https://github.com/Marketionist/protractor-numerator - that can be used with protractor to select second, third, fourth, etc. elements.
So, applied to your case (to select 2nd element from the second matching class), it would be much more readable and will look like this:
var itemSecond = element.all(by.css('.swatches.swatches_size.swatches_find-box')).second().all(by.tagName('label')).second();
itemSecond.click();
I have a function that removes list element from one ordered list then finds all ordered lists after current one, gets their first element and appends it to that lists previous one.
The issue: if I remove first element from any list or it is appended function stops working, I believe it is due jQuery remembering what first element was and as it is no longer in its place it can't find it, however it should just re-define / look up new element in particular list that is first child at the moment. Here is the function:
function removeQueueItem(element) {
//Get ordered list of removed list element
var itemMonth = element.parents().eq(2); //li.queue-month
//Get all following lists
nextMonths = itemMonth.nextAll('.queue-month');
//Fade out removed element
element.parent().fadeOut(function(index){
//Remove element from DOM
element.remove();
nextMonths.each(function(index) {
//Check if next month has socks
if($(this).find('.item-dragable').length > 0) {
var firstItem = $(this).find('.item-dragable:first-child');
$(this).prev().find('ol').append(firstItem);
}
});
});
}
JsFiddle - Remove first item in September then remove any item in August, the first item in September should become pink, but it isn't happening. This is what the problem is.
Because you are removing an a tag instead of a li tag. So when you search :first-child it is there, but you do not see it.
In order to make it work you need to change your code from:
element.parent().fadeOut(function(index){
//Remove element from DOM
element.remove(); <-- here
...
});
To:
element.parent().fadeOut(function(index){
//Remove element from DOM
$(this).remove(); <-- element to $(this)
...
});
JSFiddle
That's because it's the parent you're fading out, but the inner element you're removing. Your .item-dragable element still exists and ends up with its display property set to none. This means it's still the first child.
...becomes:
To fix this, simply change:
element.remove()
...to:
element.parent().remove()
JSFiddle demo.
On a page that contains a list of <div> blocks, each of which contain location info, and after each <div> there is an <hr>, I need to target and remove all divs that do not have the city Boston in them.
I was able to easily remove those divs with:
$("div.location").not(":contains('Boston')").remove();
That was when I noticed the surplus of leftover <hr>
Would it be better to target and remove all of the dividers first? Then the divs? Can I do both with one stroke of jQuery? Thanks!
$("div.location").not(":contains('Boston')").next('hr').remove().end().remove();
DEMO
NOTE to comment
$("div.location").not(":contains('Boston')") // return the target div
.next('hr') // take the pointer to hr, next to target div
.remove() // remove the hr
.end() // return the pointer to target div.location again
.remove(); // remove the target div
Can I do both with one stroke of jQuery
Not that it's any "better", but you can always just chain it, remove the next() HR, then use end() to step back and remove() the div, or do it the other way around removing the div first, does'nt really matter much:
$('div.location').filter(function() {
return $(this).text().indexOf('Boston') == -1;
}).next('hr').remove().end().remove();
The obvious one is $("div.location:not(:contains('Boston')), div.location:not(:contains('Boston')) + hr").remove()
Use a simple selector, then get the conjunctive hr elements left over
$("div.location:not(:contains('Boston'))").remove().add("hr+hr").remove();
EDIT:
alternate avoid double dom manipulation by direct selection first
$("div.location:not(:contains('how'))").add("div.location:not(:contains('how'))+hr").remove();
I see that this has been asked many times. But, unfortunately I have not come across a straight forward solution. Most solutions revolve around multiple nodes within the div.
So here's problem. I have the following markup:
<div class="test">Text1<span></span></div>
I need "Text1" to be replaced with "Text2" without affecting the span tag and event handlers attached to the span tag.
Doing something like $('.test')html('Text2<span></span>') does replace the text. But, removes the event handlers on the span tag, which is not desired. I am looking for a quick and efficient method for this one.
Wrap replaceable text with a tag:
<div class="test"><span class="test-text">Text1</span><span></span></div>
You can access the Text Node itself with contents. Now if you know that the element starts with text you can do this:
$($('.test').contents()[0]).replaceWith('New Text');
Now if you didn't know the location in the array of the Text Node, you can filter with:
return this.nodeType === 3;
and compare the text values (if you know those).
Fiddle
if you would add event handler with .live or .on functions (depends on jQuery version) .html('Text2') would work just fine.
On the assumption that the text to be replaced will always precede the existing span, that it will always be the firstChild and that it will be an unwrapped textNode:
$('.test').click(
function() {
this.firstChild.nodeValue = 'Text2';
});
JS Fiddle demo.
To ensure that only the first textNode is changed, regardless of where it's found within the .test element:
$('.test').click(
function(e) {
var newText = 'Text2',
children = e.target.childNodes;
for (var i=0,len=children.length;i<len;i++){
if (children[i].nodeName == '#text'){
children[i].nodeValue = newText;
return false;
}
}
});
JS Fiddle demo.