72

When I run event.path[n].id in Firefox, I get this error. It works in other browsers.

event.path undefined

AlexMA
  • 9,422
  • 7
  • 40
  • 58
Hanson
  • 753
  • 1
  • 5
  • 5
  • More generally for the Firefox web console and "undefined": *[Chrome/Firefox console.log always appends a line saying 'undefined'](https://stackoverflow.com/questions/14633968)* – Peter Mortensen Oct 20 '20 at 18:17

5 Answers5

135

The path property of Event objects is non-standard. The standard equivalent is composedPath, which is a method. But it's new.

So you may want to try falling back to that, e.g.:

var path = event.path || (event.composedPath && event.composedPath());
if (path) {
    // You got some path information
} else {
    // This browser doesn't supply path information
}

Obviously that won't give you path information if the browser doesn't supply it, but it allows for both the old way and the new, standard way, and so will do its best cross-browser.

Example:

document.getElementById("target").addEventListener("click", function(e) {
  // Just for demonstration purposes
  if (e.path) {
    if (e.composedPath) {
      console.log("Supports `path` and `composedPath`");
    } else {
      console.log("Supports `path` but not `composedPath`");
    }
  } else if (e.composedPath) {
    console.log("Supports `composedPath` (but not `path`)");
  } else {
    console.log("Supports neither `path` nor `composedPath`");
  }
  
  // Per the above, get the path if we can
  var path = e.path || (e.composedPath && e.composedPath());
  
  // Show it if we got it
  if (path) {
    console.log("Path (" + path.length + ")");
    Array.prototype.forEach.call(
      path,
      function(entry) {
        console.log(entry.nodeName);
      }
    );
  }
}, false);
<div id="target">Click me</div>

In my tests (updated May 2018), neither IE11 nor Legacy Edge (v44 or earlier, before the Chromium update that starts with v79) supports either path or composedPath. Firefox supports composedPath. Chrome supports both path (it was Google's original idea) and composedPath. According to MDN recent versions of all major browsers apart from IE11 support composedPath as of January 2020.

So I don't think you can get the path information directly on IE11 (or Legacy Edge). You can, obviously, get the path via e.target.parentNode and each subsequent parentNode, which is usually the same, but of course the point of path/composedPath is that it's not always the same (if something modifies the DOM after the event was triggered but before your handler got called).

T.J. Crowder
  • 959,406
  • 173
  • 1,780
  • 1,769
  • Hey! Thank you for your answer, but event.ComposedPath returned undefined in Chrome and Firefox – Hanson Aug 31 '16 at 11:14
  • @Hanson: Right, again, it's the *new* standard for this. Chrome supports the old way (`path`). See the updated answer, I don't think this info is available on Firefox (or IE, didn't test Edge). – T.J. Crowder Aug 31 '16 at 11:40
  • Yeah, FireFox definitely does not support this. :\ – Martyn Chamberlin Jan 21 '17 at 01:00
  • chiming in from 2018 - still no support in FF – Stephen Tetreault Apr 13 '18 at 18:51
  • @SMT: Indeed not, and surprisingly, I can't find a bugzilla entry for it. Just [this one](https://bugzilla.mozilla.org/show_bug.cgi?id=1444857) from a month ago syncing up tests, and if you follow it to the [upstream bug](), Anne van Kesteren notes: "I suspect the reason this breaks the build is because Firefox doesn't implement these features." So who knows, maybe that will raise the profile. – T.J. Crowder Apr 14 '18 at 07:27
  • 1
    It seems FF has support for `composedPath()` now (tested with version 59.0.3). – Peter Herdenborg May 14 '18 at 11:14
  • 1
    @PeterHerdenborg - Indeed! I've updated. Chrome does too now (it used to support only `path`). Also tested Edge, was sorry to see neither is supported. – T.J. Crowder May 14 '18 at 11:23
  • The property 'composedPath' seems to be changed into 'composed', I guess to avoid a conflict between the property and the method. (Mac FF and Safari) – Esger Dec 03 '18 at 09:57
  • 2
    @Esger - No, `composed` is [something else entirely](https://developer.mozilla.org/en-US/docs/Web/API/Event/composed), unrelated to `path` or `composedPath()`. – T.J. Crowder Dec 03 '18 at 10:50
  • Is there any cost associated with accessing the eventPath in terms of performance? I am aware that DOM operations are expensive. Would this fall under those? – Nahush Farkande Feb 25 '22 at 03:13
  • @NahushFarkande - DOM *mutations* can be expensive. This is just accessing DOM information, which may not be quite as cheap as accessing a JavaScript object property, but it'll be close. As always, worry about performance issues when you have a performance issue to worry about. :-) – T.J. Crowder Feb 25 '22 at 08:15
26

You can create your own composedPath function if it's not implemented in the browser:

function composedPath (el) {

    var path = [];

    while (el) {

        path.push(el);

        if (el.tagName === 'HTML') {

            path.push(document);
            path.push(window);

            return path;
       }

       el = el.parentElement;
    }
}

The returned value is equivalent to event.path of Google Chrome.

Example:

document.getElementById('target').addEventListener('click', function(event) {

    var path = event.path || (event.composedPath && event.composedPath()) || composedPath(event.target);
});
Guillaume Jasmin
  • 1,030
  • 8
  • 6
  • 5
    That's is not actually the same, sometimes the parentElement is returning null is some cases and the event.path/composePath() will give you the full path.. – Islam Attrash Dec 26 '17 at 14:51
  • 2
    This is **not** an implementation of `path`/`composedPath`. It misses the key aspect of them (which you can't polyfill). – T.J. Crowder May 14 '18 at 11:24
  • The accepted answer misses this function to work on edge, since composed path is not supported either. Really nice. – Cédric MEYER Jan 16 '19 at 08:26
  • this does not work in open shadow roots. I was looking for a Edge polyfill that would give me the source dom node within the web component, not the document. – Vlad Nicula Jun 27 '19 at 09:45
12

This function serves as a polyfill for Event.composedPath() or Event.Path

function eventPath(evt) {
    var path = (evt.composedPath && evt.composedPath()) || evt.path,
        target = evt.target;

    if (path != null) {
        // Safari doesn't include Window, but it should.
        return (path.indexOf(window) < 0) ? path.concat(window) : path;
    }

    if (target === window) {
        return [window];
    }

    function getParents(node, memo) {
        memo = memo || [];
        var parentNode = node.parentNode;

        if (!parentNode) {
            return memo;
        }
        else {
            return getParents(parentNode, memo.concat(parentNode));
        }
    }

    return [target].concat(getParents(target), window);
}
Guido Bouman
  • 2,857
  • 4
  • 21
  • 32
Mr.7
  • 2,065
  • 1
  • 21
  • 30
3

Use composePath() and use a polyfill for IE: https://gist.github.com/rockinghelvetica/00b9f7b5c97a16d3de75ba99192ff05c

include above file or paste code:

// Event.composedPath
(function(e, d, w) {
  if(!e.composedPath) {
    e.composedPath = function() {
      if (this.path) {
        return this.path;
      } 
    var target = this.target;

    this.path = [];
    while (target.parentNode !== null) {
      this.path.push(target);
      target = target.parentNode;
    }
    this.path.push(d, w);
    return this.path;
    }
  }
})(Event.prototype, document, window);

and then use:

var path = event.path || (event.composedPath && event.composedPath());
Komal
  • 966
  • 9
  • 20
1

I had the same issue. I need the name of the HTML element. In Chrome I get the name with path. In Firefox I tried with composedPath, but it returns a different value.

For solving my problem, I used e.target.nodeName. With target function you can retrieve the HTML element in Chrome, Firefox and Safari.

This is my function in Vue.js:

selectFile(e) {
        this.nodeNameClicked = e.target.nodeName
        if (this.nodeNameClicked === 'FORM' || this.nodeNameClicked === 'INPUT' || this.nodeNameClicked === 'SPAN') {
          this.$refs.singlefile.click()
      }
    }
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124