# Templated Event Bindings

**URL:** <https://forums.bitovi.com/t/templated-event-bindings/87>\
**Category:** CanJS\
**Created:** [December 26, 2015, 7:32pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87 "2015-12-26T19:32:55Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 26, 2015, 7:32pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/1 "2015-12-26T19:32:55Z")

</div>

In “events” of a can.Component, is it possible to do the following:

`"{getSomething} click": function(el, ev) { ..... }`

Where “getSomething” is a property on the component’s viewModel, but it is a function that returns a string?

---

<div class="post-metadata">

**Author:** ![pYr0x](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/pyr0x/32/95_2.png) [@pYr0x](https://forums.bitovi.com/u/pYr0x)\
**Post date:** [December 28, 2015, 5:14pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/2 "2015-12-28T17:14:58Z")

</div>

I made pull requests for the components event documentation. Maybe it will help you  
[https://github.com/pYr0x/canjs/blob/component-doc/component/events.md](https://github.com/pYr0x/canjs/blob/component-doc/component/events.md)

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 28, 2015, 5:35pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/3 "2015-12-28T17:35:28Z")

</div>

I actually ended up answering my own question.

The way to do what I need is to use the define plugin.

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 28, 2015, 6:00pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/4 "2015-12-28T18:00:00Z")

</div>

Using the `events` object should almost always be avoided in modern CanJS. There’s almost no reason for it.

And yeah, the way to avoid it is the define plugin or functions combined with `call expressions`.

```
{{#each getPointsForPlayer(player.id)}}
```

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 28, 2015, 6:42pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/5 "2015-12-28T18:42:51Z")

</div>

Why is the “events” object so out of favor? How do you handle DOM manipulation? How about responding to events?

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 28, 2015, 8:15pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/6 "2015-12-28T20:15:14Z")

</div>

> How do you handle DOM manipulation?

With live-binding.

> Why is the “events” object so out of favor? How about responding to events?

It’s out of favor because you should be deriving the behavior of your application’s data (in nicely unit-testable view-models) and letting the view’s live-binding do its thing.

There are a few situations where events is needed, but I’d say 90% of the `events` object use I encounter is incorrect.

There are two types of events that people tend to be using “events” for:

- data events like `"{viewModel.stats} add"` and
- DOM events like `"li click"`

## DOM events

In general, DOM events should be replaced by `($click)="method()"` type view-bindings with the two possible exceptions:

- Event delegation performance is needed.
- The `document` or some other global element is needed to be listened to. (If this is your situation, I’d still take care that there’s not a better global state that might be more useful).

## Data Events

This is the most common situation the use of `events` was incorrect. With the define plugin, data-based-diffing, `call expressions`, and view-model-event-bindings there’s little reason to be listening on data events yourself.

- data based diffing - We will diff lists passed to `#each` in the view so even if entirely new lists are passed, we don’t replace all the elements.
- `call expressions` - Allow calling methods like: `{{#each getPointsForPlayer(player.id)}}`
- view-model-event-bindings - Allow you to listen to view model events in the view like `(added-items)="method()"`

Here’s an example, say I had a list of points by player like:

```js
var points = new can.List( [{playerId: 1, value: 2}, {player2: value: 3}, ...])

```

And I wanted to show a summary of each players points:

```auto
Player1: 2, 2, 3, 3
Player2: 3, 3, 2
Player3: 2, 1, 1
...

```

In the past, I might setup listeners on `"{points} add"` and `"{points} remove"` to add and remove point values from some `pointsSummary` list of lists:

```auto
"{viewModel.points} add": function(points, ev, points, index){
  points.forEach((point)=>{
    this.viewModel.attr("pointsSummary")
        .attr(point.attr("playerId")).push(point.attr("value") )
  })
}

```

Instead, with the define plugin, I can create points summary map and a `getPlayerPoints` method like:

```js
define: {
  pointsSummary: {
    get: function(){
      var playerSummary = {};
      this.attr("points").each((point) => {
        var playerId = point.attr("playerId"),
            players = playerMap[playerId]
        if(!players) {
          players = playerMap[playerId] = [];
        }
        players.push(point.attr("value"))
      });
      return playerSummary;
    }
  }
},
getPlayerPoints: function(playerId){
  return this.attr("pointsSummary").attr(playerId);
}

```

