How to bind object throw multi child elements - polymer

TLDR: How to define and upward pass a common property throw 3 registered elements?
Assume that you have a parent interface element and call it dashboard, now <dashboard> has a child element called <tree-node> which includes another child element inside it called <tree-node-element> which prompts the user to push some data into an array called chapters.
How to pass chapters object from <tree-node-element> upwards to <dashboard>, should I define chapters property in each element, what flags should I give that property in each definition.
Polymer V1x

Use event bubbling, so fire() the event node-element-foo-changed and listen for it in the dashboard element.
This is probably late stage, but you can also for example use Redux or data mixins for state management in your application.

Define the chapters property on the top node, dashboard. Propagate it down through the tree via polymer data binding. Have the child node (tree-node-element) emit an event to change the value. Have the dashboard element listen for the event and update the value with this.set(). The value will then automatically propagate down to all the child nodes in the tree. That way you only need to implement the logic to update the data in one place.

Related

Polymer two-way data binding and Facebook callback

I am very new to JavaScript and Polymer. I do like the PWA concept but now hit some roadblocks.
I tried to use polymerfire <firebase-auth> and was able to do google provider logins. But got blocked as I don't know how to do Facebook provider login and didn't find anywhere on how to use the tag as I wish to provide Facebook login too in JavaScript. If someone guides me to a source that works I will then not need part 2 of the question.
So, I tried facebook login via Graph API FB.login(). FB.login() has callback and I was not able to extract the response.name, public_profile and set it to Polymer attribute say {{user}} like
var userName = response.name; and then this.user = {displayName : userName};
I noticed that as soon as I exit FB.login() callback on successful login, I lose the changes done in assignment in callback to 'this.user ' object.
My question is - I am not able to make two way binding work in polymer. How can I change the object in child element and then it propagates to all the pages / polymer elements?
How can I change the object in child element and then it propagates to all the pages / polymer elements?
Well really that depends on how you set up all the pages. If you're in the parent, you can pass functions, variables, and objects to the child element by passing it in the component.
<ChildElement details={{_details}}/> // If you want to pass a details object to the child
<ChildElement sqft={{square(size)}}/> // This will call the square function inside your ChildElement and pass in the parameter size
Use the latter to call a function in your child and that function will have access to all the elements within that scope.
If you're in the child and you want to change something in the parent, you can do a callback with this.fire(someFunction()), and then create a function in your parent that with the same name. It's not too bad when you're just passing from parent to child or vice versa but if you're passing it everywhere, then you might want to look into some sort of state management. Passing things from one place to everywhere else will get ugly real fast.

Is there a way to have two custom elements sharing a DOM element, e.g. an <iron-ajax>

I have two custom elements having similar functionality and both having an <iron-ajax> element(in local DOM template) to make service calls, I was trying to extract these common part into a behavior. But I also realize that polymer behavior does not carry local DOM template. Is there a way to let the behavior have the <iron-ajax>? dynamically create it using Document.create?
As "behavior" is the Polymer way of doing code sharing, can a DOM element be shared across elements?
You should create an other element for your API calls which have inside the <iron-ajax> and have your api call methods, then you need just change the iron-ajax element in your elements and use your <api-element> for this.
Below are two methods which i can think of
Create iron-ajax element at root level of your application and then refer to that element from each of your element using querySelector or getElementById on document
In your behavior create iron-ajax element from javascript with createElement function of javascript.
In both the cases you can add event listener on response and error.

Getting a list of the rendered items

