Selecting element after 'this' - javascript

I need to select multiple elements at once for a function. I've got
jQuery
$('[class^="shapeLeft"]').click(function(){
var $parent = $(this).parent()
var $both = $(this, 'this + div[class^="shapeRight"]')
$both.css({'height': parent.height() + 20})
})
HTML
<div class="shapeLeftDiamond"></div>
<div class="shapeRightDiamond"></div>
The part where I say $(this, 'this + div[class^="shapeRight"]') doesn't seem to work.
The clicked element does get its height changed, but its direct neighbor with a class starting with shapeRight doesn't.
How do I select the clicked element and its shapeRight sibling at once?
Thanks

Starting with this, here's how to find all siblings matching a selector:
var allSiblings = $(this).siblings("the-selector-here");
Here's how to find all following siblings:
var allSiblings = $(this).nextAll("the-selector-here");
Here's how to find one following sibling that may not be adjacent:
var allSiblings = $(this).nextAll("the-selector-here").first();
More in the API documentation.
From your fiddle, I don't know which of those you want, but in a comment you said:
I want to write something that is going to select a whole lot of elements.
...which makes me think you want nextAll (without first). Then there's this comment:
I need to select the element after this AND this at the same time
...which means you also want .add(this):
$(".shapeLeftDiamond").click(function() {
var parent = $(this).parent();
var thisShape = $(this).nextAll("div[class^='shapeRight']").add(this);
thisShape.height(parent.height() + 20);
})
main {
height: 200px;
width: 200px;
background-color: #F13;
}
.shapeLeftDiamond {
float: left;
width: 80px;
height: 50px;
background-color: #FF0;
}
.shapeRightDiamond {
float: right;
width: 80px;
height: 50px;
background-color: #0FF;
}
<main>
<div class="shapeLeftDiamond">Click me</div>
<div class="shapeRightDiamond">Should also grow</div>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

You need to remove this from the selector (this has no meaning in CSS selectors) and change the order of your parameters. The selector string comes first, followed by the context:
$(".shapeLeftDiamond").click(function(){
var parent = $(this).parent();
var thisShape = $("+ div[class^='shapeRight']", this);
thisShape.height(parent.height() + 20);
});
Edit: If you want both elements to grow, use .add():
thisShape.add(this).height(parent.height() + 20);
https://jsfiddle.net/qukkwvL1/4/

Either use .next() if it is the exact following node
var thisShape = $(this).next().addBack();
or use .siblings() if they share the same parent but might have other elements in the DOM between them
var thisShape = $(this).siblings('[class^="shapeRight"]').addBack();
In both cases you alse need to add the .addBack() at the end, to include the current element in the selection (the this in your case)
Demo at https://jsfiddle.net/gaby/qukkwvL1/3/

The line:
$(this, "this + div[class^='shapeRight']");
Means:
Look for the element this in the context of this + div[class^='shapeRight']". where the second this in the string would be an element <this/>, not the object.
You want to use either $(this).next(".shapeRightDiamond") or $(this).siblings(".shapeRightDiamond") to get the element beside the one that was clicked. To link the elements to the same set, you want to use .add() or .addBack()
var elems = $(this).add( $(this).next(".shapeRightDiamond") );
or
var elems = $(this).next(".shapeRightDiamond").addBack();

Related

JQuery event delegation: how to get the index of a JQuery Object in a Array?

I have created an array full of jQuery Object - dom elements:
var tabComponet = new Class({
var $tab = $("<div class='tab'></div>");
var $container = $("<div id='container'></div>");
var tabsArr = [];
[a, b, c].each(function(){
tabsArr.push($tab);
$container.append($tab);
});
$container.on('click', '.tab', function (e) {
e.preventDefault();
var index = $(tabsArr).indexOf($(this));
}
});
I created tabsArr to avoid when there are multiple components created by this Class above by then there will be multiple components contains .tab class thus using $('.tab') would not be working right, but it seems I could not simply put a $ sign on tabsArr to make this working. Also in the delegation, I should avoid using '.tab' as parameter too, right?
I googled about it, it may be because that everytime I use $ to make a JQuery object they would be not the same but just contain the same value, so $(this) is not in tabsArr, because tabsArr doesn't contain it but just the same value.
so how should I do this? how should I create a object that contains the exact tab elements that belong to its own component?
When you create element, you obtain reference to this element. Reference is not value. Your code serves as nice example: when your for loop finishes, you will see only one element inside container no matter what..
Wrapping javascript element into jQuery always create new reference. When you compare two elements(and any non-primitive type) in javascript, you don't compare values(content), but their references. Fortunately you can use get() method to obtain javascript direct reference to element!
var $container = $("<div id='container'></div>");
var tabsArr = [];
for (var i=0;i<2;i++) {
let $tab = $("<div class='tab'></div>");
tabsArr.push($tab.get(0));
$container.append($tab);
};
$container.on('click', '.tab', function (e) {
e.preventDefault();
console.log(tabsArr.indexOf(this));
});
$container.appendTo('body');
.tab {
height: 100px;
width: 200px;
background-color: red;
margin-bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Only one Active class and Visible Div at a time

There are a bunch of div elements on the page.
I have a nested div inside of them.
I want to be able to add a class to the clicked element, and .show() the child div.
$('.container').on('click', function(){
$(this).toggleClass('red').children('.insideItem').slideToggle();
});
I can click on it, it drops down.
Click again, it goes away.
So, now I need some method to removeClass() and slideUp() all of the other ones in the event of a click anywhere except the open div. Naturally, I tried something like this:
$('html').on('click', function(){
$('.container').removeClass('red').children('div').slideUp();
});
Well, that just stops the effect from staying in the first place. I've read around on event.Propagation() but I've read that should be avoided if possible.
I'm trying to avoid using any more prebuilt plugins like accordion, as this should be a pretty straightforward thing to accomplish and I'd like to know a simple way to make it work.
Would anyone be able to show a quick example on this fiddle how to resolve this?
Show only one active div, and collapse all others if clicked off
https://jsfiddle.net/4x1Lsryp/
One way to go about it is to update your code with the following:
1) prevent the click on a square from bubbling up to the parent elements
2) make sure to reset the status of all the squares when a new click is made anywhere.
$('.container').on('click', function(){
$this = $(this);
$('.container').not($this).removeClass('red').children('div').slideUp();
$this.toggleClass('red').children('div').slideToggle();
return false;
});
See the updated JSfiddle here: https://jsfiddle.net/pdL0y0xz/
You need to combine your two approaches:
for (var i = 0; i < 10; i++) {
$('#wrap').append("<div class='container'>" + i + "<div class='insideDiv'>Inside Stuff</div></div>");
}
$('.container').on('click', function() {
var hadClassRed = $(this).hasClass('red');
$('.container').removeClass('red').children('div').slideUp();
if (!hadClassRed) {
$(this).toggleClass('red').children('div').slideToggle();
}
});
.container {
width: 200px;
height: 200px;
float: left;
background: gray;
margin: 1em;
}
.insideDiv {
display: none;
}
.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap"></div>

javascript: how to replace all the tag with something different

I want to replace all the tags with different tag using javascript.
Lets say I want to replace "asdf" tag with "xyz"
<asdf>
<asdf> First
<asdf> First nested </asdf>
</asdf>
<asdf> Second</asdf
</asdf>
This is what I am expecting:
<xyz>
<xyz> First
<xyz> First nested </xyz>
</xyz>
<xyz> Second </xyz>
</xyz>
i tried with using jquery
$('asdf').each(function() {
$(this).replaceWith("<xyz>"+$(this).html()+"</xyz>")
});
but it replaces only the first not all.
I'd do it in reverse document order so that we process descendant elements before ancestor ones, and I'd avoid making a round-trip through markup since that's unnecessary overhead and will wipe out event handlers we could avoid wiping out. (Not much we can do about the ones on the actual elements we're changing, at least not ones attached with modern techniques.)
See comments:
// Get all target elements, and then get a raw array for them
// and reverse it. Then loop through the reversed copy.
$("div").get().reverse().forEach(function(src) {
// Get a jQuery wrapper for this element
var $src = $(src);
// Create the replacement
var $dest = $("<span>");
// Move all its contents over
$dest.append($src.contents());
// Copy its attributes
Array.prototype.forEach.call(src.attributes, function(attr) {
$dest[0].setAttribute(attr.nodeName, attr.nodeValue);
});
// Replace it
$src.replaceWith($dest);
});
Live Example:
setTimeout(function() {
// Get all target elements, and then get a raw array for them
// and reverse it. Then loop through the reversed copy.
$("div").get().reverse().forEach(function(src) {
// Get a jQuery wrapper for this element
var $src = $(src);
// Create the replacement
var $dest = $("<span>");
// Move all its contents over
$dest.append($src.contents());
// Copy its attributes
Array.prototype.forEach.call(src.attributes, function(attr) {
$dest[0].setAttribute(attr.nodeName, attr.nodeValue);
});
// Replace it
$src.replaceWith($dest);
});
}, 500);
div {
border: 1px solid red;
}
span {
border: 1px solid green;
}
.test {
color: blue;
font-weight: bold;
}
<p>Divs will change to spans in a moment. "Second" is blue because it has a class on it, to check that we copy attributes correctly.</p>
<div>
<div>First
<div>First nested</div>
</div>
<div class="test">Second</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Made simple jquery plugin
$.fn.renameTag = function(replaceWithTag){
this.each(function(){
var outerHtml = this.outerHTML;
var tagName = $(this).prop("tagName");
var regexStart = new RegExp("^<"+tagName,"i");
var regexEnd = new RegExp("</"+tagName+">$","i")
outerHtml = outerHtml.replace(regexStart,"<"+replaceWithTag)
outerHtml = outerHtml.replace(regexEnd,"</"+replaceWithTag+">");
$(this).replaceWith(outerHtml);
});
return this;
}
Usage:
$('asdf').renameTag('xyz')

