How to access parent model from polymer component - dart

I have my-app as main application component in index.html file and uses model.dart as its model which is my application model.
my-app has my-component as its content. When user interacts with my-component, I need to update values in model.dart.
<my-app>
<my-component></my-component>
</my-app>
one approach I thought is to access my-app in my-component dart file and use its model property to access model.dart.
Is this the right approach to access model of the application? Also how to get my-app from within my-component?

I would submit that having the child component have awareness of its parent is not a particularly good pattern.
But you are right, often what happens in the child component changes a value in the parent, or in a model bound to the parent. For cases like these, I have found that the child can dispatch an event, and the parent can choose to interact with that event as it sees fit.
Dispatching an event is as simple as doing the following (this is class MyComponent):
dispatchEvent(new CustomEvent('foo'));
And the parent can listen for that event like this:
<my-app>
<my-component on-foo="{{someMethodOnTheParent}}"></my-component>
</my-app>
In effect, the child simply broadcasts that something has happened, but has no control over how (or even if) the parent responds. If <my-component> is used by a different parent, that parent could choose to respond to the custom event in a different way:
<another-element>
<my-component on-foo="{{someOtherMethod}}"></my-component>
</another-element>
The callback that is triggered in parent could do pretty much anything, including modifying the model.
Hope that helps.

Dart Polymer >= 1.0.0-x
new PolymerDom(this).parentNode
See also https://www.polymer-project.org/1.0/docs/devguide/local-dom.html
Dart Polymer <= 0.16.x
#ShailenTuli is right about encapsulation should not be broken.
But also JS Polymer elements access the parent in their layout elements because it's still convenient in some scenarios.
This works now in PolymerDart too.
(this.parentNode as ShadowRoot).host

Related

Angular2: Dynamic Component Loader and injection

I've been experimenting with the dynamic component loader in Angular2. An issue, possibly related to this: https://github.com/angular/angular/issues/4330 , seems to be that once a component is loaded with, say, the loadIntoLocation() function, the injector cannot find the parent component's injector or the things that were injected into it. As that article suggests, you can pass an array of Resolved Providers obtained from the parent's injector (Injector.resolve) into the last parameter of loadIntoLocation().
This seems to work initially, but I have also found that any children of the dynamically loaded components also have the same problem. The injector of the children does not know to look up the injection tree for providers, so a standard injection in the constructor of the children like
constructor( myComponent: MyComponent)
does not work. The children (of the dynamically loaded components) are not dynamically loaded but just "normally" instantiated using a template, selector etc. I am wondering:
Is this (still) a known issue or am I misunderstanding anything?
If a known issue is there any workaround at the child level? I tried a constructor as above and also using #Host and also using forward ref + #host but none work. Is there another way to manually pass bindings to a component that is not dynamically loaded?
Is there any other possible workaround for this?
The problems seems to be caused by the resolved providers passed to loadToLocation(). DI is hierarchical and DI tries to resolve required types by walking the hierarchy towards the root, but the chain is broken at loadToLocation() because there providers are passed instead of a child-injector.
The dynamically added component and its children can only resolve providers passed to loadToLocation() or listed in the providers list of the dynamically added component itself (or one of its children if it is a (grand-)parent of the actually resolved component).
When DI walks upwards from within the dynamically inserted tree to resolve a dependency, the iteration stops at the component added by loadToLocation() because the injector of this component doesn't have a parent injector (which would be the injector of the host component where the dynamically added component was added).
See also https://github.com/angular/angular/issues/5990
Correction on this. I have conflated another problem in my code with what I thought was the bug described above. The children of my dynamically loaded component were derived from abstract classes. I was trying to inject the abstract class into the children as opposed to the actual implementation which, per this
Interface based programming with TypeScript, Angular 2 & SystemJS
I have learned you cannot do. The injection tree does get broken upon a dynamic load (which I do think should be corrected), but I take back the part about the children thereafter not being able to traverse their own tree. Thanks for the comments - it helped me sort it out.

Subscribing to PostValidationEvent of dynamicaly created child component

