javascript find selector of an element - javascript

what i want is to detect which elements clicks by user and send those selector query to server
I don't want to use any library and want to do this only by javascript itself, my code listen document.onclick and I could get event.target and do some stuff in real time, but I want store this element selector query in server for future usage
document.onclick = function (event) {
var target = event.target;
var selector ; //
}
how get event.target unique selector? and use this selector in document.querySelector and access to element

I built a function in Javascript without Jquery that creates a unique identifier for any element in the DOM. If it has an id it uses the id. Otherwise it creates a path based on the parents of that element:
function getSelector(node) {
var id = node.getAttribute('id');
if (id) {
return '#'+id;
}
var path = '';
while (node) {
var name = node.localName;
var parent = node.parentNode;
if (!parent) {
path = name + ' > ' + path;
continue;
}
if (node.getAttribute('id')) {
path = '#' + node.getAttribute('id') + ' > ' + path;
break;
}
var sameTagSiblings = [];
var children = parent.childNodes;
children = Array.prototype.slice.call(children);
children.forEach(function(child) {
if (child.localName == name) {
sameTagSiblings.push(child);
}
});
// if there are more than one children of that type use nth-of-type
if (sameTagSiblings.length > 1) {
var index = sameTagSiblings.indexOf(node);
name += ':nth-of-type(' + (index + 1) + ')';
}
if (path) {
path = name + ' > ' + path;
} else {
path = name;
}
node = parent;
}
return path;
}
So if you want to click on an element and get the unique selector just add:
window.addEventListener('click', function(event) {
var ele = document.elementFromPoint(event.x, event.y);
alert(getSelector(ele));
});

I suppose you mean a CSS selector. If so, it can be selected through multiple methods. If it has an id you can simply get the id from the element:
var selector = "#" + target.id;

If you want it to be very expressive you could do, or perhaps remove the else block.
const attributes = target.getAttributeNames();
let query = target.localName;
for (let i = 0; i < attributes.length; i++) {
const a = attributes[i];
const attrValue = target.getAttribute(a);
if (!attrValue) return;
if (a === 'id') {
query += `#${attrValue}`;
} else if (a === 'class') {
query += `.${attrValue.split(' ').join('.')}`;
} else {
query += `[${a}="${attrValue}"]`;
}
}

Related

How to store a reference DOM element for later use

I'm on a website, I click on any element and manipulate it
document.addEventListener('click', function(e){
e.target.innerHTML = `<span style="background: red">${e.target.innerText}</span>`
})
How can I store a reference to the element I clicked on?
I want to store a reference to the database so that when the page is reloaded, that exact same element is wrapped in a span tag.
Not thoroughly tested, but an alternative to the code in Build the querySelector string value of any given node in the DOM
Note: that code assumes well written HTML, i.e unique ID's - unfortunately, the web is full of rubbish pages that have non-unique ID's, therefore that code will fail
The result may well be a longer selector than the above code, but it seems to work - I've yet to break it :p
function getCSSPath(el) {
const fullPath = [];
const fn = el => {
let tagName = el.tagName.toLowerCase();
let elPath = '';
if (el.id) {
elPath += '#' + el.id;
}
if (el.classList.length) {
elPath += '.' + [...el.classList].join('.');
}
if (el.parentElement) {
if (el.previousElementSibling || el.nextElementSibling) {
let nthChild = 1;
for (let e = el.previousElementSibling; e; e = e.previousElementSibling, nthChild++);
tagName += `:nth-child(${nthChild})`;
}
fn(el.parentElement);
}
fullPath.push(tagName + elPath);
};
fn(el);
return fullPath.join('>');
}
I think this is better version of above though:
function getCSSPath(el) {
let elPath = el.tagName.toLowerCase();
if (el.parentElement && (el.previousElementSibling || el.nextElementSibling)) {
let nthChild = 1;
for (let e = el.previousElementSibling; e; e = e.previousElementSibling, nthChild++);
elPath += `:nth-child(${nthChild})`;
}
if (el.id) {
elPath += '#' + el.id;
}
if (el.classList.length) {
elPath += '.' + [...el.classList].join('.');
}
return (el.parentElement ? getCSSPath(el.parentElement) + '>' : '') + elPath;
}

