jquery cannot get div to show using this selector - javascript

I am querying the Twitch API for a list of users in my database, to see if they are online.
I am essentially listing them all, with "display: none" and then unhiding if online:
$('.online_list').each(function (index) {
var tnick = $(this).data('tnick');
$.getJSON("https://api.twitch.tv/kraken/streams?client_id={:twitch_key}&channel="+tnick+"", function(a) {
if (a["streams"].length > 0)
{
alert(tnick);
$(this).show();
console.log(index + ": " + $( this ).text());
}
});
});
In my testing, the alert(tnick) works perfectly, so I know it's running. The problem is $(this).show(); just isn't working.
Here's example HTML:
<div class="online_list" data-tnick="test" style="display: none;">test:Twitch <span>(Online)</span></div>
<div class="online_list" data-tnick="test2" style="display: none;">test2:Twitch <span>(Online)</span></div>

this is the current scope object!
to fix your code you can do the following:
$('.online_list').each(function (index) {
var $that = $(this); // create a temp var that
var tnick = $that.data('tnick');
$.getJSON("https://api.twitch.tv/kraken/streams?client_id={:twitch_key}&channel="+tnick+"", function(a) {
if (a && a["streams"] && a["streams"].length > 0) {
alert(tnick);
$that.show(); // use that instead of this
console.log(index + ": " + $that.text());
}
});
});
Check out this resource for more information on scope & this: http://javascriptplayground.com/blog/2012/04/javascript-variable-scope-this/

EDIT:
Also, like #djxak suggests, you can use the element parameter of the callback, that is more simple and clean in my opinion.
The #djxak suggests:
$('.online_list').each(function (index, element) {
//... (scope1 code)
$.getJSON("", function(a) {
//... (scope2 code)
$(element).show();
});
});
My approach:
$('.online_list').each(function (index) {
//... (scope1 code)
var $current = $(this);
$.getJSON("", function(a) {
//... (scope2 code)
$current.show();
});
});
Info about each function and element parameter in jQuery docs: https://api.jquery.com/each/#each-function

Related

How to get the string passed to jquery? [duplicate]

$("*").click(function(){
$(this); // how can I get selector from $(this) ?
});
Is there an easy way to get selector from $(this)? There is a way to select an element by its selector, but what about getting the selector from element?
Ok, so in a comment above the question asker Fidilip said that what he/she's really after is to get the path to the current element.
Here's a script that will "climb" the DOM ancestor tree and then build fairly specific selector including any id or class attributes on the item clicked.
See it working on jsFiddle: http://jsfiddle.net/Jkj2n/209/
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>
$(function() {
$("*").on("click", function(e) {
e.preventDefault();
var selector = $(this)
.parents()
.map(function() { return this.tagName; })
.get()
.reverse()
.concat([this.nodeName])
.join(">");
var id = $(this).attr("id");
if (id) {
selector += "#"+ id;
}
var classNames = $(this).attr("class");
if (classNames) {
selector += "." + $.trim(classNames).replace(/\s/gi, ".");
}
alert(selector);
});
});
</script>
</head>
<body>
<h1><span>I love</span> jQuery</h1>
<div>
<p>It's the <strong>BEST THING</strong> ever</p>
<button id="myButton">Button test</button>
</div>
<ul>
<li>Item one
<ul>
<li id="sub2" >Sub one</li>
<li id="sub2" class="subitem otherclass">Sub two</li>
</ul>
</li>
</ul>
</body>
</html>
For example, if you were to click the 2nd list nested list item in the HTML below, you would get the following result:
HTML>BODY>UL>LI>UL>LI#sub2.subitem.otherclass
::WARNING:: .selector has been deprecated as of version 1.7, removed as of 1.9
The jQuery object has a selector property I saw when digging in its code yesterday. Don't know if it's defined in the docs are how reliable it is (for future proofing). But it works!
$('*').selector // returns *
Edit: If you were to find the selector inside the event, that information should ideally be part of the event itself and not the element because an element could have multiple click events assigned through various selectors. A solution would be to use a wrapper to around bind(), click() etc. to add events instead of adding it directly.
jQuery.fn.addEvent = function(type, handler) {
this.bind(type, {'selector': this.selector}, handler);
};
The selector is being passed as an object's property named selector. Access it as event.data.selector.
Let's try it on some markup (http://jsfiddle.net/DFh7z/):
<p class='info'>some text and <a>a link</a></p>​
$('p a').addEvent('click', function(event) {
alert(event.data.selector); // p a
});
Disclaimer: Remember that just as with live() events, the selector property may be invalid if DOM traversal methods are used.
<div><a>a link</a></div>
The code below will NOT work, as live relies on the selector property
which in this case is a.parent() - an invalid selector.
$('a').parent().live(function() { alert('something'); });
Our addEvent method will fire, but you too will see the wrong selector - a.parent().
In collaboration with #drzaus we've come up with the following jQuery plugin.
jQuery.getSelector
!(function ($, undefined) {
/// adapted http://jsfiddle.net/drzaus/Hgjfh/5/
var get_selector = function (element) {
var pieces = [];
for (; element && element.tagName !== undefined; element = element.parentNode) {
if (element.className) {
var classes = element.className.split(' ');
for (var i in classes) {
if (classes.hasOwnProperty(i) && classes[i]) {
pieces.unshift(classes[i]);
pieces.unshift('.');
}
}
}
if (element.id && !/\s/.test(element.id)) {
pieces.unshift(element.id);
pieces.unshift('#');
}
pieces.unshift(element.tagName);
pieces.unshift(' > ');
}
return pieces.slice(1).join('');
};
$.fn.getSelector = function (only_one) {
if (true === only_one) {
return get_selector(this[0]);
} else {
return $.map(this, function (el) {
return get_selector(el);
});
}
};
})(window.jQuery);
Minified Javascript
// http://stackoverflow.com/questions/2420970/how-can-i-get-selector-from-jquery-object/15623322#15623322
!function(e,t){var n=function(e){var n=[];for(;e&&e.tagName!==t;e=e.parentNode){if(e.className){var r=e.className.split(" ");for(var i in r){if(r.hasOwnProperty(i)&&r[i]){n.unshift(r[i]);n.unshift(".")}}}if(e.id&&!/\s/.test(e.id)){n.unshift(e.id);n.unshift("#")}n.unshift(e.tagName);n.unshift(" > ")}return n.slice(1).join("")};e.fn.getSelector=function(t){if(true===t){return n(this[0])}else{return e.map(this,function(e){return n(e)})}}}(window.jQuery)
Usage and Gotchas
<html>
<head>...</head>
<body>
<div id="sidebar">
<ul>
<li>
Home
</li>
</ul>
</div>
<div id="main">
<h1 id="title">Welcome</h1>
</div>
<script type="text/javascript">
// Simple use case
$('#main').getSelector(); // => 'HTML > BODY > DIV#main'
// If there are multiple matches then an array will be returned
$('body > div').getSelector(); // => ['HTML > BODY > DIV#main', 'HTML > BODY > DIV#sidebar']
// Passing true to the method will cause it to return the selector for the first match
$('body > div').getSelector(true); // => 'HTML > BODY > DIV#main'
</script>
</body>
</html>
Fiddle w/ QUnit tests
http://jsfiddle.net/CALY5/5/
Did you try this ?
$("*").click(function(){
$(this).attr("id");
});
Try this:
$("*").click(function(event){
console.log($(event.handleObj.selector));
});
Well, I wrote this simple jQuery plugin.
This checkes id or class name, and try to give as much exact selector as possible.
jQuery.fn.getSelector = function() {
if ($(this).attr('id')) {
return '#' + $(this).attr('id');
}
if ($(this).prop("tagName").toLowerCase() == 'body') return 'body';
var myOwn = $(this).attr('class');
if (!myOwn) {
myOwn = '>' + $(this).prop("tagName");
} else {
myOwn = '.' + myOwn.split(' ').join('.');
}
return $(this).parent().getSelector() + ' ' + myOwn;
}
Just add a layer over the $ function this way:
$ = (function(jQ) {
return (function() {
var fnc = jQ.apply(this,arguments);
fnc.selector = (arguments.length>0)?arguments[0]:null;
return fnc;
});
})($);
Now you can do things like $("a").selector and will return "a" even on newer jQuery versions.
http://www.selectorgadget.com/ is a bookmarklet designed explicitly for this use case.
That said, I agree with most other people in that you should just learn CSS selectors yourself, trying to generate them with code is not sustainable. :)
I added some fixes to #jessegavin's fix.
This will return right away if there is an ID on the element. I also added a name attribute check and a nth-child selector in case a element has no id, class, or name.
The name might need scoping in case there a multiple forms on the page and have similar inputs, but I didn't handle that yet.
function getSelector(el){
var $el = $(el);
var id = $el.attr("id");
if (id) { //"should" only be one of these if theres an ID
return "#"+ id;
}
var selector = $el.parents()
.map(function() { return this.tagName; })
.get().reverse().join(" ");
if (selector) {
selector += " "+ $el[0].nodeName;
}
var classNames = $el.attr("class");
if (classNames) {
selector += "." + $.trim(classNames).replace(/\s/gi, ".");
}
var name = $el.attr('name');
if (name) {
selector += "[name='" + name + "']";
}
if (!name){
var index = $el.index();
if (index) {
index = index + 1;
selector += ":nth-child(" + index + ")";
}
}
return selector;
}
I've released a jQuery plugin: jQuery Selectorator, you can get selector like this.
$("*").on("click", function(){
alert($(this).getSelector().join("\n"));
return false;
});
I was getting multiple elements even after above solutions, so i extended dds1024 work, for even more pin-pointing dom element.
e.g. DIV:nth-child(1) DIV:nth-child(3) DIV:nth-child(1) ARTICLE:nth-child(1) DIV:nth-child(1) DIV:nth-child(8) DIV:nth-child(2) DIV:nth-child(1) DIV:nth-child(2) DIV:nth-child(1) H4:nth-child(2)
Code:
function getSelector(el)
{
var $el = jQuery(el);
var selector = $el.parents(":not(html,body)")
.map(function() {
var i = jQuery(this).index();
i_str = '';
if (typeof i != 'undefined')
{
i = i + 1;
i_str += ":nth-child(" + i + ")";
}
return this.tagName + i_str;
})
.get().reverse().join(" ");
if (selector) {
selector += " "+ $el[0].nodeName;
}
var index = $el.index();
if (typeof index != 'undefined') {
index = index + 1;
selector += ":nth-child(" + index + ")";
}
return selector;
}
Taking in account some answers read here I'd like to propose this:
function getSelectorFromElement($el) {
if (!$el || !$el.length) {
return ;
}
function _getChildSelector(index) {
if (typeof index === 'undefined') {
return '';
}
index = index + 1;
return ':nth-child(' + index + ')';
}
function _getIdAndClassNames($el) {
var selector = '';
// attach id if exists
var elId = $el.attr('id');
if(elId){
selector += '#' + elId;
}
// attach class names if exists
var classNames = $el.attr('class');
if(classNames){
selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
}
return selector;
}
// get all parents siblings index and element's tag name,
// except html and body elements
var selector = $el.parents(':not(html,body)')
.map(function() {
var parentIndex = $(this).index();
return this.tagName + _getChildSelector(parentIndex);
})
.get()
.reverse()
.join(' ');
if (selector) {
// get node name from the element itself
selector += ' ' + $el[0].nodeName +
// get child selector from element ifself
_getChildSelector($el.index());
}
selector += _getIdAndClassNames($el);
return selector;
}
Maybe useful to create a jQuery plugin?
This can get you selector path of clicked HTML element-
$("*").on("click", function() {
let selectorPath = $(this).parents().map(function () {return this.tagName;}).get().reverse().join("->");
alert(selectorPath);
return false;
});
Are you trying to get the name of the current tag that was clicked?
If so, do this..
$("*").click(function(){
alert($(this)[0].nodeName);
});
You can't really get the "selector", the "selector" in your case is *.
Javascript code for the same, in case any one needs, as i needed it. This just the translation only of the above selected answer.
<script type="text/javascript">
function getAllParents(element){
var a = element;
var els = [];
while (a && a.nodeName != "#document") {
els.unshift(a.nodeName);
a = a.parentNode;
}
return els.join(" ");
}
function getJquerySelector(element){
var selector = getAllParents(element);
/* if(selector){
selector += " " + element.nodeName;
} */
var id = element.getAttribute("id");
if(id){
selector += "#" + id;
}
var classNames = element.getAttribute("class");
if(classNames){
selector += "." + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, ".");
}
console.log(selector);
alert(selector);
return selector;
}
</script>
Thank you p1nox!
My problem was to put focus back on an ajax call that was modifying part of the form.
$.ajax({ url : "ajax_invite_load.php",
async : true,
type : 'POST',
data : ...
dataType : 'html',
success : function(html, statut) {
var focus = $(document.activeElement).getSelector();
$td_left.html(html);
$(focus).focus();
}
});
I just needed to encapsulate your function in a jQuery plugin:
!(function ($, undefined) {
$.fn.getSelector = function () {
if (!this || !this.length) {
return ;
}
function _getChildSelector(index) {
if (typeof index === 'undefined') {
return '';
}
index = index + 1;
return ':nth-child(' + index + ')';
}
function _getIdAndClassNames($el) {
var selector = '';
// attach id if exists
var elId = $el.attr('id');
if(elId){
selector += '#' + elId;
}
// attach class names if exists
var classNames = $el.attr('class');
if(classNames){
selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
}
return selector;
}
// get all parents siblings index and element's tag name,
// except html and body elements
var selector = this.parents(':not(html,body)')
.map(function() {
var parentIndex = $(this).index();
return this.tagName + _getChildSelector(parentIndex);
})
.get()
.reverse()
.join(' ');
if (selector) {
// get node name from the element itself
selector += ' ' + this[0].nodeName +
// get child selector from element ifself
_getChildSelector(this.index());
}
selector += _getIdAndClassNames(this);
return selector;
}
})(window.jQuery);
This won't show you the DOM path, but it will output a string representation of what you see in eg chrome debugger, when viewing an object.
$('.mybtn').click( function(event){
console.log("%s", this); // output: "button.mybtn"
});
https://developer.chrome.com/devtools/docs/console-api#consolelogobject-object
How about:
var selector = "*"
$(selector).click(function() {
alert(selector);
});
I don't believe jQuery store the selector text that was used. After all, how would that work if you did something like this:
$("div").find("a").click(function() {
// what would expect the 'selector' to be here?
});
The best answer would be
var selector = '#something';
$(selector).anything(function(){
console.log(selector);
});

