Skip to content
This repository has been archived by the owner on Sep 21, 2022. It is now read-only.

How to add events to buttons #18

Open
optikalefx opened this issue Oct 22, 2014 · 12 comments
Open

How to add events to buttons #18

optikalefx opened this issue Oct 22, 2014 · 12 comments

Comments

@optikalefx
Copy link

I've added buttons to my table via the rowTemplate. But how am I able to attach events to those? Right now the only thing that comes to mind is to attach an event to the entire element and look for e.target to test if it's that button. Kind of lame.

Thanks

@optikalefx
Copy link
Author

Actually that doesn't even work. So not sure what to do here.

@optikalefx
Copy link
Author

So for now, in the rowSelect method I've added this

if(e.target.templateInstance) {
    this.fire('rowClick', {
        data: e.target.templateInstance.model.record.row,
        target: e.target
    });
}

To use it

$('.bootstrap').on('rowClick', function(e) {
    console.log(e.originalEvent.detail);
});

If you want this to be a PR, let me know.

@stevenrskelton
Copy link
Owner

Events definitely need a little work; none have been defined yet but they are necessary so I'm working on adding them.

Another person had this same issue (sortable-table#12) where I've explained the standard web components approach.

@optikalefx
Copy link
Author

I think my approach is way simpler then the one mentioned in #12. Right now I ruin the ability to run bower update because of the code change. But the code needed is only like 4 lines. I Made a btnClick event.

if(e.target.templateInstance && e.target.nodeName === "BUTTON") {
    this.fire('btnClick', {
        data: e.target.templateInstance.model.record.row,
        target: e.target
    });
}

Usage is just

$("sortable-table").on("btnClick", function(e) {
    e.originalEvent.detail.data; // row data
    e.originalEvent.detail.target; // actual button element
});

This code works on any button element inside any of my sortable tables. Works really well. I do agree that binding btnClick to the table is a bit contrived.

@stevenrskelton
Copy link
Owner

Thanks for your input. :)

I was pointing out for tough cases you can fall back on that approach; but I really don't think it should be necessary to wrap every button inside a web component just to capture the event.

I'll likely merge in something close to your first snippet, hard coding node names like in the last one won't work for people using polymer's core-button or paper-button

@optikalefx
Copy link
Author

Yea for sure. It just worked for my case. I can write a generic one that delegates a selector if you want. So you could bind (rowClick, "button") or ("rowClick",".somethingInMyTemplate")

@stevenrskelton
Copy link
Owner

I think I'm going to go this route:

Previously I added an args attribute parameter to sortable-table to pass in extra data needed by the template (meta-data which doesn't belong in the data array).

I'll do the same thing with an eventHandlers attribute. While binding on-* to function variables doesn't work, it is possible to turn those function variables into sortable-table properties....

<polymer-element name="test-element">
    <template>
        <button on-click="{{eventHandlers_stuff}}">Do Stuff</button>
    </template>
    <script>
    "use strict";
    Polymer({
        eventHandlers: {
            stuff: function(){
                console.log('stuff');
            }
        },
        ready: function(){
            var self = this;
            var names = Object.getOwnPropertyNames(self.eventHandlers);
            names.forEach(function(name){
                self['eventHandlers_' + name] = self.eventHandlers[name];
            });
        }
    });
    </script>
</polymer-element>

Notice <button on-click="{{eventHandlers.stuff}}"> doesn't work, but above syntax does and it's super close - so if they ever change polymer to support this it would be a very minimal change.

@optikalefx
Copy link
Author

Apologies for being new to polymer but can you show what the use case of
that is? Without firing the event I don't see a way to then bind to it to
define the click functionality.

Or are you making a new button element to be used which would fire its own
click event?
On Oct 22, 2014 11:13 PM, "Steven Skelton" [email protected] wrote:

I think I'm going to go this route:

Previously I added an args attribute parameter to sortable-table to pass
in extra data needed by the template (meta-data which doesn't belong in the
data array).

I'll do the same thing with an eventHandlers attribute. While binding on-*
to function variables doesn't work, it is possible to turn those function
variables into sortable-table properties....

Do Stuff <script> "use strict"; Polymer({ eventHandlers: { stuff: function(){ console.log('stuff'); } }, ready: function(){ var self = this; var names = Object.getOwnPropertyNames(self.eventHandlers); names.forEach(function(name){ self['eventHandlers_' + name] = self.eventHandlers[name]; }); } }); </script>

Notice doesn't work, but
above syntax does and it's super close - so if they ever change polymer to
support this it would be a very minimal change.


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

@stevenrskelton
Copy link
Owner

Instead of using

$('.bootstrap').on('rowClick', function(e) {
    console.log(e.originalEvent.detail);
});

You would define your event handlers via

<sortable-table eventHandlers="{{myEventHandlers}}"></sortable-table>

where

myEventHandlers = {  
           stuff: function(){
                console.log('stuff');
           }
}

You should be able to reference these handlers on any elements (like buttons) in your templates.

The actual scope and arguments that would be passed when executing myEventHandlers.stuff is a bit of a mystery, but I think i can coax them into something workable.

I might do both - not sure yet I'll have to play around with it for a while.

@optikalefx
Copy link
Author

So I really don't like the idea of passing an events object in. When I built OpenJSGrid I started out with property defined events and people felt really limited by that. It was much easier to bind to events on the grid, which would fire in context.

In your example there, where is myEventHandlers defined? Global scope? What about in a framework where I want my events with my other UI manipulation code?

Maybe if a <sortable-table-button name="myFireableButton"> existed and then you bound to $("sortable-table").on("click.myFireableButton"). Or some namespaced convention.

@optikalefx
Copy link
Author

The more I look into this, the more we need a combination approach. There is no way I can tell to expose the inner elements for delegation.

So you might be right that the only way to do this is to pass in a functions object. When I'm not on the clock I'll investigate more.

@optikalefx
Copy link
Author

I did one other thing that is a bit more useful. In this case, I had to apply events to the buttons without user interaction.

I added this function

modifyRows: function(modifier) {
            if(modifier) {
                var rows = this.shadowRoot.querySelectorAll("tbody tr");
                [].forEach.call(rows, function(row) {
                    modifier(row);
                });
            }
        },

Then fired this event at the end of your ready statement
this.fire("loaded");

So I'm able to just bind to loaded, and then do whatever I want with the row

$(".bootstrap").on("loaded", function() {
    this.modifyRows(function(row) {
            $(row).find(".copyUrl").each(function() {

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants