JavaScript/jQuery: hasDescendant / hasAncestor - javascript

Hilariously, I'm having incredible difficulty finding any half-good way to determine whether or not an HTML element is inside another one or not -- which seems like it should be a basic core feature of traversing and analyzing the HTML DOM. I was immensely surprised and disappointed that the "hasDescendant" (or likewise) method is missing.
I'm trying to do this:
var frog = $('#frog');
var walrus = $('#walrus');
if (frog.hasDescendant(walrus)) console.log("Frog is within walrus.");
else console.log("Frog is outside walrus.");
I've tried to reproduce what I'm looking for with many jQuery combinations.
walrus.is(frog.parents());
walrus.has(frog);
walrus.find(' *').has(frog);
frog.is(walrus.find(' *'));
I haven't found a working solution yet.
[edit]
Solution: walrus.has(frog)
Alternate: if (walrus.has(frog)) { doStuff(); }
Alternate: var booleanResult = walrus.has(frog).length>0;
//Chase.

jQuery has just the function for this: jQuery.contains: "Check to see if a DOM element is within another DOM element."
Demo (live copy):
HTML:
<p id="frog">Frog <span id="walrus">walrus</span></p>
JavaScript:
jQuery(function($) {
var frog = $("#frog"),
walrus = $("#walrus");
display("frog contains walrus? " + $.contains(frog[0], walrus[0]));
display("walrus contains frog? " + $.contains(walrus[0], frog[0]));
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
});

Use
if (walrus.has(frog).length) {
// frog is contained in walrus..
}
Demo at http://jsfiddle.net/gaby/pZfLm/
An alternative
if ( $('#frog').closest('#walrus').length ){
// frog is contained in walrus..
}
demo at http://jsfiddle.net/gaby/pZfLm/1/

If you wanted to write your own function you could do it without jQuery, perhaps something like this:
function isAncestor(ancestor, descendent) {
while ((descendent = descendent.parentNode) != null)
if (descendent == ancestor)
return true;
return false;
}

Related

Adding a class using JavaScript

Could anyone give me a hand with the following JavaScript issue.
I am trying to come up with a function that adds a class to a div that has a specified class.
I have tried to come up with something based on what a few people have said but it doesn't seem to work.
http://jsfiddle.net/samsungbrown/vZ9Hu/
Where am I going wrong?
Thanks
function toggleClass(matchClass,content) {
var elems = document.getElementsByTagName('*'),i;
for (i in elems) {
if((" "+elems[i].className+" ").indexOf(" "+matchClass+" ") > -1) {
elems[i].classList.toggle(content);
}
}
}
window.onload = function () {
toggleClass("col-left","display");
}
Because of some quirks in jsFiddle your code doesn't run. Remove the .onload wrapper and your code runs. See: http://jsfiddle.net/vZ9Hu/1/

javascript - trying to make an onClick alert based on id/class

