Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'target' field in 'event' argument passed into callback function for click/pointer events refers to first element instantiated #641

Closed
hesamrabeti opened this issue Jul 17, 2014 · 9 comments

Comments

@hesamrabeti
Copy link

If a custom element is made up of other elements, a mouse event on any of the children elements will initiate an event with the 'toElement' and 'target' fields pointing to the first parent element initiated in the root html file (before any imports).

For example, a 'pointerup' event on a 'paper-input' element inside a custom element named 'x-custom-editor' will pass in an 'event' object with the field 'target' set to the 'x-custom-editor' element instead of the 'paper-input' element.

<polymer-element name="x-custom-editor">
  <template>
   <paper-input></paper-input>
  </template>
</polymer-element>
document.addEventListener('pointerup', function(event) {
  console.log(event.target) // Prints parent DOM element
}

Contact me if you have any more questions.

@hesamrabeti
Copy link
Author

This seems to be the correct way to behave based on the fact that the child elements are in the shadow DOM tree of the parent element and for modularity's sake children elements are considered a part of the parent element.

However, this can create problems in certain situations.

The old way of intercepting click events on 'a' tagged elements with an 'href' field in single-page applications no longer works. If you have modularized your app in such a way where the root index.html instantiates an 'app' custom element, all clicks events will now return the 'app' element. This returned element gives no real information on what element was clicked. There are 2 options for fixing this issue.

  1. Traverse the shadow DOM and change all change-page-inducing tags to not cause a browser page change but to call a proprietary JavaScript function to change the current page.

  2. Each change-page-inducing element handles it's own on-click logic. This can get messy very very fast.

  3. Include a 'shadowTarget' field in the event passed to the callback function to indicate the specific element that was actually clicked/pointedto.

  4. Create a 'view-changer' element that calls a global/dependency-injected function to signal the need to change the current view/url

Option 1 - Not bad but not the best solution, will probably end up as a library included in every SPA app
Option 2 - Not the best way forward due to the fact that you have to create special logic
Option 3 - This is my favorite solution but can potentially break down some tenants of modularity
Option 4 - Maybe non-browser (search engine) compatibility issues?

@sjmiles
Copy link
Contributor

sjmiles commented Jul 18, 2014

Check event.path for the complete path to the target.

On Thu, Jul 17, 2014 at 6:07 AM, hesamrabeti notifications@github.com
wrote:

This seems to be the correct way to behave based on the fact that the
child elements are in the shadow DOM tree of the parent element and for
modularity's sake children elements are considered a part of the parent
element.

However, this can create problems in certain situations.

The old way of intercepting click events on 'a' tagged elements with an
'href' field in single-page applications no longer works. If you have
modularized your app in such a way where the root index.html instantiates
an 'app' custom element, all clicks events will now return the 'app'
element. This returned element gives no real information on what element
was clicked. There are 2 options for fixing this issue.

  1. Traverse the shadow DOM and change all change-page-inducing tags to not
    cause a browser page change but to call a proprietary JavaScript function
    to change the current page.

  2. Each change-page-inducing element handles it's own on-click logic. This
    can get messy very very fast.

  3. Include a 'shadowTarget' field in the event passed to the callback
    function to indicate the specific element that was actually
    clicked/pointedto.

  4. Create a 'view-changer' element that calls a global/dependency-injected
    function to signal the need to change the current view/url

Option 1 - Not bad but not the best solution, will probably end up as a
library included in every SPA app
Option 2 - Not the best way forward due to the fact that you have to
create special logic
Option 3 - This is my favorite solution but can potentially break down
some tenants of modularity
Option 4 - Maybe non-browser (search engine) compatibility issues?


Reply to this email directly or view it on GitHub
#641 (comment).

@hesamrabeti
Copy link
Author

In my case it's always a NodeList with length == 0.

path-nodelist 0

Is this typical behavior?

@hesamrabeti
Copy link
Author

'atomos-view' is the top-level instantiated element.

@hesamrabeti
Copy link
Author

Inspecting the console.log after-the-fact returns the zero-length array. An immediate print still does not give enough information. It stops at the first element instantiated instead of digging down to the deepest child. Here is the javascript code used to print:

    document.addEventListener('click', function(event) {
      console.log()
      console.log("EVENT: ", event)
      console.log("EVENT PATH: ", event.path)
      console.log("EVENT PATH.LENGTH: ", event.path.length)

      console.log("PRINTING PATH ARRAY: ");
      for(var i =0; i<event.path.length;i++) {
        console.log(event.path[i])
      }
    });

Here is a screenshot of the output:
page-array-print

@hesamrabeti
Copy link
Author

I tried the following bit of code:

<atomos-card on-click="{{nodeClick}}">
  nodeClick: function(event) {
    console.log(event.path)
  },

It works perfectly:

0: div
1: div
2: atomos-card.node-card
3: div
4: document-fragment
5: atomos-view-directory#viewDirectory.core-selected
6: core-pages#pages.pages
7: document-fragment
8: atomos-view-node-explorer#viewNodeExplorer.core-selected
9: core-pages#pages.pages
10: document-fragment
11: atomos-view-project-explorer#viewProjectExplorer.view.core-selected
12: core-pages#pages.pages
13: document-fragment
14: atomos-view-explorer#viewExplorer.view.core-selected
15: core-pages#pages.pages
16: core-header-panel
17: document-fragment
18: atomos-view#atomos-view
19: body
20: html
21: document

It seems like document.addEventListener(eventName, function(event){...}) acts differently than 'on-x' events on an element.

Events passed into document.addEventListener() callbacks point to the first element instantiated in your 'index.html' (or equivalent) while events associated with a particular event in HTML (on-tap, on-click, etc.) return the full path.

@sjmiles
Copy link
Contributor

sjmiles commented Jul 20, 2014

What browser and version are you using? event.path was not working
properly in Chrome 35, but was fixed in Chrome 36.

On Sun, Jul 20, 2014 at 12:04 PM, hesamrabeti notifications@github.com
wrote:

I tried the following bit of code:

nodeClick: function(event) {
console.log(event.path)
},

It works perfectly:

0: div
1: div
2: atomos-card.node-card
3: div
4: document-fragment
5: atomos-view-directory#viewDirectory.core-selected
6: core-pages#pages.pages
7: document-fragment
8: atomos-view-node-explorer#viewNodeExplorer.core-selected
9: core-pages#pages.pages
10: document-fragment
11: atomos-view-project-explorer#viewProjectExplorer.view.core-selected
12: core-pages#pages.pages
13: document-fragment
14: atomos-view-explorer#viewExplorer.view.core-selected
15: core-pages#pages.pages
16: core-header-panel
17: document-fragment
18: atomos-view#atomos-view
19: body
20: html
21: document

It seems like document.addEventListener('click', function(event){...})
acts differently than 'on-x' events on an element.


Reply to this email directly or view it on GitHub
#641 (comment).

@hesamrabeti
Copy link
Author

Debian Version 35.0.1916.153. My evergreen seems to be a little less green than others.

@sorvell
Copy link
Contributor

sorvell commented Aug 12, 2014

Chrome 36 and the ShadowDOM polyfill both properly support event.path.

@sorvell sorvell closed this as completed Aug 12, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants