I have a custom #NgComponent in my project and it works if I place it within the static HTML of the application. What I'm trying to figure out is how to add one to the DOM dynamically? If I construct an instance of my Component it does not appear to be of type Element and so it cannot be added directly to the children of an element in the DOM. Is there an alternate way to construct my component or wrap it for injection into the DOM?
e.g. I naively expected to be able to do something like:
dom.Element holderEl = dom.document.querySelector("#my-holder");
holderEl.children.add( new MyComponent() );
But I have also tried simply appending HTML containing my custom element to an element using innerHTML
holder.innerHtml="<my-component></my-component>"
and creating the element using document.createElement()
dom.Element el = dom.document.createElement("my-component");
dom.document.body.append(el);
But the component does not seem to be realized when added.
thanks,
Pat
You can add components dynamically, but you must manually invoke the Angular compiler so it notices that the innerHTML has a component embedded in it.
However, that is not the "Angular way".
Instead, write your template as
<div id="my-holder">
<my-component ng-if="should_component_be_displayed"></my-component>
</div>
Here, my-component will be created and included in the DOM only if should_component_be_displayed is true.
The my-holder div can be removed which leads to a cleaner DOM structure.
Related
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'.
I have my custom decorator like from the tutorial which adds HTML code to a page.
But if HTML code contains my custom component it will not be processed by AngularDart.
How can I add a processed component from a decorator?
Components can't be added dynamically. Instead, use ng-hide with a bool value to toggle it.
Then you can use your decorator to update the value upon your needs.
In angular-dart it is possible to create your own components as can be seen here. If you use custom tags in the html like this:
<rating></rating>
angular will create a component by calling the constructor of the class associated with rating, in this case new RatingComponent() (if i'm not mistaken).
I know you can add attributes for having some control over it, but i was wondering if it is possible to supply your own instances, instead of angular calling the constructor. What if i have a list of buttons in the main controller, how to achieve something like this:
<div ng-repeat='b in ctrl.buttonList'>
<fancy-button instance='b'></fancy-button>
</div>
I have the feeling i'm missing something obvious, but i did search around and couldn't find the answer.
edit (for extra clarification): I think it boils down to if you can or can not influence/bypass the call of the constructor by angular. If it was just about generating the html, its easy to not use the component and just generate the html using the main-controller (like below), but if possible i would like to use a component since it also has shadow-dom for sandboxing the css.
<div ng-repeat='b in ctrl.buttonList'>
<input type='button' class='fancy' value='{{b.label}}'></input>
</div>
You want something like
<div ng-bind-html='ctrl.html'></div>
This way you can provide the html by the controller.
You would have to create your own implementation of NgBindHtmlDirective (just a few lines) though, because the used NodeValidator of ng-bind-html doesn't allow custom tags (yet).
Maybe there are more sophisticated ways but I don't know Angular very well yet.
=== Edit ===
I think what you try to do is not Angularish.
You can ng-repeat over a model that provides values for the attributes of the fancy-button or input.
In the components class you have access to these attributes and can make the behavior and appearance depending on that attributes.
Using ng-bind-html you can create the markup using code if you don't know at development time what kind of tag you want to use.
I would like to pass a reference to WebComponent instances created in markup to the WebComponent dart class. For instance:
html:
<element name="x-container>
<template iterate="x in xs">
<x-content-elem>
<x-item item="{{x}}" top-container="{{lexical-scoped-ref-to-container}}">
</x-content-elem>
</template>
...
I'm looking for a way to get a reference to x-container to the x-item.top-container property. The main thing is x-item might be nested in some complicated way so doing dynamic lookup could be difficult or not very robust.
You can use the DOM to find the parent element. Something like this should work.
From inside of x-item:
Container container = this.parent.xtag;
A custom element acts like a node on the page. The elem.xtag getter returns the Dart object that backs the node on the page.
If there are other elements in-between, you can can still use CSS queries to find elements that you are looking for.
I created my dart web component that extends a DIV element.
In DART I can add a DIV element to the DOM with:
DivElement div = new DivElement();
document.body.elements.add(div);
Dart html api
Can I do the same thing with my web component?
What's the right syntax?
Web UI Specification has a section about web component instantiation:
http://www.dartlang.org/articles/dart-web-components/spec.html#instantiation
... call new FooComponent.forElement(elem) in Dart. We don’t recommend
using this approach because this constructor call cannot be used by
itself–it requires several set up steps. We might have runtime
libraries to make this easier in the future ...