Now my template might look like:

```auto
{{#each playerIds}}
  Player{{.}}: 
  {{#each getPlayerPoints(.)}} {{.}} {{/each}}
{{/each}}

```

The benefits of all of this are:

- `.attr("pointsSummary")` and `getPlayerPoints` are easily unit testable.
- live-binding will automatically update the page if something is added to `points` and do it in an efficient way because of the data-based-diffing

## Conclusion

The big idea here is that you shouldn’t have to do data transforms via bindings in the `events` object or anywhere else. Model your application’s data and its derivations using the define plugin / prototype methods. Then let the view intelligently update the DOM.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 29, 2015, 3:35am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/7 "2015-12-29T03:35:18Z")

</div>

Thanks for the detailed response. How greatly things have changed since the days of JavascriptMVC!

Here’s something that bothers me:

```
can.Component.extend({
	tag:"bit-panel",
	template: panelStache,
	scope: BitPanelVM,
	events: {
		inserted: function(){
			this.element.parent().scope().addPanel( this.scope );
		},
		removed: function(){
			this.element.parent().scope().removePanel( this.scope );
		}
	}
});
```

The following line:  
**this.element.parent().scope().addPanel( this.scope );**

This is basically creating a tightly coupled relationship between a bit-panel component and a bit-tabs component. If a bit-panel exists and is not within a bit-tabs, this will error.

Is this type of relationship acceptable?

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 29, 2015, 4:26am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/8 "2015-12-29T04:26:33Z")

</div>

Yes, that’s fine. It’s an interface. As long as the parent provides an addPanel and removePanel method it could be anything.

It is possible to wire this up in the view like ($inserted)=“addParent(%viewModel)”, but I think that is overly complex.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 29, 2015, 4:29am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/9 "2015-12-29T04:29:11Z")

</div>

Ok. Makes sense.

So you’d be against the model where bit-tabs looks at the DOM within itself to discover bit-panel elements?

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 29, 2015, 4:44am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/10 "2015-12-29T04:44:36Z")

</div>

> So you’d be against the model where bit-tabs looks at the DOM within itself to discover bit-panel elements?

I’m not against that. It wouldn’t be easy to make work without MutationObservers. If you are in an environment that supports them, I think that’s a fine way of doing it.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 29, 2015, 5:24am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/11 "2015-12-29T05:24:45Z")

</div>

If you cannot dynamically add new components at runtime, do you need MutationObservers?

MutationObservers aside, this process of looking at the DOM within itself would happen in bit-tabs’s “inserted” event? Would that be the correct place?

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 29, 2015, 1:56pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/12 "2015-12-29T13:56:21Z")

</div>

Stache will dynamically insert bit-panels.

The only way of knowing about them in bit-tabs would be with mutation observer.

You can’t use inserted because it doesn’t bubble.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 29, 2015, 5:39pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/13 "2015-12-29T17:39:46Z")

</div>

I am guessing you are going to dislike this, but I want to get your thoughts anyway.

Given the following:

```
CanJS provides the MV*
  
  
    StealJS provides the infrastructure.
```

In the “inserted” of bit-tabs, couldn’t I do the following to grab all panels?  
this.element.find( “bit-panel” )

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 29, 2015, 6:22pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/14 "2015-12-29T18:22:43Z")

</div>

That wouldn’t work if panels are added or removed.

---

<div class="post-metadata">