jQuery: how can I move character before letters

I have a html code that cannot be altered directly.
<span class="class1 class2 class3 "> First name*: </span>
I need to move the * at the begining or the text. The end result should be this:
<span class="class1 class2 class3 "> *First name: </span>
I also need to make the * to be red (I need to add a class only for this character).
Any ideas?
I'd suggest:
$('span.class1.class2.class3').text(function(i, t){
/* i is in the index of the current element among those returned,
t is the text of the current element.
We return the new text, which is an asterisk, followed by the original text,
with the asterisk removed (using replace to replace the asterisk with an empty string):
*/
return '*' + t.replace(/\*/,'');
});
JS Fiddle demo.
If, however, you need a more generic approach (for example if you have multiple elements with the same/similar selectors):
// selects all the span elements, and filters:
$('span').filter(function(){
// discards the elements that *don't* have '*:' in their text:
return $(this).text().indexOf('*:') > -1;
// iterates over those elements (as above):
}).text(function(i, t) {
return '*' + t.replace(/\*/,'');
});
JS Fiddle demo.
In order to 'make it red,' you'd have to manipulate the HTML, rather than just the text, of the element:
$('span').filter(function(){
return $(this).text().indexOf('*:') > -1;
// Using 'html()' to set the HTML of the 'span' element:
}).html(function(i, h) {
// creating a span and prepending to the current element
return '<span class="required">*</span>' + h.replace(/\*/,'');
});
Coupled with the CSS:
.required {
color: red;
}
JS Fiddle demo.
Further, for simplicity, given that you want to target the * with a class-name (and therefore wrap it in an element-node), you could avoid the string-manipulation and simply float:
$('span').html(function(i,h){
// simply wrapping the `*` in a span (using html() again):
return h.replace(/(\*)/,'<span class="required">*</span>');
});
With the CSS:
.required {
float: left;
color: red;
}
JS Fiddle demo.
References:
filter().
html().
text().
If the problem is the very specific scenario you gave,
$(".class1.class2.class3").each(function() {
var inner = $(this).html();
$(this).html("*" + inner.replace("*",""));
}
var span = $('span.class1.class2.class3');
var new_text = span.text().replace(/\*/, '').replace(/^(\s*)/, '\1<span style="color:red;">*</span>');
span.html(new_text);
Demo

Applying a style to and inserting a line break after the first word in a link

I've been asked to recreate an HTML site in WordPress and have it all done except for a meny bar that has me stumped. See image at: http://img36.imageshack.us/img36/8964/menubare.jpg
In short, I need a way to stylize the first word of an element differently than the rest of it and insert a line break following that first word. I'm sure it's a quick jQuery hack, but don't know enough about jQ to make it happen on my own.
Here's the catch: Those little arrows signal a drop-down menu shows up. I have the dropdowns working, but want to make sure whatever solution applies to the main menu, skips the dropdown ones (They're UL lists within an LI item).
Any help would be appreciated.
$('#nav').children('li').find('a').each(function(){
var old = $(this).text();
$(this).html(old.substring(0,old.indexOf(' ')) +'<br/>'+old.substring(old.indexOf(' '),old.length));
});
if you need to apply some class
$(this).html('<span class="first">'+old.substring(0,old.indexOf(' ')) +'</span><br/><span class="next">'+old.substring(old.indexOf(' '),old.length)+"</span>");
Without an HTML example of your menu, its hard to give you a specific answer.
But you could use some jQuery like the following, it will allow you to add styling to the first word, and the rest of them. It will .split() the HTML on spaces, giving you an array. Wrap the first item in a span allowing styling. Then uses jQuery's .each() to loop through the rest of the items adding them back to the string. Then replaces the HTML with the new version:
$('#header > ul.nav > li > a').each(function() {
var obj = $(this);
var text = obj.html();
var parts = text.split(' ');
var replace = '<span class="firstWord">'+parts[0]+'</span><br />';
parts.shift();
$.each(parts, function(key, value) {
replace += ' '+value;
});
obj.html(replace);
});
Example CSS:
.firstWord {
font-size: 15px;
}
.menuHeader {
margin-left: 10px;
float: left;
font-size: 40px;
}
.menu {
width: 100%;
height: 120px;
background-color: #FF8C00;
}
Take a look at a working demo
Update to the demo reflect code from comment.
Use the selector:
$('#header > ul.nav > li > a')
To select only the first menu item. You should only need to add:
.firstWord {
font-size: 15px;
}
To your CSS to adjust the size of the first item.
Good suggestion by Edwin V., you could change the jQuery to:
$('#header > ul.nav > li > a').each(function() {
var obj = $(this);
var text = obj.html();
var parts = text.split(' ');
var replace = '<span class="firstWord">'+parts[0]+'</span><br />';
parts.shift();
replace += parts.join(' ');
obj.html(replace);
});
To shorten it a little. Demo here..

Categories