Limit textarea characters by ID jquery

The goal: I'm trying to limit all my text boxes in all DIV ID named #boom1.
The problem: Can't get them all (a problem with the loop method in my opinion)
$(function () {
var maxL = 300;
$('#boom1').each(function (i, div) { //I got lost with syntax over here
var text = $('#boom1').text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$('#boom1').html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
})
})
I'll be glad to get some help, with syntax if possible..
Thanks.
Attaching a DEMO
try using following code, working fine
$(function () {
var maxL = 300;
$('.wp-caption-text').each(function (i, div) {
//alert("dfs");
var text = $(this).text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$(this).html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
})
})
$(function () {
var maxL = 300;
$('#boom1').each(function () { // If you don't use them you won't need them here
var text = $('#boom1').text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$('#boom1').html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
});
});
DEMO
id must be unique.
Use classes for multiple usage .
added class boom to each div.
added read less... and read more... toggling feature too.
$(this) refers to the current element in the loop.
$(function () {
var maxL = 300;
$('.boom').each(function (i, div) {
var text = $(this).text();
if (text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$(this).html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).html(function(_,ctr){
return (ctr == 'read more...') ? 'read less...':'read more...'
});
$(this).next('.hidden').slideToggle(750);
});
});
.each() makes you loop through all instances of an element, so you shouldn't use an ID. The following would iterate on every "some-class" element.
<div class="some-class"></div>
<div class="some-class"></div>
$('.some-class').each(function (i, div) {/* code*/ });
I don't think you can use each on an id - it will only get you the first one. Identifiers should be unique and only appear once per page. So only the first one will be used.
Try adding a class to each '#boom1'.. for example '.boom-class' and then doing jQuery each on it.

