Reputation: 2504
I'm trying to get familiar with polymer, and have been working my way through trying to build a sample application with it. Following the tutorials at https://www.dartlang.org/docs/tutorials/polymer-intro and reading other StackOverflow questions such as How do I fire a custom event from Polymer Dart? I have managed to build two elements where one element fires an event that is acted upon by the second element. I have, however, only been able to figure out how to do this for cases where the firing element is a child of the listening element. For example, as follows
foo.html
<link rel="import" href="bar.html">
<polymer-element name="foo">
<template>
<my-bar on-myevent="{{react}}"></mybar>
</template>
<script type="application/dart" src="foo.dart"></script>
</polymer-element>
foo.dart
@CustomTag('my-foo')
class Foo extends PolymerElement {
Foo() {}
Foo.created() : super.created();
void react() {
print("Event happened and was heard!");
}
}
bar.html
<polymer-element name="bar">
<template>
<button on-click="{{click}}"></button>
</template>
<script type="application/dart" src="bar.dart"></script>
</polymer-element>
bar.dart
@CustomTag('my-bar')
class Bar extends PolymerElement {
Bar() {}
Bar.created() : super.created();
void click(Event e, var details, Node node) {
print("Triggering event");
fire('my-event');
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<script type="application/dart" src="main.dart"></script>
<script src="packages/browser/dart.js"></script>
<link rel="import" href="foo.html">
</head>
<body>
<div id="content">
<foo></foo>
</div>
</body>
</html>
What I'd like to do is be able to move the bar
button outside of the foo
element, as in the app that I want to design, I would like the input controls to exist is a separate area of the page from the primary output display (the foo
element). Basically, I'd like to be able to make foo.html
and index.html
look like this:
foo.html
<polymer-element name="foo">
<template>
<!-- Databound output stuff here -->
</template>
<script type="application/dart" src="foo.dart"></script>
</polymer-element>
index.html
<!DOCTYPE html>
<html>
<head>
<script type="application/dart" src="main.dart"></script>
<script src="packages/browser/dart.js"></script>
<link rel="import" href="foo.html">
<link rel="import" href="bar.html">
</head>
<body>
<div id='control-panel'>
<bar></bar>
</div>
<div id="content">
<foo></foo>
</div>
</body>
</html>
I can't seem to find any examples on how, if I move the bar
button out of the foo
element, to get the event from bar
to be visible to foo
. What would be the best way to listen to the event from bar
when it is not a child of foo
?
Upvotes: 3
Views: 965
Reputation: 11027
Polymer is designed around the idea of controllers
. By this I mean, when A and B need to have some interaction, the preferred architecture is to create a third entity C. C can manage the lifecycle of A and B, and orchestrate communication. This kind of structure is excellent for maintainability, because users of C are insulated from the particulars of A and B, and A and B are insulated from everything. It also provides a convenient spot for impedance matching between A and B.
<polymer-element name="my-c">
<template>
<my-a on-my-event="{{coolAction}}"></my-a>
...
<my-b id="b"></my-b>
</template>
<script>
Polymer({
coolAction: function() {
this.$.b.doCoolThing();
}
});
</script>
</polymer-element>
Users new to component structures often perceive this set-up as inconvenient, but my experience is that it's extraordinarily helpful once you get used to it.
Ultimately your view is a graph of components, where any particular sub-graph can generally be snipped off, replaced, or reattached with a minimum of stress. This is great for building flexible applications.
The signals
concept exists for the rare occasion where you really want A and B to talk to each other directly, cutting across the component graph. This ability is almost never needed with a good application design, and should be avoided if possible.
Upvotes: 6
Reputation: 11201
Since events bubble, the easiest way to handle this is to listen to a common ancestor of both elements.
Let's say you have this structure:
<div id="event-bus">
<my-a></my-a>
<my-b></my-b>
</div>
Then <my-b>
can listen for my-event on #event-bus
.
To help ` find the event bus, you could set an attribute:
<div id="event-bus">
<my-a></my-a>
<my-b event-bus="event-bus"></my-b>
</div>
class MyB extends PolymerElement {
@published String eventBus;
ready() {
querySelector('#$eventBus').on['my-event'].listen((e){ react(); } );
}
...
}
Upvotes: 4
Reputation: 297
The <polymer-signals>
element has been ported to Dart, which lets you fire a custom event anywhere, and listen to it anywhere.
Use it like <polymer-signals on-polymer-signalfoo="{{foo}}"></polymer-signals>
where the event type you fire is polymer-signal
and the data of the fire contains {'name': 'foo', 'data': <your-data>}
The port is here polymer_elements for dart.
A good explanation of events in general for the javascript polymer which also describes how the <polymer-signals>
works is described communication and message passing.
Upvotes: 2