I have my own custom component. This component extends from a basic container. I want to be able to access the itemRenderer instances that are being visualized. I know that the component mx:list has an internal getter that provides an array of Arrays containing the itemRenderer instances that render each data provider item. I want the same thing. Any idea how of how to do that?
To be more specific: I am setting the selected property of my dataProvider items to true or false. From the updateDisplayList funcion of my ItemRenderer I check for changes of the property and correct the border color of the selected ones. Unfortunately I have to force the updateDisplayList function. I already did this once on a ItemRenderer from a list. Only with the list it was practical because by making my own list I was able to get the list of items being rendered and therefore visualized (cannot be many). It was no overhead to go trough the rendered Items and updateDisplayList. But in this case I can have 100 items. Imagine checking and changing styles on so many items. Thanks
The Flex architects intentionally made this difficult to do, because they are properly encapsulating the component. In short, to even try to do this is a violation of good OOP principles.
That said, about 90% of the things you are probably trying to do can be done by manipulating the data item, and the remaining 10% can be done by using a ClassFactory for your itemRenderer that sets a custom property on your itemRenderer to a callback where you can look at the data available to the containing context and provide back a value based on that.
If you elaborate a bit more on your end goal, I can give you more specifics.
Edit in light of clarification:
You need to make your data object class dispatch an event when it changes (one way is to make it bindable, or just make the selected property bindable). Then, in your renderer, listen for the change event and take the appropriate action.
A second way to handle this would just be to refresh() the collection, storing the selectedItem first (if you care about that) and resetting it once the refresh has finished.
I believe you can access the itemRenderer instances through getChildAt method. Flex 3's container overrides "getChildAt", "numChildren", given that some children are logical children, while some are decorative children such as background, border and scrollbars.
Keep in mind that itemRenderer may not right away become available upon dataProvider assignment, as they may be created during the next component lifecycle. Check with the underlying container's documentation and find out which event to be listened when the renderers are surely created, so you can reliably access them.

Event once all the custom item renderers have been created/set

I'm using a custom item renderer in my datagrid, and need to make a button visible or invisible based on if there has been a negative value on any of the values in the renderer. So I'd like to set a flag to false when the first renderer is set off, turn it to true if there's any negative values, and at the end check for the value of the flag. I know I can dispatch a dataChange event for every time the data is changed in the renderer instances, but I was wondering if there is anyway I can know when all of them are done?
Thanks!
There is no such event.
Like any other Flex component, a renderer will dispatch a CREATION_COMPLETE after it's been created. ItemRenderers are generally recycled (the same object gets assigned new data to render), thus listening for CREATION_COMPLETE is not sufficient, unless you disable the recycling.
For a Spark List component, you can disable recycling by setting useVirtualLayout=false on the layout class. I'm not sure if the Spark DataGrid class support this or not. The MX DataGrid may have some other way to do this.
Disabling the recycling, however, can have performance implications. I think your idea w/the DATA_CHANGE event is the best solution:
determine the initial state of the data (ie: are there any negative values)
in the renderer, use the DATA_CHANGE event (or just override the setter for the renderer's data property) to know when the data has changed
When the data changes, dispatch a custom event class that will bubble. This event has a property that tells you if the value is negative or not.
Since your custom event from the renderers will bubble up to the grid, you can add one listener on the grid to handle changes from all the renderers.
You should have a look into RendererExistenceEvents. You should be able to tell when they are all created based on how many items you have in your list or at least how many should be in view at once.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/events/RendererExistenceEvent.html

dispatching from an object not in the display list?

I have an object that controls another object that is on the display list.
The setup looks like this:
Parent (Main Timeline)
- Child
-- Grandchild --> contains instance of behaviour class that controls the grandchild's movement
I have an event in the "behaviour" that I'd like to reach the parent, but the behavior does not extend Sprite or MovieClip.
How can I get this event to reach the parent?
There are two ways. If the "behavior" object has access to the GrandChild, the GrandChild has a root property (which, conveniently) is the root -- this will only work if there is a path-to-root though. You can't remove a child (or its parents) and then expect to be able to access the root directly. But, if you have a DisplayObject which you know is on the stage, you can use that to communicate to the root directly. (You can also, with proper casting, access all of the parents and grandparents of the Grandchild).
You can also have a centralized EventDispatcher which is listened to by whatever you want to listen to it. Basically, create a Singleton (you'll need to look that up for the AS3 way) which subclasses EventDispatcher and then tell that to dispatch whatever events you need.
It would look something like this:
//on the root
EventDispatcher.getInstance().addEventListener( "myCustomEvent", myEventhandler );
//in behavior
EventDispatcher.getInstance().dispatchEvent( new Event( "myCustomEvent" ) );
//root now acts accordingly.
The "BubblingEventDispatcher" class you are referring to is a bit misleading. It's actually just adding children to the display list in order to enable bubbling:
AS3 Event Bubbling outside of the Scenegraph/DisplayList
In order to relay events without having access to bubbling, you are basically stuck listening for the events on every level and relaying them along manually. It accomplishes the same thing as if you had bubbled the event but it's more of a hassle and it also introduces tighter coupling.