.replace on array element not working in a loop javascript

I wanted to write a function that gets all the dom elements with the class active and remove that class. I am trying to use the replace method by looping through the array obtained from getElementsByClassName('active') and using replace to replace it with a blank space. Two questions: why isn't the replace method removing the active class and what would be a better alternative to remove class with vanilla js.
function removeItem(){
var activeItems = document.getElementsByClassName('active');
for (i=0; i<activeItems.length; i++){
var activeClass = activeItems[i].className;
activeClass.replace('active', '')
}
}
.replace() returns a string, which you must store, it doesn't overwrite the variable.
activeClass = activeClass.replace('active',''); // this will still need to be set as the classname
Something like this:
function removeClass(){
var activeItems = document.getElementsByClassName('active');
for (var i=0,n=activeItems.length; i<n; i++){
var classes = activeItems[i].className.split(' ') || [];
for (var j=0,l=classes.length; j<l; j++){
if(classes[j] === 'active') {
classes.splice(j,1);
j--;l--; // we popped a value off the stack
}
}
activeItems[i].className = classes.join(' ');
}
}
or as zzzzBov suggests, go native:
activeItems[i].classList.remove('active');
Strings are passed by value in Javascript. You must set the changed string. Also, .replace doesn't change the string but returns a new one.
activeItems[i].className = activeItems[i].className.replace('active', '');
You can use the following set of functions to add and remove class names. Plain js, no library.
// Return true or false if el has className or not
function hasClassName (el, cName) {
var re = new RegExp('(^|\\s+)' + cName + '(\\s+|$)');
return el && re.test(el.className);
}
// Add class to element if it doesn't have it already
function addClassName (el, cName) {
if (!hasClassName(el, cName)) {
el.className = trim(el.className + ' ' + cName);
}
}
// Remove className from element if it has it
function removeClassName(el, cName) {
if (hasClassName(el, cName)) {
var re = new RegExp('(^|\\s+)' + cName + '(\\s+|$)','g');
el.className = trim(el.className.replace(re, ''));
}
}
// Remove leading and trailing whitespace, reduce remaining whitespace to
// a single character
function trim(s) {
return s.replace(/(^\s+)|(\s+$)/g,'').replace(/\s+/g,' ');
}
To keep zzzzBov happy, here are the same function using a space instead of \s (also removed reliance on the RegExp constructor so should be faster too). I'd recommend sticking with \s as I haven't seen any convincing argument not to, but make you're own choice.
// Return true or false if el has className or not
function hasClassName (el, cName) {
return (' ' + el.className + ' ').indexOf(' ' + cName + ' ') != -1;
}
// Add class to element if it doesn't have it already
function addClassName (el, cName) {
if (!hasClassName(el, cName)) {
el.className = trimSpaces(el.className + ' ' + cName);
}
}
// Remove className from element if it has it
function removeClassName(el, cName) {
if (hasClassName(el, cName)) {
el.className = trimSpaces((' ' + el.className + ' ').replace(' ' + cName + ' ', ' '));
}
}
// Remove leading and trailing whitespace, reduce remaining whitespace to
// a single character
function trimSpaces(s) {
return s.replace(/(^ +)|( +$)/g,'').replace(/ +/g,' ');
}
You forgot to assign the className again.
activeItems[i].className = activeClass.replace(/(?:\s*)(active\s*)/, '');
Note that getElementsByClassName() might not work in older Browsers.
Raw JavaScript idea:
var doc = document;
function getClass(class){
if(doc.getElementsByClassName){
return doc.getElementsByClassName(class);
}
else{
var tags = doc.getElementsByTagName('*'), l = tags.length, r = [];
if(l < 1){
return false;
}
else{
var x = new RegExp('(^|\\s+)'+class+'(\\s+|$)');
for(var i=0; i<l; i++){
var tag = tags[i];
if(tag.className.match(x)){
r.push(tag);
}
}
return r;
}
}
}
function removeClass(class){
var cls = getClass(class), x = new RegExp('(^|\\s+)'+class+'(\\s+|$)');
for(var i=0,l=cls.length; i<l; i++){
var c = cls[i];
c.className = c.className.replace(x, '');
}
}

