Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript get element unique selector

Tags:

javascript

I am moving elements using javascript and I need to create a logic for the combinations happening during the drag/drops

I'm trying to get details from the elements, a CSS like selector could be also good, but dunno if it is possible.. (like copy-selector in chrome dev tools)

document.onmouseup = function(e){
    targetDest = e.target;
    //console.log('targetDest: ', targetDest);

    let 
    indexA = Array.from(targetCurr.parentNode.children).indexOf(targetCurr),
    indexB = Array.from(targetDest.parentNode.children).indexOf(targetDest);

    console.log(indexA, indexB);


    if(targetDest != targetCurr){
        if(targetDest == document.documentElement){
            console.log('document');
        }
        else if(targetDest == undefined){
            console.log('undefined');
        }
        else if(!targetDest){
            console.log('!dest');
        }
        else if(targetDest == null){
            console.log('null');
        }
        else if(targetDest == false){
            console.log('false');
        }
        else{
            console.log('else');
            //targetCurr.parentNode.insertBefore(targetDest, targetCurr);

            //console.log('...');
        }
    }else{
        console.log('itself');
    }


}
like image 405
neoDev Avatar asked Nov 29 '22 09:11

neoDev


2 Answers

Keep in mind that this will not necessarily uniquely identify elements. But, you can construct that type of selector by traversing upwards from the node and prepending the element you're at. You could potentially do something like this

var generateQuerySelector = function(el) {
      if (el.tagName.toLowerCase() == "html")
          return "HTML";
      var str = el.tagName;
      str += (el.id != "") ? "#" + el.id : "";
      if (el.className) {
          var classes = el.className.split(/\s/);
          for (var i = 0; i < classes.length; i++) {
              str += "." + classes[i]
          }
      }
      return generateQuerySelector(el.parentNode) + " > " + str;
}

var qStr = generateQuerySelector(document.querySelector("div.moo"));
alert(qStr);
body
<div class="outer">
  div.outer
  <div class="inner" id="foo">
    div#foo.inner
    <div class="moo man">
      div.moo.man
    </div>
  </div>
</div>

I wouldn't suggest using this for much besides presenting the information to a user. Splitting it up and reusing parts are bound to cause problems.

like image 182
CollinD Avatar answered Dec 09 '22 19:12

CollinD


My solution using :nth-child:

function getSelector(elm)
{
if (elm.tagName === "BODY") return "BODY";
const names = [];
while (elm.parentElement && elm.tagName !== "BODY") {
    if (elm.id) {
        names.unshift("#" + elm.getAttribute("id")); // getAttribute, because `elm.id` could also return a child element with name "id"
        break; // Because ID should be unique, no more is needed. Remove the break, if you always want a full path.
    } else {
        let c = 1, e = elm;
        for (; e.previousElementSibling; e = e.previousElementSibling, c++) ;
        names.unshift(elm.tagName + ":nth-child(" + c + ")");
    }
    elm = elm.parentElement;
}
return names.join(">");
}

var qStr = getSelector(document.querySelector("div.moo"));
alert(qStr);
body
<div class="outer">
  div.outer
  <div class="inner" id="foo">
    div#foo.inner
    <div class="moo man">
      div.moo.man
    </div>
  </div>
</div>

Please note it won't return the whole path if there's an element with ID in it - every ID should be unique on the page, as valid HTML requires.

I use output of this function in document.querySelector later in the code, because I needed to return focus to the same element after replaceChild of its parent element.

I hope CollinD won't mind I borrowed his markup for the code snippet :-)

like image 22
mikiqex Avatar answered Dec 09 '22 18:12

mikiqex