For a forms framework in which I like to use JSF as the real UI frontend, I am searching for a way that a parent component gets informed if in a child component the value is changed. The facelet of a basic 'control' looks like this(body/head omitted since no-one can run it anyway without a dozen classes):
<xf:input ref="/my/xpath/value">
<xf:label>Label</xf:label>
</xf:input>
The xf:input component which I developed, dynamically creates a real ui component (PrimeFaces ones) based on the type of the value that ref="/my/xpath/value" points to. This real ui component is created in a preRenderView event like is done in this example. It is handled in the following method in the 'parent' control
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
if (!context.isPostback()) {
control = createControl(context);
//context.getApplication().unsubscribeFromEvent(PostValidateEvent.class, getControl().getClass(), this);
control.subscribeToEvent(PostValidateEvent.class, this);
}
}
The actual controls all have an programmatically added ajax handler added to it, which makes it possible to just process the specific input ('implicit ajax'). Default JSF component validations are normally applied and this all works great.
The issue/challenge is that in this 'wrapper' component I'd like to be informed of value changes after the validation. My first idea was to us the subscribeEvent on the dynamically added control like this:
control.subscribeToEvent(PostValidateEvent.class, this);
The subscribing works, but on the postback, an NPE is thrown in the UIComponent (Mojarra 2.2.9) because the wrapped is null in the following method
public boolean isListenerForSource(Object component) {
if (wrapped instanceof SystemEventListener) {
return ((SystemEventListener) wrapped).isListenerForSource(component);
} else {
return instanceClass.isAssignableFrom(component.getClass());
}
}
This might be because the actual component seems to be newly created when the data is submitted en hence the 'subscription' is lost.
Registering on the ViewRoot does not work since the source of the event is always the ViewRoot and registering on the Application is plain wrong.
It might be that I'm looking for a solution in the wrong direction but for now I'm clueless. Keep in mind that I have no direct control over the created ui controls, nor do I want to override their renderers if I can prevent to. So signalling the parent from the child control is not an option to.
Other things I tried:
Using valueChangeListeners but that did not work either with lots of other problems (including ways to make it extensible)
Using composite components with binding but that failed including them dynamically, requiring naming containers that conflict with the id's required by the rest of the framework, the positions of labels, hints and alerts in the xhtml and/or resulting dom
Taghandlers to manipulate the tree when creating them
This all is with Mojarra up to 2.2.9 (did not check newer yet or MyFaces)
Adding the component in the PreRenderViewEvent works nicely. The thing is that you do not seem to be able to have subscriptions to events survive a request. The actual components are recreated (in the RestoreViewPhase I assume, did not check) and then the subscription to the event is still there, just the 'wrapped' context where it should be called is empty.
Adding the PostValidationEvent event in the PostRestoreStateEvent of this specific component (it is the only one in the FacesContext.getCurrentInstance().getPartialViewContext().getExecuteIds()) makes it fire as mentioned in the comments. The trick (hack/workaround/...) to get rid of the NPE in the next request is to actually remove the event again.
((UIComponent) event.getSource()).unsubscribeFromEvent(PostValidateEvent.class, this);
I'll try to create an example without any PrimeFaces or OmniFaces and see what happens then since they both seem to be wrappers around the context and I want to make sure they are not the cause of the behaviour.

how to access ShadowDOM of other polymer elements?