Object doesn't support this property or method in IE8 javascript

Everything works perfectly with modern browsers but for ie8 I get this error for this line:
tabValues.push(tabParams[i].split(attribute_anchor_separator));
Here the whole function:
function checkUrl()
{
if (original_url != window.location || first_url_check)
{
first_url_check = false;
url = window.location + '';
// if we need to load a specific combination
if (url.indexOf('#/') != -1)
{
// get the params to fill from a "normal" url
params = url.substring(url.indexOf('#') + 1, url.length);
tabParams = params.split('/');
tabValues = [];
if (tabParams[0] == '')
tabParams.shift();
for (var i in tabParams)
tabValues.push(tabParams[i].split(attribute_anchor_separator));
product_id = $('#product_page_product_id').val();
// fill html with values
$('.color_pick').removeClass('selected');
$('.color_pick').parent().parent().children().removeClass('selected');
count = 0;
for (var z in tabValues)
for (var a in attributesCombinations)
if (attributesCombinations[a]['group'] === decodeURIComponent(tabValues[z][0])
&& attributesCombinations[a]['attribute'] === tabValues[z][1])
{
count++;
// add class 'selected' to the selected color
$('#color_' + attributesCombinations[a]['id_attribute']).addClass('selected');
$('#color_' + attributesCombinations[a]['id_attribute']).parent().addClass('selected');
$('input:radio[value=' + attributesCombinations[a]['id_attribute'] + ']').attr('checked', true);
$('input[type=hidden][name=group_' + attributesCombinations[a]['id_attribute_group'] + ']').val(attributesCombinations[a]['id_attribute']);
$('select[name=group_' + attributesCombinations[a]['id_attribute_group'] + ']').val(attributesCombinations[a]['id_attribute']);
}
// find combination
if (count >= 0)
{
findCombination(false);
original_url = url;
return true;
}
// no combination found = removing attributes from url
else
window.location = url.substring(0, url.indexOf('#'));
}
}
return false;
}
Any ideas?? Thx!
I noticed you are using a for..in over an Array however using for..in was meant to be used for iteration over objects (not arrays):
for ( var prop in obj1 ) {
if ( obj1.hasOwnProperty(prop) ) {
// loop body goes here
}
}

Javascript Hide/Show Classes Issue

