When I create a component in Angular.dart like
library main;
import 'package:angular/angular.dart';
import 'package:di/di.dart';
class Item {
String name;
Item(this.name);
}
@NgComponent(
selector: 'my-component',
publishAs: 'ctrl',
applyAuthorStyles: true,
template: '''<div ng-repeat="value in ctrl.values"><span>{{value.name}}</span> - <content><content></div>'''
)
class MyComponent {
List<Item> values = [new Item('1'), new Item('2'), new Item('3'), new Item('4')];
MyComponent() {
print('MyComponent');
}
}
class MyAppModule extends Module {
MyAppModule() {
type(MyComponent);
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
and use it like
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
</head>
<body>
<h3>Repeat</h3>
<my-component>
<div>some provided content to repeat</div>
</my-component>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
I get
I know the <content>
tag isn't working that way in web components.
But is there any other way, some manipulation I can do in my component, to get the <div>
provided as child element repeated?
I solved it like
Code of <my-component>
@NgComponent(
selector: 'my-component',
publishAs: 'ctrl',
template: '''<div ng-repeat="value in ctrl.values"><span ng-bind-nodes="ctrl.nodes"></span><span>something hardcoded: {{value.name}}</span></div><content id='content'></content>'''
)
class MyComponent extends NgShadowRootAware {
List<Item> values = [new Item('1'), new Item('2'), new Item('3'), new Item('4')];
List<dom.Node> nodes = new List<dom.Node>();
MyComponent();
@override
void onShadowRoot(dom.ShadowRoot shadowRoot) {
nodes.addAll((shadowRoot.querySelector('#content') as dom.ContentElement).getDistributedNodes());
//nodes.forEach((n) => print(n));
nodes.forEach((n) => n.remove());
}
}
The component removes it's child nodes and provides them in the field nodes
the directive ng-bind-nodes
adds the nodes to the element where it is applied
@NgDirective(
selector: '[ng-bind-nodes]',
publishAs: 'ctrlx' // conflicts with my-component
)
class NgBindNodesDirective {
dom.Element _element;
MyComponent _myComponent;
Scope _scope;
Compiler _compile;
Injector _injector;
NgBindNodesDirective(this._element, this._myComponent, this._scope, this._compile, this._injector);
@NgOneWay('ng-bind-nodes') set nodes(var nodes) {
print(nodes);
if(nodes == null) {
return;
}
_element.nodes.clear();
nodes.forEach((dom.Node node) {
_element.nodes.add(node.clone(true));
});
BlockFactory template = _compile(_element.nodes);
Block block = template(_injector, _element.nodes);
}
}
I don't have an answer, and I can't test my suggestion right now, but try injecting the element, compiler, scope and blockfactory in MyComponent:
Element element;
Compiler compiler;
Injector injector;
Scope scope;
MyComponent(this.element, this.compiler, this.injector, this.scope) {
}
You can access the div as child of 'element'.
Then you don't use template of NgComponent, but instead build your own template from a string, insert the child and compile it:
String template = '''<div ng-repeat="value in ctrl.values"><span>{{value.name}}</span> - <div id="inner"><div></div>''';
void onShadowRoot(ShadowRoot shadowRoot) {
List<DivElement> children = element.children;
shadowRoot.appendHtml(template);
DivElement inner = shadowRoot.querySelector('#inner');
inner.children.add(children);
BlockFactory fact = compiler([shadowRoot]);
Scope childScope = scope.$new();
Injector childInjector =
injector.createChild([new Module()
..value(Scope, childScope)]);
fact(childInjector, children);
}
Maybe it gives you the right direction.