I'm learning Dart by making a simple webapp. the app ui I have in mind has two parts, one is a control panel, the other is a workspace. by clicking buttons in the control panel, user should be able to control the workspace.
both the control panel and the workspace are custom polymer elements. In the Control Panel's dart class, I can access itself by using shadowRoot.querySelector, but since the control panel needs to control the workspace, I need to access the workspace also. but I don't know how to do that. I tried querySelector for example, It gave me null. I understand it is a shadow DOM in the workspace tag, but how to access other tags' shadow DOM?
I can't find anything online, every example and document seems to only use shadowRoot to access self elements.
It is difficult to access the shadow DOM of another element, and this is by design. Instead of having your two custom elements so tightly coupled, a better approach would be to use events or signals. Your control panel element should take user input and fire appropriate events using the convenient fire() method it inherits from the PolymerElement class. Your application can catch and then relay those events to your workspace element. If that seems overly circuitous, you can use Polymer's <core-signals> element to pass events without dealing with intermediaries.
As an example, inside your control panel element, you might have a bold button.
<button on-click="{{boldClicked}}">Bold</button>
When that button is clicked, the control panel's boldClicked() method is executed in response. It might look something like this:
void boldClicked(Event event, var detail, Element target) {
fire('core-signal', detail: {'name': 'bold', 'data': null});
}
Then in your workspace element's HTML file, you might have:
<core-signals on-core-signal-bold="{{boldEventReceived}}"></core-signals>
And finally, in your workspace element's Dart class would be a method like so:
void boldEventReceived(Event event, var detail, Element sender) {
// manipulate workspace shadow DOM here
}
This is just one of several ways to accomplish this. You can look over the Dart team's <core-signals> example for more.
And of course, if you're using Polymer to its full potential, you will find that you need to do very little manual DOM manipulation. Using data binding and data-driven views is a winning strategy.
You can either use a selector that pierces though all shadow boundaries querySelector('my-tag /deep/ some-element') or querySelector('* /deep/ some-element') or as selector that just pierces through one level of shadow boundary querySelector('my-tag::shadow some-element') or alternatively
place both elements within the <template> of another Polymer element then you can connect attributes of both components with the same field on the common parent element (this is the preferred method in Polymer.
The solution of #user3216897 is fine of course especially if the elements don't share a common parent.
Instead of shadowRoot.querySelector you should be able to use $['abc'] if the element has an id attribute with the value 'abc'.

Why is CDI-Event creating a new instance instead of using existing Oberserver?

I am facing a problem with CDI on JBoss AS 7.1.1
I have two JSF-beas, where one has the CODI ViewAccessScope (Bean A) which shows all entities, and the second is plain RequestScoped (Bean B). Each Bean get a, so called, Presenter injected which takes care of all presentation logic. So far so good.
The Presenter from Bean B is responsible for creating a new entity (calling service...bla...blubb) and when everything is done Bean B is redirecting to another page but since Bean A now has to reload its content I introduced the JEE-6 Observer.
In detail: Both Beans (A & B) get a particular Presenter injected (which has a backrefrence to the jsf-bean via a interface). Bean-B-Presenter fires an event after the entity was successfully created, so that then Bean-A-Presenter (the Observer) can reload the data and notify Bean-A about the changes.
The Problem: I am getting as NullPointerException when the observing Presenter (A) reloads its data because the reference to Bean A is lost. The reason why this happens is because CDI is obviously creating a new Presenter-object (its annotated with #Named) instead of using the one that is coupled with Bean-A.
Workaround: when I use Bean-A as the Observer than everything works.
My code is pretty much the same as seen in the link I added. I don't understand why a new instance is created when firing the event.
UPDATE regarding LightGuards comment:
The presenter beans are just annotated with #Named (which should be Dependent-Scope by default).
I had a look at the Weld-Documentation and it looks like this scope is somehow isolating my beans from each other. I need the presenters to be a new instance, each time a view (jsf-bean) gets initialized (so no Singletons). On the other hand I want to be able to send events between them, meaning that only the already existing instances get notified (not that a new instance is created).
I just did a test with the presenters being RequestScoped. This doesnt work either because now on every HTTP-Request I get a new Presenter even though the view (jsf-bean) to which it belongs is ViewAccessScoped. SessionScope of course works...but this would result in the wrong design.
Sounds like you'll need to create your own scope for this usecase. None of the default scopes sound like they fit your need. Another option would be to look at MyFaces CODI and the conversation scope they're written.
Please ensure that your observers aren't private.
And you have to ensure that you redirect correctly.

ui-dialog, getTitleId method is not in the prototype literal, why?

I want to increase my knowledge concering jquery-ui, so I look at their source code.
I work with jquery-ui 1.19m5.
When I look at the 1.19m5 source code of ui-dialog I see after the call to the widget factory:
$.extend($.ui.dialog, {
...
getTitleId: function($el) {
...
I do not understand this. Why don't they put the getTitleID method directly into the prototype literal (the 3rd parameter with the widget factory call)?
jQuery UI is designed to trigger methods from the appropriate widget API. So to call a method, you would do $('.selector').widgetName('methodName',arguments);
This allows the plugin developer to easily add private/public functions, as well as avoid namespace collision. It is possible to have an object that is resizeable, draggable, and dropable all at one...these three plugins share some method names, such as the enable/disable function.
In this example, if they added it to the prototype under 'enable', this would only allow you to enable/disable the functionality of the last widget you added, making it impossible to have control over all of the widget types. With their API, you can specifically select a widget to modify. Ex. $('.selector').draggable('disable'); which would disable the drag feature, and keep the resizable and droppable widgets fully functional. Keep in mind, many widgets have the same or similar methods, events, and/or option names.
Long and short, it is for namespacing purposes. This also makes it easier on the developer because he only has to worry about the top level widget name when writing his/her own widgets, without worry of what other methods, options, data, etc that has been added to the prototype directly.
They could add it to the prototype under a second layer, possibly, but this doesn't really save you (the user) any time, and probably would not look as clear in code. or they could add a prefix to every single function to specify namespace, but that would clutter your code, and create more checks and potential points of failure for developers creating their own widgets.

Resources