Match url folders with a tag href to make an active state

I made an active state for my menu on a certain urls. I have urls like this:
/products/other-clothing/sporting/adults-anzac-australia-polo
/products/other-clothing/sporting/adults-nz-tee
/products/bags/backpacks
My code gets the folder from after the / so other-clothing, sporting, etc.
It is working fine, I just assume there is a more efficient way to write the code.
Here is my code:
jQuery(".product-nav li a").each(function() {
// URL url
var cat = location.pathname.split("/")[2];
var subcat = location.pathname.split("/")[3];
var c = "/products/" + cat + "/" + subcat;
// A tag url
var acat = this.href.split("/")[4];
var asubcat = this.href.split("/")[5];
var e = "/products/" + acat + "/" + asubcat;
if(e == c) {
jQuery(this).parent().addClass("active");
jQuery(this).parent().parent().parent().addClass("active");
}
});
If anyone can provide a cleaner way of writing the code that'd be great. I probably dont need "/products/" +.
Notice the output of the following expressions:
$('')[0].href;
/*
* http://stackoverflow.com/questions/7564539/match-url-folders-with-a-tag-href-to-make-a-active-state
*/
$('').eq(0).attr('href');
/*
* /questions/7564539/match-url-folders-with-a-tag-href-to-make-a-active-state
*/
So, if your <a> tags contain URLs that start with / then you can compare the .attr('href') with location.pathname. For testing, try running this in console from this page:
$('a').each(function () {
if ($(this).attr('href') == location.pathname) {
$(this).css({
'font-size': '40px',
'background-color': 'lime'
});
}
});
Here's a brief whack at it:
jQuery(".product-nav li a").each(function() {
// URL url
var c = location.pathname.split('/').slice(2, 4)
// A tag url
, e = this.href.split('/').slice(4, 6)
;
if(e[0] == c[0] && e[1] == c[1]) {
jQuery(this).parentsUntil(
'div:not(.subnav)', // go up the tree until the 1st div that isn't .subnav
'.product-nav li, .subnav' // and only match these parents
).addClass('active');
}
});
.parent().parent().parent()... has a pretty bad code smell to it but can't be improved without a look at your markup. You should probably be using .closest() instead.
Interesting question. Here is my attempt to clean it up:
jQuery(function ($) {
function Category(outer, inner) {
this.outer = outer
this.inner = inner
}
Category.fromURL = function (url) {
var parts = url.replace(/^(https?:\/\/.*?)?\//, "").split("/")
return new Category(parts[1], parts[2])
}
Category.prototype.equals = function (other) {
return this.outer === other.outer
&& this.inner === other.inner
}
var category = Subcategory.fromURL(location.href)
$(".product-nav a").each(function () {
if (Category.fromURL(this.href).equals(category)) {
$(this).closest("li.inner").addClass("active")
$(this).closest("li.outer").addClass("active")
}
})
})

Event doesn't get added in a for-loop

This is the html. If a link is clicked I want to replace the span-element in front of it with some text.
<p><span id="sp1">that1</span> Update1</p>
<p><span id="sp2">that2</span> Update2</p>
<p><span id="sp3">that3</span> Update3</p>
<p><span id="sp4">that4</span> Update4</p>
<p><span id="sp5">that5</span> Update5</p>
As you can see, my idea was to give the spans en the anchors identical id's and a number.
In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.
<script type="text/javascript" >
$(document).ready(function() {
var numSpans = $("span").length;
for (n=0;n<=numSpans;n++) {
$("a#update" + n).click(function(e){
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
});
</script>
For some reason this does not work.
What am I doing wrong?
The problem with your original code is that you're creating a closure on the variable n. When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(function(e) {
alert(n); //Alerts '6'
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
})
One way to fix this is to create a closure on the value of n in each iteration, like so:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(
(function(k) {
return function(e) {
alert(k);
$('span#sp' + k).replaceWith('this');
e.preventDefault();
}
})(n)
);
}
})
However, this is messy, and you'd do better to use a more jQuery-y method.
One way to do this would be to remove the ids from your code. Unless you need them for something else, they're not required:
<p><span>that1</span> Update1</p>
<p><span>that2</span> Update2</p>
<p><span>that3</span> Update3</p>
<p><span>that4</span> Update4</p>
<p><span>that5</span> Update5</p>
jQuery:
$(function() {
$('a.update').live('click', function() {
$(this).siblings('span').replaceWith("Updated that!");
});
});
jsFiddle
Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.
$(function()
{
$('span[id^=sp]').each(function(n)
{
$('#update' + n).click(function(e)
{
$('#sp' + n).replaceWith(this);
return false;
});
});
});
Demo: http://jsfiddle.net/mattball/4TVMa/
You can do way better than that, though:
$(function()
{
$('p > a[id^=update]').live('click', function(e)
{
$(this).prev().replaceWith(this);
return false;
});
});
Demo: http://jsfiddle.net/mattball/xySGW/
Try this:
$(function(){
$("a[id^='update']").click(function(){
var index = this.id.replace(/[^0-9]/g, "");
$("span#sp" + index).replaceWith(this);
e.preventDefault();
});
});