**Author:** ![DylanRoss](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/dylanross/32/71_2.png) [@DylanRoss](https://forums.bitovi.com/u/DylanRoss)\
**Post date:** [December 29, 2015, 6:59pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/15 "2015-12-29T18:59:09Z")

</div>

It’s interesting you mention the coupling of bit-tabs and bit-panel. There always has to be some known interface for them to communicate, but one of the nice things about the bit-tabs example is that neither the child nor parent know the tag name of the other, so you could in theory use them with other components.

The only requirements are the interfaces of the child and parent, and the direct parent-child DOM structure. In this case, the parent needs the `addPanel` and `removePanel` methods, and the child must be an observable with property `active`.

Sometimes you may want your components to be farther away. We can remove the DOM structure requirement by doing `this.element.closest('bit-tabs')` but that results in tighter coupling because the tag name of the parent must be known.

You can avoid that by communicating the insertion of child components with a custom event that sets up all the tear down functions initially, but it’s a little bit tricky. Maybe there’s a better way to do this, but here’s what I came up with:

```auto
can.Component.extend({
  tag: 'bit-tabs',
  viewModel: {/*...*/},
  events: {
    'bit-panel-inserted': function(el, ev) {
      var vm = this.viewModel,
          panelVM = ev.viewModel;
      
      vm.addPanel(panelVM);
      
      // parent hands child teardown function
      ev.makeTeardown(function() {
        vm.removePanel(panelVM);
      });

      // allow nested tabs
      ev.stopPropagation();
    }
  }
});

can.Component.extend({
  tag: 'bit-panel',
  viewModel: {/*...*/},
  events: {
    inserted: function() {
      var ctrl = this;
      
      this.element.trigger({
        type: 'bit-panel-inserted',
        viewModel: this.viewModel,

        // parent will call this to hand the child the teardown function
        makeTeardown: function(teardown) {
          // save teardown function on the events control
          ctrl.teardown = teardown;
        }
      });
    },
    removed: function() {
      var ctrl = this;
      ctrl.teardown();
    }
  }
});

```

Furthermore, you can be more explicit with the interface by not even passing the child viewModel at all. Instead, pass only the functions that the parent will need (e.g., `makeActive` and `makeInactive`) which will restrict the parent to only changing as much state as the child allows.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 29, 2015, 7:11pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/16 "2015-12-29T19:11:18Z")

</div>

Yes, I agree. I said in an earlier comment that as long as sub components couldn’t be added or removed after initialization, then this approach “might” work.

The reason for this proposed approach is that I want the outer component (bit-tabs) to do some initialization before considering sub components (bit-panels).

Please note that I am not actually referring to bit-tabs and panels. Just using them as an example.

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 30, 2015, 12:03am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/17 "2015-12-30T00:03:36Z")

</div>

Dylan,  
Events are a good idea. I’ve not thought of that.

In the past, keep walking up the parentNode’s `can.viewModel()` until I find the function I’m looking for.

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 30, 2015, 12:43am UTC](https://forums.bitovi.com/t/templated-event-bindings/87/18 "2015-12-30T00:43:20Z")

</div>

I like this, but need think about it further…

---

<div class="post-metadata">

**Author:** ![thecountofzero](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/thecountofzero/32/79_2.png) [@thecountofzero](https://forums.bitovi.com/u/thecountofzero)\
**Post date:** [December 30, 2015, 5:38pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/19 "2015-12-30T17:38:11Z")

</div>

@justinbmeyer so which approach do you favor?

`this.element.parent().scope().addPanel( this.scope );`

or dylan’s suggestion of triggering an event in the inserted event of component to allow parent components to listen for?

---

<div class="post-metadata">

**Author:** ![justinbmeyer](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.bitovi.com/justinbmeyer/32/179_2.png) [@justinbmeyer](https://forums.bitovi.com/u/justinbmeyer)\
**Post date:** [December 30, 2015, 6:00pm UTC](https://forums.bitovi.com/t/templated-event-bindings/87/20 "2015-12-30T18:00:05Z")

</div>

@thecountofzero I’ve never tried dylans, so I’m unsure. I wouldn’t compare it to:

`this.element.parent().scope().addPanel( this.scope );`

instead, I’d compare it to walking up the parent viewModels until you find one with an `addPanel` method. Lets say the comparison is between “walking” and “eventing”

Comparing them I see the following positives and negatives.

### Eventing

Eventing is nice because you simply trigger the event and let jQuery’s event system do your walking for you. The only downside is that parents need to listen to this event, and then call their `.addPanel` method. Now there’s an `events` object in both places.

### Walking

The walking code would be annoying to write.

### Conclusion

In the end, I’d probably go the “eventing” approach. Less code is typically better. I’d just make sure there’s as little code in the events object as possible, so most code is in the unit-testable viewModels.

[Next page](https://forums.bitovi.com/t/templated-event-bindings/87.md?page=2)