I'm new to programming and was wondering how to make a customized alert that shows the id or class name of the object when I click on it. My site has a picture of 8 different animals, and I want it so that every time I click on one of the animals there's an alert with "This is a (animal's name)". Why won't my javascript code below work?
should i be using "this" instead of "parama"? i don't understand whether or not to have any parameters for my function clicky.
var images = new Array()
images[0] = "bison"
images[1] = "frog"
function clicky(parama){
for (entry in images){
if (parama.attributes["name"].value === images[entry]){
$(parama).onClick(alert("This is a" + parama.attributes["name"].value));
} else {
$(parama).onClick(alert("dang it");
}
}
}
using sort of a combination of both your answers, I figured out a way to do it with a lot less code than I originally had. Check it out! (images all had classes of "pic")
$('.pic').click(function(){
alert("This is a " + this.getAttribute('alt'))
});
I'd recommend to use the title or alt attribute on images instead of a JS array - that's more SEO friendly and semantic. Not to mention that alt is required on images to make your HTML valid - DEMO
var images = document.getElementsByTagName("img");
for ( var i = 0, count = images.length; i < count; i++ ) {
images[i].addEventListener("click", function() {
alert( this.getAttribute("alt") );
});
}
UPDATE
if you open to use jQuery - DEMO
$("img").on("click", function() {
alert( $(this).prop("alt") );
});​
You can use .click() but it's recommended to use .on() instead to attach different kind of event listeners to elements. jQuery also provides a shorthand for getting the properties - .prop()

Help me simplify this JS code

I'm a beginner in JS and want to know a way to simplify this code. There are 7 different divs with iframes, and also 7 different links. I have shown 1 div with iframe and 1 link. I have no idea where to start. Any help would be greatly appreciated.
NOTE: The code works to my needs, but I just need to simplify it (less js code in html, and more in js file).
JavaScript in .js file:
function show_visibility(){
for(var i = 0,e = arguments.length;i < e;i++){
var myDiv = document.getElementById(arguments[i]).style;
myDiv.display = "block";}
}
function hide_visibility(){
for(var i = 0,e = arguments.length;i < e;i++){
var myDiv = document.getElementById(arguments[i]).style;
myDiv.display = "none";}
}
function refFrame() {
for(var i = 0,e = arguments.length;i < e;i++){
document.getElementById(arguments[i]).src = document.getElementById(arguments[i]).src;
}
}
Div/iframe to be modified:
<div id="r1-box">
<iframe id="frame-box1" class="work" src="youtubelink" width="720" height="405" frameborder="0"></iframe>
</div>
Link to execute JS:
<a id="r1" href="javascript:refFrame('frame-box2','frame-box3','frame-box4','frame-box5','frame-box6','frame-box7');show_visibility('r1-box');hide_visibility('r2-box','r3-box', 'r4-box','r5-box','r6-box','r7-box');">
</a>
As a beginner you shouldn't start using jQuery until you understand Javascript more.
There are a few ways you could simplify this, the most immediate one would be to get the Javascript out of the link and into a Javascript file, or at the top of the page:
window.onload = function() {
document.getElementById('#r1').onclick = function() {
refFrame('frame-box2','frame-box3','frame-box4','frame-box5','frame-box6','frame-box7');
show_visibility('r1-box');
hide_visibility('r2-box','r3-box', 'r4-box','r5-box','r6-box','r7-box');
};
// more...
};
window.onload is an event which fires once the page has - you guessed it - finished loading. There are better ways of doing this, but this is about as basic as it gets. I'd advise you look at javascript domready?
After looking at your code a bit more, I realised all your seven links will do essentially the same thing. You can simply this by using a single function:
function refClick(id) {
var i = 7,
frames = [],
boxes = [];
while(i--) {
if(i != id) {
frames.push('frame-box' + i);
boxes.push('r' + i + '-box');
}
}
refFrame.apply(null, frames);
hide_visibility.apply(null, boxes);
show_visibility('r' + id + '-box');
}
What I'm doing here is looping through 7 times, and building an array of arguments for the refFrame and hide_visibility functions. The id variable tells the loop not to put in that id into the arrays.
Using the .apply method, I can apply an array as the arguments and call it normally.
For each of your links, you can apply the following function
document.getElementById('#r1').onclick = function() {
refClick(1);
};
document.getElementById('#r2').onclick = function() {
refClick(2);
};
//.....
You could start using jQuery.
http://jquery.com/

How to make custom script into Jquery like plugin

I have writtern a script to limit the number of characters in the textarea, and the code is here
<script>
function limitchar(charcount, counterId, msgId)
{
var tex = document.getElementById(msgId).value;
var len = tex.length;
if(len > charcount)
{
alert("Content Limit Exceeded");
tex = tex.substring(0,charcount);
document.getElementById(msgId).value =tex;
return false;
}
document.getElementById(counterId).innerHTML = charcount-len;
}
</script>
I am calling the function as
<textarea name="txtar1" id="txtar1" onkeyup=limitchar('10','verid','txtar1')></textarea>
I dont want these kind of ugly function call, since my textareas are dynamically generated
Like Jquery, I want my function to be called like
$('txtar1').limitchar();
Is there anyother way to achieve this. Thanks Experts! in advance
ANSWER :
Thanks for andy rose. I used his approach. Here is my final code:
<script>
$(document).ready(function() {
$('#txtar1').keydown(function() {
limiter('10', 'verid' , this.id);
});
});
</script>
<textarea name="txtar1" id="txtar1"></textarea>
<span id="verid">10</span>
<script>
/* Will use as common.js */
function limiter(charcount,showcountid,msgId)
{
var tex = document.getElementById(msgId).value;
var len = tex.length;
if(len > charcount)
{
//alert("Content Limit Exceeded");
tex = tex.substring(0,charcount);
document.getElementById(msgId).value =tex;
return false;
}
document.getElementById(showcountid).innerHTML = charcount-len;
}
</script>
You might want to look at this blog entry from Mike Alsup in which he explains a pretty good pattern on how to develop a jQuery-Plugin. He also goes into very much details about further development and extending the basic plugin.
Rather than creating a new plugin why not use one of jQuery's key events:
$('txtar1').keydown(function() {
...stuff here
});
It's easy. Just do:
$.fn.limitchar = function () {
var $items = $(this);
};
$items will be a jQuery object equivalent to $('txtar1').

How to best utilize jQuery to programmatically generate HTML elements

I have a bunch of Javascript functions that look like the following:
function generateBusinessImage (business) {
var business_image = document.createElement('img');
business_image.setAttribute('class','photo');
business_image.alt = business.name;
business_image.title = business.name;
business_image.align = 'right';
business_image.src = business.photo_url;
return business_image;
}
This seems like a good canidate for a refactor. From reviewing a few different jQuery docs, it would appear that I should be able to do something similar to this pseudo code:
return var business_image = document.createElement('img').
setAttribute('class','photo').
alt(business.name).
title(business.title).
align('right').
src(business.photo_url);
Am I on the right track?
Thanks!
EDIT
I'm calling the function above with the following code and the line where I do appendChild on div with generateBusinessImage is where my errors are occurring with some of the answers below:
var div = document.createElement('div');
var div_class = document.createAttribute('class');
div.setAttribute('class','business');
div.appendChild(generateBusinessImage(business));
You can create all that with jQuery via chained calls:
function generateBusinessImage (business) {
return $('<img class="photo" align="right" />')
.attr('alt', business.name)
.attr('title', business.name)
.attr('src', business.photo_url)
.get(0)
}
(Note on the get(0) on the last line: to remain backwards compatible with your existing caller of generateBusinessImage() I return the DOM element jQuery created, by calling .get(0))
References:
jQuery.attr
jQuery.fn.get
Yes, you are right. Generally, it is, however, thought to be faster to actually do string concatenation (albeit, it is a bit sloppier).
To do what you want in jquery, it would be like so:
function generateBusinessImage (business) {
var $business_image = $('<img />');
$business_image
.addClass('photo')
.attr('alt',business.name)
.attr('title',business.name)
.attr('align','right')
.attr('src',business.photo_url);
return $business_image;
}
To be perfectly honest, though, this will be faster (but uglier code):
function generateBusinessImage(business) {
return $('<img src="'+business.photo_url+'" alt="'+business.name+'" title="'+business.name+'" align="right" class="photo" />');
}

Categories

Resources