Find specific child of parent's previous siblings when siblings are dynamic - javascript

I ran into an issue trying to find the closest sibling of a parent that contained a specific child (one tree level). I finally found the answer through trial and error, but I searched on here before proceeding with testing. Thought I'd share my findings and see if anyone has an easier way to do what I'm doing.
Essentially I'm using jQuery 1.7 (latest as of 03/30/2012) and needed to find a title previously displayed for a "continue" heading in the following row. Here's what I came up with:
(($(this).parent().prevAll()).children('h2')).first().html();
I simply assigned this to a variable and used it to create a new "continue" title on the next row.
Any suggestions for cleaner code? Can this be done easier or more efficiently?
EDIT:
Here's the HTML as requested:
<div class="container">
<div class="subbox">
<h2>Title1</h2>
<div class="itembox">...some content here...</div>
</div>
<div class="subbox"><div class="itembox">...some content here...</div></div>
</div>
As you can see, it's simply a set of sub-boxes with the first one in the set having an H2, but in my case I was working with 4+ sets and needed to get the title of the first item in the set (not necessarily the title of the first set).

Not 100% sure if this will work since i haven't tested it, but you could simplify the code if you would have something like:
($(this).parent().prevAll()).children("h2:first").html();

Related

Change CSS of element not in DOM

