polymer, shadow dom, events and bubbeling - polymer

I have a polymer custom element using shadow dom (v1), this element is inside another polymer custom element, also wrapped in shadow dom..
In my understanding, when the most inner element raises an event, the most outer element (the app) should be able to listen for these events.
Is this incorrect?
I have a rating component inside a review component inside an app component. the rating component throws an event:
this.dispatchEvent(new CustomEvent('custom-event'), { bubbles:true, composed:true });
However, the code below in the app-component never gets fired..
connectedCallback() {
super.connectedCallback();
this.addEventListener('custom-event', () => { console.log('a');});
}
Am I incorrect in assuming the event should bubble all the way up the different shadow doms to the window eventually, unless someone stops the propagation?
Thanx for any answers..
John.

Found it, I set the options as argument to the dispatchEvent instead of adding the options to the CustomEvent.
so instead of
this.dispatchEvent(new CustomEvent("event"), { options });
you have to do
this.dispatchEvent(new CustomEvent("event", { options }));

Related

Polymer - Fire not updating the UI checkboxes

I have very simple setup. When I check on checkbox, a pop up will open and ask to link to another checkbox.
When I close the popup, whatever the checkbox I selected, both will be checked.
I have array updated with checkbox value.
After I close the popup, the values are showing right in the array but not in UI. When I select other tab and get back to this tab, checkboxes are showing right.
this.fire('details', this.details);
This is not working from child page.
How can I refresh the parent element?
Above your details event, will fire an event with on-<your-custom-event> at parent element as on-details So you need to assign a listener something like at parent:
<child-element
on-details = '_detailsChanged'>
</child-element>
...
Polymer {(
_detailsChanged: function(e) {
// e.detail will give you this.details object
}
Or I assume you want to assign an object at the child and reflect observations on the parent, so at parent element :
<child-element
details = "{{details}}"
><child-element>
and at the child element, you need to notify=true this object at property declarations and notifyPath with making observable changes at parent something like:
properties: {
details: {
type:Object,
notify:true
}
}
..
this.set('details', nevDetailsValue); //Use this.set method
this.notifyPath('details'); // Than detail property will change value at parent.
EDIT : Need to specify the exact path !!
DEMO
this.notifyPath('details.<path which is changed>'); // ie:this.notifyPath('details.name')

How to trigger mouse-click event on multiple HTML elements covering each other?

How to trigger multiple mouse-click events on arbitrarily many HTML elements covering each other?
I know you can use pointer-events: none; to let your click pass through your elements, but what if I want to trigger the mouse-click event on an element AND the mouse-click event on arbitrarily many other elements beneath it?
but what if I want to trigger the mouse-click event on an element AND the mouse-click event on arbitrarily many other elements beneath it?
Events bubble. Which means and event fired on an inner element, will also be received by the parent elements until the top most parent.
<div id="topmost">
<div id="second">
<p id="firstp"></p>
</div>
</div>
Assume you are using jquery. Below is how you would listen to click events from all elements below div.id="topmost".
Since the normal flow of events is for any click event (could be any other type of event) that is fired by any element with in the topmost div element will be bubbled to the outermost element, I only list to topmost click event and then check which element fired that event by checking the id of the target element. e.target will be the actual element that the click was performed on. You can either switch target.attr('id') or run it through if else conditions.
$(function () {
$("#topmost").on("click", function (e) {
e.preventDefault();
var target = $(e.target);
if(target.attr('id') === "idOfElement"){
// code to handle the event
}else{
});
A solution could be to track mouse move using :
$( document ).mousemove();
Store coordinates to a global variable then check its position when your element is clicked. That would give something like :
var mousePos = [0,0];
$( document ).mousemove(function( event ) {
mousePos[0] = event.pageX
mousePos[1] = event.pageY
});
$("#target").click(function(){
// Compare mouse coordinates and your items ones using offset, height and width
if(mousePos[0] > $('#target2').offset.left){
// Do whatever you are willing to do
}
});

Add API to Polymer web component

I am building a Polymer web component that should respond to mouse/touch events. I would like to bind the on-tap="{{$.myElement.show}}" where show is a function in the element:
show: function(e) {
// Do something with the event here
}
Is there anyway to define a public API in Polymer. The route I am going at the moment is to have attributes="event" on the element then the parent element has on-tap="{{updateEvent}}":
updateEvent: function(e) {
this.$.myElement.event = e;
}
The element then just has:
eventChanged: function() {
show(this.event);
}
Which just seems boilerplaty (think that is a made up word). Can I add the show function to the element prototype somehow?
If show() is a method on your element, just use on-tap="{{show}}". show() is part of the element's public APi.
But it looks like you want is to call another element's method? This came up recently in a pull request: https://github.com/Polymer/polymer-dev/pull/30
What you have with setting this.$.myElement.event = e; and using eventChanged() in myElement works. You can also just call the element's method directly:
updateEvent: function(e) {
this.$.myElement.show();
}
Here are a few other ways: http://jsbin.com/guyiritu/1/edit

Receiving FlexEvent.SHOW events in a ViewStack's grandchildren

The direct children of a ViewStack receive a FlexEvent.SHOW once the respective child view is shown. Unfortunately, the event information is lost at deeper child levels so that the grandchildren of the ViewStack do not receive the SHOW event.
Which approach would be advisable to tap into the SHOW events received by a ViewStack's direct children from a grandchild or grand-grand-child?
Using parent.parent.[...].addEventListener(FlexEvent.SHOW, [...]) would be possible, of course, but is kind of ugly as it will break as soon as the number of hierarchy levels between the two components changes.
Are there other events that are better suited?
The background of my question is that I would like to reload the grandchildren's content when it becomes visible again.
You could listen for the ADDED_TO_STAGE event in the grandchild view and find out if you're part of a view stack. If yes, then just listen to the view stack child's show/hide events.
... addedToStage="setMeUpForViewStack()" ...
Which is:
private var vsView:UIComponent = null;
private function setMeUpForViewStack():void
{
if (vsView) {
vsView.removeEventListener("show", vsViewShowHideHandler);
vsView.removeEventListener("hide", vsViewShowHideHandler);
vsView = null;
}
var obj:DisplayObject = this;
while (obj.parent != obj) {
if (obj.parent is ViewStack) {
vsView = obj;
break;
}
obj = obj.parent;
}
if (vsView) {
vsView.addEventListener("show", vsViewShowHideHandler, false, 0, true);
vsView.addEventListener("hide", vsViewShowHideHandler, false, 0, true);
}
}
And in your vsViewShowHideHandler you would reload the content (if the view is visible).
Basically this frees your from worrying about the level of nesting. It doesn't work with multiple nested view stacks though.
In the REMOVED_FROM_STAGE event handler you would forget vsView.
Although burying down into the viewstack would work I agree this is ugly and potentially can lead to headaches as soon as something changes.
A different approach could be to implement a global event dispatcher.
By having a static event dispatcher in a class, the grandchildren could subscribe to events from the static dispatcher from anwywhere within the application.
When the parent hears the FlexEvent.Show the handler could dispatch a custom event using the global dispatcher?

Flex popup window

I am creating modal popup canvas window in a parent page. When I close the popup how do we get notification in parent screen that child popup is just closed. Any event for that ?
The code to show your popup:
var popup:MyPopup = new popup:MyPopup();
popup.addEventListener(CloseEvent.CLOSE, function(evt) {
PopUpManager.removePopUp(popup);
});
PopUpManager.addPopUp(popup, this, true);
Inside your MyPopup class, you will have a button for closing the popup. Simply hook the click event to publish a "CLOSE" event:
<s:Button Label="X" click="dispatchEvent(new CloseEvent(CloseEvent.CLOSE));" />
I prefer this mechanism over having the MyPopup object calling PopUpManger.removePopUp (as #Fank is suggesting) because it couples the MyPopup component to the PopUpManager which I don't like. I'd prefer the user of MyPopup to decide how to use the component.
Honestly, though, these are two very similar mechanisms to perform the same end goal.
Yes there is:
I Preffer to use the Popupmanager:
Your Popup:
There is a Button "close" call a internal function eg.closeme
private function closeMe () :void
{
PopUpManager.removePopUp(this);
}
in your Parent, you open the PopUp like this:
private function openPopup () :void
{
var helpWindow:TitleWindow = TitleWindow(PopUpManager.createPopUp(this,MyTitleWindow,fale));
helpWindow.addEventListener(CloseEvent.CLOSE, onClose);
}
protected function onClose (event:CloseEvent) :void
{
PopUpManager.removePopUp (TitleWindow(event.currentTarget));
}
My TitleWindow is the name of your class of cour popup extended by TitleWindow.
BR
Frank
Along with Brian's answer don't forget to detach the event listener. If you leave the event handler in your main app listening for an event from a child object, the child object will not be garbage collected as something is still referencing it. This is a common memory leak issue.
popup.addEventListener(CloseEvent.CLOSE, popup_CloseHandler);
private function popup_CloseHandler(event:CloseEvent):void{
event.target.removeEventListener(CloseEvent.CLOSE, popup_CloseHandler);
PopUpManager.removePopUp(popup);
}
Here's a great post about Flex's memory management if you want to delve into that further.
http://blogagic.com/163/flex-memory-management-and-memory-leaks