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.
Related
I have a grid of cards, right now clicking one of the cards adds an overlay to all of them.
I need:
1.- If user clicks one cards, and only that card gets the overlay.
2.- No more than 3 cards at a time can have an overlay. User would have to click one of the already clicked cards to diselect it, in order to select another one.
Codepen:
https://codepen.io/ogonzales/pen/yLJGzYr
JS Code:
$('.imageDiv').click(function(){
$('img').toggleClass("tricky_image");
$(".text").toggleClass("display-inline");
});
Expected result:
Try this instead. Make use of this so that the relevant scope is preserved.
$('.imageDiv').click(function(){
$(this).find('img').toggleClass("tricky_image");
/*$(".text").css("display", "inline");*/
$(this).find(".text").toggleClass("display-inline");
});
You could equally (maybe) use the .children() method (as opposed to .find()) but I didn't know exactly how your dom structure was inside each "imageDiv".
Your specified click function search for every 'img' element and every node with a .text class.
What you actually want, is to get the child img element and .text of the clicked .imageDiv
By limiting the queried scope with $(this).find(...) we only search for child elements of the clicked .imageDiv.
With some additional logic your second requirement can be also fulfilled ->
$('.imageDiv').click(function(){
const trickyCount = $(".tricky_image").length;
const img = $(this).find('img');
const text = $(this).find(".text");
if(trickyCount < 3 || img.hasClass("tricky_image")){
img.toggleClass("tricky_image");
text.toggleClass("display-inline");
}
});
If you click option 2, it appends the original clone from page load but it wont repeat every time the button is clicked.
1. Turn the element red...<br />
2. Append the original black element...<br /><br />
<div id="container">
<div class="element">This is an element!</div>
</div>
$(document).ready(function () {
var obj = $(".element").clone(true);
$(".copy").click(function (e) {
e.preventDefault();
//alert(obj); //Just to see if it still exists.
$("#container").append(obj);
});
$(".modify").click(function (e) {
e.preventDefault();
$(".element").css("color", "#F00");
});
});
Here is my CodePen link http://codepen.io/anon/pen/dsvLm
Any ideas?
One feature of an individual DOM element, that you may not have been aware of, is that it can only have one parent. This makes sense as the DOM tree connects elements up, down, and sideways to each other and only have a single parent-element link (and a single next and single prev sibling element link) but a list of multiple children.
When you clone an element, you create a new DOM element that is effectively a new branch in a DOM tree (if only a small one). Calling append adds the element to its new parent, but it also points a parent link of your clone to its new parent. By appending the same element over and over you are simply changing the parent of a single element (i.e. moving it in the DOM tree).
Instead just make a new clone of your disconnected cloned object (in its original state) each time you need one:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/7h8MK/2/
$("#container").append(obj.clone(true));
You need to create the clone while appending.Use:
var obj = $(".element");
$(".copy").click(function (e) {
e.preventDefault();
//alert(obj); //Just to see if it still exists.
$("#container").append(obj.clone(true));
});
Demo
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
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 have to set a class name on a (li) element.
This script find all the (a) elements in the list, and creates a click event.
jQuery("#" + ElementID).find(TagName).click(function () {
GetPageByUrl(jQuery(this).attr("href"));
jQuery(this).parent().addClass('yourClass');
//ChangeSelectedMenuItem(this);
return false;
});
The parent of every (a) element is a (li) element
But nothing happens when this line is executing
jQuery(this).parent().addClass('yourClass');
Everything else is working just fine.
What am I doing wrong here?
Okay, but it still won't work. It won't add any class jQuery(this).addClass('yourClass'); Should add a class to the (a) element, but it doesn't?
Specify the optional selector to target what you want:
jQuery(this).parent('li').addClass('yourClass');
Or:
jQuery(this).parents('li').addClass('yourClass');
$(this.parentNode).addClass('newClass');