How can I get selector from jQuery object

$("*").click(function(){
$(this); // how can I get selector from $(this) ?
});
Is there an easy way to get selector from $(this)? There is a way to select an element by its selector, but what about getting the selector from element?
Ok, so in a comment above the question asker Fidilip said that what he/she's really after is to get the path to the current element.
Here's a script that will "climb" the DOM ancestor tree and then build fairly specific selector including any id or class attributes on the item clicked.
See it working on jsFiddle: http://jsfiddle.net/Jkj2n/209/
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>
$(function() {
$("*").on("click", function(e) {
e.preventDefault();
var selector = $(this)
.parents()
.map(function() { return this.tagName; })
.get()
.reverse()
.concat([this.nodeName])
.join(">");
var id = $(this).attr("id");
if (id) {
selector += "#"+ id;
}
var classNames = $(this).attr("class");
if (classNames) {
selector += "." + $.trim(classNames).replace(/\s/gi, ".");
}
alert(selector);
});
});
</script>
</head>
<body>
<h1><span>I love</span> jQuery</h1>
<div>
<p>It's the <strong>BEST THING</strong> ever</p>
<button id="myButton">Button test</button>
</div>
<ul>
<li>Item one
<ul>
<li id="sub2" >Sub one</li>
<li id="sub2" class="subitem otherclass">Sub two</li>
</ul>
</li>
</ul>
</body>
</html>
For example, if you were to click the 2nd list nested list item in the HTML below, you would get the following result:
HTML>BODY>UL>LI>UL>LI#sub2.subitem.otherclass
::WARNING:: .selector has been deprecated as of version 1.7, removed as of 1.9
The jQuery object has a selector property I saw when digging in its code yesterday. Don't know if it's defined in the docs are how reliable it is (for future proofing). But it works!
$('*').selector // returns *
Edit: If you were to find the selector inside the event, that information should ideally be part of the event itself and not the element because an element could have multiple click events assigned through various selectors. A solution would be to use a wrapper to around bind(), click() etc. to add events instead of adding it directly.
jQuery.fn.addEvent = function(type, handler) {
this.bind(type, {'selector': this.selector}, handler);
};
The selector is being passed as an object's property named selector. Access it as event.data.selector.
Let's try it on some markup (http://jsfiddle.net/DFh7z/):
<p class='info'>some text and <a>a link</a></p>​
$('p a').addEvent('click', function(event) {
alert(event.data.selector); // p a
});
Disclaimer: Remember that just as with live() events, the selector property may be invalid if DOM traversal methods are used.
<div><a>a link</a></div>
The code below will NOT work, as live relies on the selector property
which in this case is a.parent() - an invalid selector.
$('a').parent().live(function() { alert('something'); });
Our addEvent method will fire, but you too will see the wrong selector - a.parent().
In collaboration with #drzaus we've come up with the following jQuery plugin.
jQuery.getSelector
!(function ($, undefined) {
/// adapted http://jsfiddle.net/drzaus/Hgjfh/5/
var get_selector = function (element) {
var pieces = [];
for (; element && element.tagName !== undefined; element = element.parentNode) {
if (element.className) {
var classes = element.className.split(' ');
for (var i in classes) {
if (classes.hasOwnProperty(i) && classes[i]) {
pieces.unshift(classes[i]);
pieces.unshift('.');
}
}
}
if (element.id && !/\s/.test(element.id)) {
pieces.unshift(element.id);
pieces.unshift('#');
}
pieces.unshift(element.tagName);
pieces.unshift(' > ');
}
return pieces.slice(1).join('');
};
$.fn.getSelector = function (only_one) {
if (true === only_one) {
return get_selector(this[0]);
} else {
return $.map(this, function (el) {
return get_selector(el);
});
}
};
})(window.jQuery);
Minified Javascript
// http://stackoverflow.com/questions/2420970/how-can-i-get-selector-from-jquery-object/15623322#15623322
!function(e,t){var n=function(e){var n=[];for(;e&&e.tagName!==t;e=e.parentNode){if(e.className){var r=e.className.split(" ");for(var i in r){if(r.hasOwnProperty(i)&&r[i]){n.unshift(r[i]);n.unshift(".")}}}if(e.id&&!/\s/.test(e.id)){n.unshift(e.id);n.unshift("#")}n.unshift(e.tagName);n.unshift(" > ")}return n.slice(1).join("")};e.fn.getSelector=function(t){if(true===t){return n(this[0])}else{return e.map(this,function(e){return n(e)})}}}(window.jQuery)
Usage and Gotchas
<html>
<head>...</head>
<body>
<div id="sidebar">
<ul>
<li>
Home
</li>
</ul>
</div>
<div id="main">
<h1 id="title">Welcome</h1>
</div>
<script type="text/javascript">
// Simple use case
$('#main').getSelector(); // => 'HTML > BODY > DIV#main'
// If there are multiple matches then an array will be returned
$('body > div').getSelector(); // => ['HTML > BODY > DIV#main', 'HTML > BODY > DIV#sidebar']
// Passing true to the method will cause it to return the selector for the first match
$('body > div').getSelector(true); // => 'HTML > BODY > DIV#main'
</script>
</body>
</html>
Fiddle w/ QUnit tests
http://jsfiddle.net/CALY5/5/
Did you try this ?
$("*").click(function(){
$(this).attr("id");
});
Try this:
$("*").click(function(event){
console.log($(event.handleObj.selector));
});
Well, I wrote this simple jQuery plugin.
This checkes id or class name, and try to give as much exact selector as possible.
jQuery.fn.getSelector = function() {
if ($(this).attr('id')) {
return '#' + $(this).attr('id');
}
if ($(this).prop("tagName").toLowerCase() == 'body') return 'body';
var myOwn = $(this).attr('class');
if (!myOwn) {
myOwn = '>' + $(this).prop("tagName");
} else {
myOwn = '.' + myOwn.split(' ').join('.');
}
return $(this).parent().getSelector() + ' ' + myOwn;
}
Just add a layer over the $ function this way:
$ = (function(jQ) {
return (function() {
var fnc = jQ.apply(this,arguments);
fnc.selector = (arguments.length>0)?arguments[0]:null;
return fnc;
});
})($);
Now you can do things like $("a").selector and will return "a" even on newer jQuery versions.
http://www.selectorgadget.com/ is a bookmarklet designed explicitly for this use case.
That said, I agree with most other people in that you should just learn CSS selectors yourself, trying to generate them with code is not sustainable. :)
I added some fixes to #jessegavin's fix.
This will return right away if there is an ID on the element. I also added a name attribute check and a nth-child selector in case a element has no id, class, or name.
The name might need scoping in case there a multiple forms on the page and have similar inputs, but I didn't handle that yet.
function getSelector(el){
var $el = $(el);
var id = $el.attr("id");
if (id) { //"should" only be one of these if theres an ID
return "#"+ id;
}
var selector = $el.parents()
.map(function() { return this.tagName; })
.get().reverse().join(" ");
if (selector) {
selector += " "+ $el[0].nodeName;
}
var classNames = $el.attr("class");
if (classNames) {
selector += "." + $.trim(classNames).replace(/\s/gi, ".");
}
var name = $el.attr('name');
if (name) {
selector += "[name='" + name + "']";
}
if (!name){
var index = $el.index();
if (index) {
index = index + 1;
selector += ":nth-child(" + index + ")";
}
}
return selector;
}
I've released a jQuery plugin: jQuery Selectorator, you can get selector like this.
$("*").on("click", function(){
alert($(this).getSelector().join("\n"));
return false;
});
I was getting multiple elements even after above solutions, so i extended dds1024 work, for even more pin-pointing dom element.
e.g. DIV:nth-child(1) DIV:nth-child(3) DIV:nth-child(1) ARTICLE:nth-child(1) DIV:nth-child(1) DIV:nth-child(8) DIV:nth-child(2) DIV:nth-child(1) DIV:nth-child(2) DIV:nth-child(1) H4:nth-child(2)
Code:
function getSelector(el)
{
var $el = jQuery(el);
var selector = $el.parents(":not(html,body)")
.map(function() {
var i = jQuery(this).index();
i_str = '';
if (typeof i != 'undefined')
{
i = i + 1;
i_str += ":nth-child(" + i + ")";
}
return this.tagName + i_str;
})
.get().reverse().join(" ");
if (selector) {
selector += " "+ $el[0].nodeName;
}
var index = $el.index();
if (typeof index != 'undefined') {
index = index + 1;
selector += ":nth-child(" + index + ")";
}
return selector;
}
Taking in account some answers read here I'd like to propose this:
function getSelectorFromElement($el) {
if (!$el || !$el.length) {
return ;
}
function _getChildSelector(index) {
if (typeof index === 'undefined') {
return '';
}
index = index + 1;
return ':nth-child(' + index + ')';
}
function _getIdAndClassNames($el) {
var selector = '';
// attach id if exists
var elId = $el.attr('id');
if(elId){
selector += '#' + elId;
}
// attach class names if exists
var classNames = $el.attr('class');
if(classNames){
selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
}
return selector;
}
// get all parents siblings index and element's tag name,
// except html and body elements
var selector = $el.parents(':not(html,body)')
.map(function() {
var parentIndex = $(this).index();
return this.tagName + _getChildSelector(parentIndex);
})
.get()
.reverse()
.join(' ');
if (selector) {
// get node name from the element itself
selector += ' ' + $el[0].nodeName +
// get child selector from element ifself
_getChildSelector($el.index());
}
selector += _getIdAndClassNames($el);
return selector;
}
Maybe useful to create a jQuery plugin?
This can get you selector path of clicked HTML element-
$("*").on("click", function() {
let selectorPath = $(this).parents().map(function () {return this.tagName;}).get().reverse().join("->");
alert(selectorPath);
return false;
});
Are you trying to get the name of the current tag that was clicked?
If so, do this..
$("*").click(function(){
alert($(this)[0].nodeName);
});
You can't really get the "selector", the "selector" in your case is *.
Javascript code for the same, in case any one needs, as i needed it. This just the translation only of the above selected answer.
<script type="text/javascript">
function getAllParents(element){
var a = element;
var els = [];
while (a && a.nodeName != "#document") {
els.unshift(a.nodeName);
a = a.parentNode;
}
return els.join(" ");
}
function getJquerySelector(element){
var selector = getAllParents(element);
/* if(selector){
selector += " " + element.nodeName;
} */
var id = element.getAttribute("id");
if(id){
selector += "#" + id;
}
var classNames = element.getAttribute("class");
if(classNames){
selector += "." + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, ".");
}
console.log(selector);
alert(selector);
return selector;
}
</script>
Thank you p1nox!
My problem was to put focus back on an ajax call that was modifying part of the form.
$.ajax({ url : "ajax_invite_load.php",
async : true,
type : 'POST',
data : ...
dataType : 'html',
success : function(html, statut) {
var focus = $(document.activeElement).getSelector();
$td_left.html(html);
$(focus).focus();
}
});
I just needed to encapsulate your function in a jQuery plugin:
!(function ($, undefined) {
$.fn.getSelector = function () {
if (!this || !this.length) {
return ;
}
function _getChildSelector(index) {
if (typeof index === 'undefined') {
return '';
}
index = index + 1;
return ':nth-child(' + index + ')';
}
function _getIdAndClassNames($el) {
var selector = '';
// attach id if exists
var elId = $el.attr('id');
if(elId){
selector += '#' + elId;
}
// attach class names if exists
var classNames = $el.attr('class');
if(classNames){
selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
}
return selector;
}
// get all parents siblings index and element's tag name,
// except html and body elements
var selector = this.parents(':not(html,body)')
.map(function() {
var parentIndex = $(this).index();
return this.tagName + _getChildSelector(parentIndex);
})
.get()
.reverse()
.join(' ');
if (selector) {
// get node name from the element itself
selector += ' ' + this[0].nodeName +
// get child selector from element ifself
_getChildSelector(this.index());
}
selector += _getIdAndClassNames(this);
return selector;
}
})(window.jQuery);
This won't show you the DOM path, but it will output a string representation of what you see in eg chrome debugger, when viewing an object.
$('.mybtn').click( function(event){
console.log("%s", this); // output: "button.mybtn"
});
https://developer.chrome.com/devtools/docs/console-api#consolelogobject-object
How about:
var selector = "*"
$(selector).click(function() {
alert(selector);
});
I don't believe jQuery store the selector text that was used. After all, how would that work if you did something like this:
$("div").find("a").click(function() {
// what would expect the 'selector' to be here?
});
The best answer would be
var selector = '#something';
$(selector).anything(function(){
console.log(selector);
});

Categories

Resources