I have the following function that is supposed to get all elements in a document with the given class:
function getElementByClass(objClass)
{
// This function is similar to 'getElementByID' since there is no inherent function to get an element by it's class
var elements = (ie) ? document.all : document.getElementsByTagName('*');
for (i=0; i<elements.length; i++)
{
alert(elements[i].className);
alert(objClass);
if (elements[i].className==objClass)
{
return elements[i]
}
}
}
When I call this function with:
<script type="text/javascript">document.write(getElementByClass('done'));</script>
Nothing happens. Is there something wrong with the function?
This function does not get all elements with that class name, it gets one. And what is your intent with the way you are calling it? document.write seems like a funny thing to do with a DOM element already on your page.
I hate to just say "use jquery"... but you probably should.
Aside from the missing declaration of ie, this function does work. One problem you will have with it is if you have multiple classes on an element, this function won't work.
document.getElementsByClassName('done');
EDIT:
src: http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/
/*
Developed by Robert Nyman, http://www.robertnyman.com
Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag, elm){
if (document.getElementsByClassName) {
getElementsByClassName = function (className, tag, elm) {
elm = elm || document;
var elements = elm.getElementsByClassName(className),
nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
returnElements = [],
current;
for(var i=0, il=elements.length; i<il; i+=1){
current = elements[i];
if(!nodeName || nodeName.test(current.nodeName)) {
returnElements.push(current);
}
}
return returnElements;
};
}
else if (document.evaluate) {
getElementsByClassName = function (className, tag, elm) {
tag = tag || "*";
elm = elm || document;
var classes = className.split(" "),
classesToCheck = "",
xhtmlNamespace = "http://www.w3.org/1999/xhtml",
namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
returnElements = [],
elements,
node;
for(var j=0, jl=classes.length; j<jl; j+=1){
classesToCheck += "[contains(concat(' ', #class, ' '), ' " + classes[j] + " ')]";
}
try {
elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
}
catch (e) {
elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
}
while ((node = elements.iterateNext())) {
returnElements.push(node);
}
return returnElements;
};
}
else {
getElementsByClassName = function (className, tag, elm) {
tag = tag || "*";
elm = elm || document;
var classes = className.split(" "),
classesToCheck = [],
elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
current,
returnElements = [],
match;
for(var k=0, kl=classes.length; k<kl; k+=1){
classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
}
for(var l=0, ll=elements.length; l<ll; l+=1){
current = elements[l];
match = false;
for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
match = classesToCheck[m].test(current.className);
if (!match) {
break;
}
}
if (match) {
returnElements.push(current);
}
}
return returnElements;
};
}
return getElementsByClassName(className, tag, elm);
};
if you have posted full source then what is ie in
var elements = (ie) ? document.all : document.getElementsByTagName('*');
try to track error via firebug.
var elements = (ie) is referencing an undefined variable ie
Have you considered using a JavaScript library? Functions like this have been written many times before, painful to waste time on these kinds of things.
You should probably use getElementsByClassName when available.

How to add/remove a class in JavaScript?

Since element.classList is not supported in IE 9 and Safari-5, what's an alternative cross-browser solution?
No-frameworks please.
Solution must work in at least IE 9, Safari 5, FireFox 4, Opera 11.5, and Chrome.
Related posts (but does not contain solution):
how to add and remove css class
Add and remove a class with animation
Add remove class?
Here is solution for addClass, removeClass, hasClass in pure javascript solution.
Actually it's from http://jaketrent.com/post/addremove-classes-raw-javascript/
function hasClass(ele,cls) {
return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
Look at these oneliners:
Remove class:
element.classList.remove('hidden');
Add class (will not add it twice if already present):
element.classList.add('hidden');
Toggle class (adds the class if it's not already present and removes it if it is)
element.classList.toggle('hidden');
That's all! I made a test - 10000 iterations. 0.8s.
I just wrote these up:
function addClass(el, classNameToAdd){
el.className += ' ' + classNameToAdd;
}
function removeClass(el, classNameToRemove){
var elClass = ' ' + el.className + ' ';
while(elClass.indexOf(' ' + classNameToRemove + ' ') !== -1){
elClass = elClass.replace(' ' + classNameToRemove + ' ', '');
}
el.className = elClass;
}
I think they'll work in all browsers.
The simplest is element.classList which has remove(name), add(name), toggle(name), and contains(name) methods and is now supported by all major browsers.
For older browsers you change element.className. Here are two helper:
function addClass(element, className){
element.className += ' ' + className;
}
function removeClass(element, className) {
element.className = element.className.replace(
new RegExp('( |^)' + className + '( |$)', 'g'), ' ').trim();
}
One way to play around with classes without frameworks/libraries would be using the property Element.className, which "gets and sets the value of the class attribute of the specified element." (from the MDN documentation).
As #matías-fidemraizer already mentioned in his answer, once you get the string of classes for your element you can use any methods associated with strings to modify it.
Here's an example:
Assuming you have a div with the ID "myDiv" and that you want to add to it the class "main__section" when the user clicks on it,
window.onload = init;
function init() {
document.getElementById("myDiv").onclick = addMyClass;
}
function addMyClass() {
var classString = this.className; // returns the string of all the classes for myDiv
var newClass = classString.concat(" main__section"); // Adds the class "main__section" to the string (notice the leading space)
this.className = newClass; // sets className to the new string
}
Read this Mozilla Developer Network article:
https://developer.mozilla.org/en/DOM/element.className
Since element.className property is of type string, you can use regular String object functions found in any JavaScript implementation:
If you want to add a class, first use String.indexOf in order to check if class is present in className. If it's not present, just concatenate a blank character and the new class name to this property. If it's present, do nothing.
If you want to remove a class, just use String.replace, replacing "[className]" with an empty string. Finally use String.trim to remove blank characters at the start and end of element.className.
Fixed the solution from #Paulpro
Do not use "class", as it is a reserved word
removeClass function
was broken, as it bugged out after repeated use.
`
function addClass(el, newClassName){
el.className += ' ' + newClassName;
}
function removeClass(el, removeClassName){
var elClass = el.className;
while(elClass.indexOf(removeClassName) != -1) {
elClass = elClass.replace(removeClassName, '');
elClass = elClass.trim();
}
el.className = elClass;
}
The solution is to
Shim .classList:
Either use the DOM-shim or use Eli Grey's shim below
Disclaimer: I believe the support is FF3.6+, Opera10+, FF5, Chrome, IE8+
/*
* classList.js: Cross-browser full element.classList implementation.
* 2011-06-15
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! #source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
(function (view) {
"use strict";
var
classListProp = "classList"
, protoProp = "prototype"
, elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
, objCtr = Object
, strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
}
, arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0
, len = this.length
;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
, DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
}
, checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR"
, "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR"
, "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
}
, ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.className)
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
, i = 0
, len = classes.length
;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.className = this.toString();
};
}
, classListProto = ClassList[protoProp] = []
, classListGetter = function () {
return new ClassList(this);
}
;
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function (token) {
token += "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
this._updateClassName();
}
};
classListProto.remove = function (token) {
token += "";
var index = checkTokenAndGetIndex(this, token);
if (index !== -1) {
this.splice(index, 1);
this._updateClassName();
}
};
classListProto.toggle = function (token) {
token += "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.add(token);
} else {
this.remove(token);
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter
, enumerable: true
, configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
}
Improved version of emil's code (with trim())
function hasClass(ele,cls) {
return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className = ele.className.trim() + " " + cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className = ele.className.replace(reg,' ');
ele.className = ele.className.trim();
}
}
function addClass(element, classString) {
element.className = element
.className
.split(' ')
.filter(function (name) { return name !== classString; })
.concat(classString)
.join(' ');
}
function removeClass(element, classString) {
element.className = element
.className
.split(' ')
.filter(function (name) { return name !== classString; })
.join(' ');
}
Just in case if anyone would like to have prototype functions built for elements, this is what I use when I need to manipulate classes of different objects:
Element.prototype.addClass = function (classToAdd) {
var classes = this.className.split(' ')
if (classes.indexOf(classToAdd) === -1) classes.push(classToAdd)
this.className = classes.join(' ')
}
Element.prototype.removeClass = function (classToRemove) {
var classes = this.className.split(' ')
var idx =classes.indexOf(classToRemove)
if (idx !== -1) classes.splice(idx,1)
this.className = classes.join(' ')
}
Use them like:
document.body.addClass('whatever') or document.body.removeClass('whatever')
Instead of body you can also use any other element (div, span, you name it)
add css classes: cssClassesStr += cssClassName;
remove css classes: cssClassStr = cssClassStr.replace(cssClassName,"");
add attribute 'Classes': object.setAttribute("class", ""); //pure addition of this attribute
remove attribute: object.removeAttribute("class");
A easy to understand way:
// Add class
DOMElement.className += " one";
// Example:
// var el = document.body;
// el.className += " two"
// Remove class
function removeDOMClass(element, className) {
var oldClasses = element.className,
oldClassesArray = oldClasses.split(" "),
newClassesArray = [],
newClasses;
// Sort
var currentClassChecked,
i;
for ( i = 0; i < oldClassesArray.length; i++ ) {
// Specified class will not be added in the new array
currentClassChecked = oldClassesArray[i];
if( currentClassChecked !== className ) {
newClassesArray.push(currentClassChecked);
}
}
// Order
newClasses = newClassesArray.join(" ");
// Apply
element.className = newClasses;
return element;
}
// Example:
// var el = document.body;
// removeDOMClass(el, "two")
https://gist.github.com/sorcamarian/ff8db48c4dbf4f5000982072611955a2

Categories