I have an element, let's say a circle.
And there is a list of item in a list view.
Initially, the circle is not rendered. I have set its CSS display property to none, and instead select an item message is displayed. The idea is when the user selects an item from the list, I want to show the circle changing its background-color property associated with selected item.
My approach is something like this
itemSelected(item) {
const itemtColor = item.color;
$('#selected-item-color').css('background-color', itemColor);
}
The issue is:
As the element is not present in the DOM when I try $('#selected-item-color'), it will return an empty list, and the change of property does not do anything. But on next subsequent selections, it works fine.
So, is there any clean way to do this before the element is actually rendered in the DOM either jQuery or JavaScript. Or, should I just look for a way to do this after the element is rendered, which I'm not sure if there is a way with my problem.
Any help is appreciated, thanks!
Edit:
I have the HTML code written in handlebars
The code calling above function
<div class="item-list-content">
{{#each itemList as |item|}}
<div class="list-item" {{action "itemSelected" item}}>{{item.name}}</div>
{{/each}}
</div>
The dynamic content
<div class="item-details">
{{#if selecteditem}}
<div id="selected-item-color"></div>
{{else}}
<div class="item-details-message">Please select an item</div>
{{/if}}
</div>
To solve your problem you can just use ngShow instead of ngIf. There are better ways to do that as well, but for your issue ngShow will solve your problem.
I tried out few things and could not get anything to solve this.
So, I ended up doing the next best thing:
Putting the code to change project color inside a timeout function.
A timeout of 1ms worked for me, however I have not tested it well, and to be on a safer side, an interval of 10ms should work without problems.
setTimeout()

Jquery Select one object but hide others of the same type

I'm new to programming and I've never posted on here before but this problem should be fairly simple yet I can't get it. It goes beyond the basics for me. I have 5 objects all with the same div class. I've experimented with hiding classes and such but my goal is to use an event handler and jquery selectors to select the one object and hide or detach the rest. My code is probably pretty ugly but I'm working toward an answer.However once the object that wasn't hidden is clicked again I want the others to reappear.
Check this out:
.not(this) selects every other element of the common class except from the selected one
.toggle() keeps changing the elements' status from hidden to visible and back forever...
$('.aa').click(function(){
$('.aa').not(this).toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="aa">1</div>
<div class="aa">2</div>
<div class="aa">3</div>
<div class="aa">4</div>
<div class="aa">5</div>

jQuery hide(), show() or html()

I have a
<div id="content">
</div>
and three js variables that store different html: content1, content2 and content3.
By user interactions, the content of mentioned above div changes to one of that that stored in js variables.
What is preferable either to directly set div content to what I need by user interaction:
$("#content").html(content2);
or to change div structure to:
<div id="content">
<div id="c1">
// value of content1 variable here
</div>
<div id="c2">
// value of content2 variable here
</div>
<div id="c3">
// value of content3 variable here
</div>
</div>
And doing hide() and show() to that inner blocks, i.e when I want content2 to be shown:
$("#c1").hide();
$("#c2").show();
$("#c3").hide();
?
I'd say hiding & showing divs.
It's less intensive, and if the content inside the javascript variables happens to contain elements that you'll bind to, you won't have to rebind everytime you refresh the content, and if you wanted to have some sort of animation between the different content, multiple divs also allows that.
As a side note, using jQuery it's less code to do something like
$("#c2").show().siblings().hide();
The two aren't really all-that comparable since they do different things. They may well give a similar perception but what's happening isn't the same in terms of markup. In fact, it's not uncommon to see .html('Something').show() chained together.
Passing a string to .html() replaces the content of the selected element, it does nothing to affect the element itself.
Calling .show() or .hide() only affects the element itself - all the descendants remain exactly the same, they just can't be seen because their parent is not being displayed.
By using .html() you are replacing everything inside your element. All references to these descending elements will become undefined and direct (non-delegated) event listeners will also be lost.
.hide() and .show() do exactly what they say. The data inside your element is still preserved, the event handlers still in place, it's all just 'hidden' by way of display: none.
If the content dynamically changes, without page-load, use .html(), if not, .show() and .hide() are more appropriate.
For the ease of use and shorter more cleaner looking code, setting the content through HTML is the right option!
Think of it as what you're trying to do, 1 DIV => Can contain 3 different contents, you can manipulate it through JS.
So, in your first solution, you actually have one div and manipulating it through JS:
$("#content").html(content1);
$("#content").html(content2);
$("#content").html(content3);
Whereas, in the second solution, you are actually using 4 divs for the same functionality! So definitely, if you can do something with 1 div. That's the preferred way.
They both are taking equal lines for JS, but with the second approach, your HTML will contain a lot more code considering your contents are large.
I think that the best solution is to store the different contents into three variables and then assign to the div the choosen one with
$("#content").html(content2);
In this way you have three less nodes on your DOM tree
There isn't that much difference between the two options. One factor that might affect this is the actual size of the content you are changing. If the content is relatively small then it really doesn't matter which way you choose.
Another thing to consider is how available the three versions of the content variable is. If you have to fetch this HTML content each time you load it then it might make sense to pre-populate the content before you display it to your users so as to save the time it takes to load it. Then just show/hide the appropriate content.

how to toggle a div on click at different div?

I am trying to toggle a div by clicking on a different div. The only relation that two divs share is that they are inside the same div. I have a DIV class comment which holds DIV class button that is supposed to toggle DIV class box when clicked. The box DIV is also inside the comment DIV. I am trying to use jQuery(this).find(".box").toggle();, but it is not working. I am triggering it with $( ".button" ).click(function(). The script is currently at the bottom of my body.
Could anyone please tell me what am I doing wrong here? I've been playing around with the function for a while now, but with no luck at all. Thank you in advance for your replies.
JSFIDDLE here
HTML
<div class="comment">
<div class="button">
show/hide .box with text1
</div>
<div class="box">
text 1
</div>
</div>
<div class="comment">
<div class="button">
show/hide .box with text2
</div>
<div class="box">
text 2
</div>
<div>
jQuery
$( ".button" ).click(function() {
jQuery(this).find(".box").toggle();
});
You can use the jQuery selector .siblings() to re-write your function like this:
$( ".button" ).click(function() {
$(this).siblings().toggle();
});
Here's a working fiddle to demonstrate.
All you really need to do is this:
$(this).parent().find(".box").toggle();
In short, change:
jQuery(this).find(".box").toggle();
To ONE of the following lines:
$(this).parent('.comment').find(".box").toggle();
$(this).closest('.comment').find(".box").toggle();
$(this).siblings(".box").toggle();
Full Explanation:
The reason it's not working is due to the call. Let's break down your call and see what exactly it's doing.
First we see a simple jQuery selector. This tells jQuery to look for a div containing the class button. Keep in mind, jQuery makes use of any CSS selector. So selecting an item in jQuery is as simple as using it's CSS selector!
$( ".button" )
Next you are assigning an event. In this case, that event is click, meaning you're telling a div having the class button to do something every time it is clicked. Keep in mind, however, not including a callback function is an easy way to trigger this event as well.
$( ".button" ).click(function() {
Now this next line is where your mistake takes place.
jQuery(this).find(".box").toggle();
The first mistake is the use of jQuery. after you're already making use of it's short sign, $. You only need use the elongated name if you are using jQuery's noconflict because another JS library you include might use $. In other words, if $('.button') works and is a jQuery object when used, then you don't need to use jQuery.. See more about this here.
Now, that aside, we can look at jQuery(this) as $(this). Whenever you use $(this) in an Event's callback method, you're referring to the element that the event was tied too. That means that $(this) in your function refers to $('.button'). The problem here is that you then want it to find an inner element containing the class box. Well according to your HTML, that can't happen since .box is a sibling, it is not within the inner HTML of .button. Thus you need to make a different call before you can find .box.
There are actually several solutions here. No solution is more "correct" than another, just simply different and possibly causes a different amount of "time" to run. Now I went with what I saw as being the most simple in that it gives you control over the parent element which contains ALL relevant elements to this function. I'll talk about possible alternatives in a minute.
$(this).closest('.comment')
The above line simply tells .button:clicked to look for the first parent element that contains the class .comment. In other words, this won't find any children or siblings, it will only go up from the current element. This allows us to grab the block that contains all relevant elements and information and thus make maneuvers as needed. So, in the future, you might even use this as a variable in the function, such as:
$('.button').click(function(e) {
var container = $(this).closest('.comment');
Now you can find anything within this element block. In this case you want to find box and toggle it. Thus:
$(this).closest('.comment').find(".box").toggle();
// Or with our variable I showed you
container.find(".box").toggle();
Now, there are plenty of alternatives based on your HTML layout. This example I've given would be good even if .box was buried inside more elements inside .comment, however, given your exact HTML, we see that .button and .box are siblings. This means that you could make this call different entirely and get the same result using something like:
$(this).siblings(".box").toggle();
This will allow our currently clicked and selected button element to look for ANY and ALL siblings having class box. This is a great solution and simple if your HTML is that simple.
However, many times, for "comment" type setups, our HTML is not so simple, nor is it static. It's usually something loaded after the page load. This means our general assignment of .click will not work. Given your exact HTML and not knowing a static Parent ID, I would probably write your code as:
$(document).on('click', '.button', function(e) {
$(this).siblings('.box').toggle();
});
What this does is allow for this click event to be assigned to ANY element containing .button for a class, whether loaded with page or even ten minutes after the page is up. However, the caveat often seen here is the assignment is placed on document. Should we assign a lot of events to document it could become quite convoluted and possibly slow down the client's browser. Not to mention the arguments held over all the other headaches this could cause. So here's my recommendation, make a static (loads with page, is a part of page's main HTML) loading area and do our dynamic assignment to that. For instance:
<div id"Comments"><!-- load comments --></div>
Then you can do the assignment as such:
$('#Comments').on('click', '.button', function(e) {
$(this).siblings('.box').toggle();
});
If you have any more questions, just comment!
Side Note .on is for jQuery versions 1.7+. If using older jQuery, use .live or .bind

Best way to manipulate many sliding objects with moo tools's Fx.Slide

I'm trying to think of the most elegant solution to handle multiple Fx.Slides within mootools. I'm developing a dictionary page with a very long list of words where there's a pair word -- translation and all the translations must be hidden by default showing just a word list. I'm looking for a solution that won't require creating a separate slide for each word on the page, so that they're created on-the-fly when a visitor clicks on a word because the size of the script and performance hit concern me. There's another problem in that their initial states must be set to 'hidden' beforehand and I don't want to do it in CSS (that would hide everything from people whose browsers don't support javascript).
Is anything of this sort possible or will I have to rely on creating slides in a loop (my element ids go like w01, w02, ...)? If so, how would I put that block inside a loop?
Check out this question regarding if the user does not have Javascript Embedding extra styles with noscript.
After that is taken care of we can concentrate in mootools. You want the elements to have visability: hidden when you load the page with Javascript. Give your elements a class so we can select them all at once. Example to initialize the elements.
$$('.sliders').each(function(el) {
el.slide('hide').setStyle('visibility', 'visible');
});
Now we need to handle the click event. The same goes here.
Example html:
<h3 class="slideIn" >Some title</h3>
<div class="sliders>Some lengthy text<div>
Example html:
$$('.slideIn').addEvent('click', function() {
this.getNext().getChildren('.sliders').slide();
});
​
Example fiddle: http://jsfiddle.net/b4Zjs/
Edit: If there are a lot of elements that should have click events it's better to use event delegation. Then you are only adding one event listener to the page, and it can make a huge difference some times.
$('parent').addEvent('click:relay(h3.slideIn)', function(event, target) {
target.getNext().getChildren('.sliders').slide();
});
jsFiddle example: http://jsfiddle.net/b4Zjs/2/

Categories

Resources