calling main to ngBootstrap with latest polymer-version shows error - dart

To call ngBootstrap I used
void main() {
initPolymer()
.run(() {
ngBootstrap(module: new AppModule());
});
}
Since polymer 0.10.0-pre.8 this seems not possible anymore:
Dartium currently only allows a single Dart script tag per application, and in the future it will run them in separtate isolates. To prepare for this all the following script tags need to be updated to use the mime-type "application/dart;component=1" instead of "application/dart":
&smt;script type=​"application/​dart" src=​"main.dart"></script>
​
Only one Dart script tag allowed per document
But my main is not a component - it is a regular main!!!

Was easier than thought.
index.html:
<head>
<script type='application/dart;component=1' src='main.dart'></script>
</head>
main.dart:
import 'package:polymer/polymer.dart';
import 'package:angular/angular.dart';
import 'package:angular/angular_dynamic.dart';
// HACK until we fix code gen size. This doesn't really fix it,
// just makes it better.
#MirrorsUsed(override: '*')
import 'dart:mirrors';
void myRouteInitializer(Router router, RouteViewFactory views) {
views.configure({
'hello': ngRoute(
path: '/hello',
enter: views('views/hello.html')),
'goodbye': ngRoute(
path: '/hellopolymer/:callerID',
enter: views('views/hello-polymer.html'))
});
}
#NgController( selector: '[webapp-sample]', publishAs: 'ctrl')
class MyControler {
final Repository _repository;
MyControler(final RouteProvider routeProvider,this._repository) {
final int value = routeProvider.parameters["callerID"];
if(value != null && value != null) {
_repository.value = value;
}
}
int get value => _repository.value;
}
class Repository {
int value = 0;
}
class AppModule extends Module {
AppModule() {
value(RouteInitializerFn, myRouteInitializer);
value(Repository,new Repository());
type(MyControler);
factory(NgRoutingUsePushState, (_) => new NgRoutingUsePushState.value(false));
}
}
#initMethod
void init() {
dynamicApplication().addModule(new AppModule()).run();
}

Related

custom annotation / Metadata in dart lang

Can any one explain me the use of annotations in Dart?
In the documentations, I found this example:
library todo;
class todo {
final String who;
final String what;
const todo(this.who, this.what);
}
followed by
import 'todo.dart';
#todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
so, what shall I write in the main() to get the doSomething() function executed?
thanks
Something like
import 'dart:mirrors';
import 'do_something.dart';
import 'todo.dart';
void main() {
currentMirrorSystem().libraries.forEach((uri, lib) {
//print('lib: ${uri}');
lib.declarations.forEach((s, decl) {
//print('decl: ${s}');
decl.metadata.where((m) => m.reflectee is Todo).forEach((m) {
var anno = m.reflectee as Todo;
if(decl is MethodMirror) {
print('Todo(${anno.who}, ${anno.what})');
((decl as MethodMirror).owner as LibraryMirror).invoke(s, []);
};
});
});
});
}

Simple AngularDart component Failing

I have this minimal code for an Angular Dart component, I've even written it in the same file, but I cant get it to work.
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
void main() {
applicationFactory().addModule(new TT()).run();
}
class TT extends Module
{
TT ()
{
bind(SimpleString);
}
}
#Component(
selector: 'simplestring',
publishAs: 'cmp',
template: '<div> {{cmp.str}} </div>'
)
class SimpleString
{
#NgAttr('str')
String str;
}
Html body
<body>
<simplestring str='hola'></simplestring>
</body>
This should show "hola", but nothing is happening.
publishAs:is deprecated and not interpreted any more since AngularDart 1.0
Use the property name directly:
#Component(
selector: 'simplestring',
template: '<div> {{str}} </div>'
)
class SimpleString
{
#NgAttr('str')
String str;
}

Can't get Angular Dart Router to work

I've tried this syntax in AngularDart 0.11.0: Angular Dart passing data from route service into a controller
module.value(RouteInitializerFn, configureRoutes);
void configureRoutes(Router router, RouteViewFactory views)
{
print("configureRoutes");
views.configure({
'login': ngRoute(
path: '/login',
view: 'login/login.tpl.html'),
'today': ngRoute(
path: '/today',
view: '/today/today.tpl.html')
});
However, my routing function never seems to get called. I've used both a print statement and breakpoint to no avail. When I attempt to call it like so:
WorkoutLoggerApplication(this.rootScope, this.router)
{
print("WorkoutLoggerApplication::constructor");
new Future.delayed(new Duration(seconds: 2), ()
{
router.go("login", {});
});
}
I get:
Bad state: Invalid route name: login
I've tried 0.10.0, but no dice. I've also tried 3 varieties of the new bind function format, both also don't seem to ever fire the routing function.
I've also struggled a lot with the current examples. I ended up with something like the example below. The NgRoutingUsePushState setting was necessary in 0.11.0 or changing routes didn't seem to work, may have been fixed on 0.12.0.
library myangular;
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
class MyModule extends Module {
MyModule() {
bind(RouteInitializerFn, toValue: myRouteInitializer);
bind(NgRoutingUsePushState, toFactory: (_) => new NgRoutingUsePushState.value(false));
}
}
void myRouteInitializer(Router router, RouteViewFactory views) {
views.configure({
'foo': ngRoute(
path: '/foo',
view: 'view/foo.html'),
'bar': ngRoute(
path: '/bar',
view: 'view/bar.html',
defaultRoute: true),
});
}
void main() {
applicationFactory()
.addModule(new MyModule())
.run();
}
This is the way I'm handling my routing now, it also took a while, but it's working in AngularDart 0.12.0
In your router file you'll have this code:
void configureRoutes(Router configureRoutes, RouteViewFactory view) {
configureRoutes.root
..addRoute(
name: 'login',
path: '/login',
enter: view('login/login.tpl.html')
)
..addRoute(
name: 'today',
path: '/today',
enter: view('today/today.tpl.html')
);
}
Then in your module initialization class you'll add this code:
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:angular/routing/module.dart';
import 'package:logging/logging.dart';
// router config import
import 'my_router_config.dart';
class MainModule extends Module {
MainModule() {
this
// bind all you need and then bind routing
// ROUTING
..bind(RouteInitializerFn, toValue: configureRoutes)
..bind(NgRoutingUsePushState,
toFactory: (_) => new NgRoutingUsePushState.value(false));
}
void main() {
//some logging logic and then init
Logger.root.level = Level.FINEST;
Logger.root.onRecord.listen((LogRecord r) { print(r.message); });
applicationFactory()
.addModule(new MainModule())
.run();
}
}
Finally, to access the router in a Controller, you would simply do it like this:
#Controller(
selector: '[some-controller]',
publishAs: 'c')
class SomeController {
Router router;
SomeController(this.router) {
print(router);
}
}

Repeat over elements provided as content

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.

How to add a component programmatically in Angular.Dart?

I would like to dynamically build a component tree basing on some information received from AJAX calls.
How to programmatically add a component to the DOM from inside of other component? I have <outer-comp> and I would like, basing on some logic, insert an <inner-comp>. The following code just inserts the elements <inner-comp></inner-comp> to the DOM, and not actual <inner-comp> representation.
#NgComponent(
selector: 'outer-comp',
templateUrl: 'view/outer_component.html',
cssUrl: 'view/outer_component.css',
publishAs: 'outer'
)
class AppComponent extends NgShadowRootAware {
void onShadowRoot(ShadowRoot shadowRoot) {
DivElement inner = shadowRoot.querySelector("#inner");
inner.appendHtml("<inner-comp></inner-comp>");
}
}
Update:
I managed to render the inner component correctly in the following way, but I'm still not sure if this is the proper way:
class AppComponent extends NgShadowRootAware {
Compiler compiler;
Injector injector;
AppComponent(this.compiler, this.injector);
void onShadowRoot(ShadowRoot shadowRoot) {
DivElement inner = shadowRoot.querySelector("#inner");
inner.appendHtml("<inner-comp></inner-comp>");
BlockFactory template = compiler(inner.nodes);
var block = template(injector);
inner.replaceWith(block.elements[0]);
}
}
The API has changed in AngularDart 0.9.9:
BlockFactory now is ViewFactory
scope.$new now seems to be scope.createChild(scope.context)
injector.createChild(modules) now requires a list of modules (instead of a single one)
AngularDart 0.10.0 introduces these changes:
NgShadowRootAware not is ShadowRootAware
..value() now is ..bind(., toValue: .)
So the code of pavelgj now looks like so:
class AppComponent extends ShadowRootAware {
Compiler compiler;
Injector injector;
Scope scope;
DirectiveMap directives;
AppComponent(this.compiler, this.injector, this.scope, this.directives);
void onShadowRoot(ShadowRoot shadowRoot) {
DivElement inner = shadowRoot.querySelector("#inner");
inner.appendHtml("<inner-comp></inner-comp>");
ViewFactory template = compiler([inner], directives);
Scope childScope = scope.createChild(scope.context);
Injector childInjector =
injector.createChild([new Module()..bind(Scope, toValue: childScope)]);
template(childInjector, [inner]);
}
}
This would be a proper use of the block API.
class AppComponent extends NgShadowRootAware {
Compiler compiler;
Injector injector;
Scope scope;
DirectiveMap directives;
AppComponent(this.compiler, this.injector, this.scope, this.directives);
void onShadowRoot(ShadowRoot shadowRoot) {
DivElement inner = shadowRoot.querySelector("#inner");
inner.appendHtml("<inner-comp></inner-comp>");
BlockFactory template = compiler([inner], directives);
Scope childScope = scope.$new();
Injector childInjector =
injector.createChild(new Module()..value(Scope, childScope));
template(childInjector, [inner]);
}
}
Also, if you ever need to recompile the inner template make sure you do childScope.$destroy() on the previous childScope.
The above code samples on longer work because of changes in the Angular Dart library. Specifically ViewFactory.call which no longer takes an injector but takes a Scope and a DirectiveInjector. I've tried adapting what's above and I get very close. The component shows up but none of the bindings are replaced (I see {{cmp.value}} for example.
Here's the code I'm using. I think the issue here is that DirectiveInjector is coming in as null.
void main() {
IBMModule module = new IBMModule();
AngularModule angularModule = new AngularModule();
Injector injector = applicationFactory()
.addModule(module)
.run();
AppComponent appComponent = injector.get(AppComponent);
appComponent.addElement("<brazos-input-string label='test'/>");
}
#Injectable()
class AppComponent {
NodeValidator validator;
Compiler _compiler;
DirectiveInjector _injector;
DirectiveMap _directiveMap;
NodeTreeSanitizer _nodeTreeSanitizer;
Scope _scope;
AppComponent(this._injector, this._compiler, this._directiveMap, this._scope, this._nodeTreeSanitizer) {
validator = new NodeValidatorBuilder.common()
..allowCustomElement("BRAZOS-INPUT-STRING")
..allowHtml5()
..allowTemplating();
}
void addElement(String elementHTML) {
DivElement container = querySelector("#container");
DivElement inner = new DivElement();
inner.setInnerHtml(elementHTML, validator: validator);
ViewFactory viewFactory = _compiler.call([inner], _directiveMap);
Scope childScope = _scope.createChild(new PrototypeMap(_scope.context));
if (_injector == null) {
print("injector is null");
}
View newView = viewFactory.call(childScope, _injector);
container.append(inner);
newView.nodes.forEach((node) => inner.append(node));
}
}
class IBMModule extends Module {
IBMModule() {
bind(BrazosInputStringComponent);
bind(BrazosTextAreaComponent);
bind(BrazosButtonComponent);
bind(ProcessDataProvider, toImplementation: ActivitiDataProvider);
bind(AppComponent);
}
}
I did finally get this to work but was not happy with having to add a timer:
#Injectable()
class AppComponent{
NodeValidator validator;
Compiler _compiler;
DirectiveInjector _directiveInjector;
DirectiveMap _directiveMap;
NodeTreeSanitizer _nodeTreeSanitizer;
Injector _appInjector;
Scope _scope;
AppComponent(this._directiveInjector, this._compiler, this._directiveMap, this._nodeTreeSanitizer, this._appInjector, this._scope) {
validator = new MyValidator();
}
void addElement(String id, String elementHTML) {
DivElement container = querySelector(id);
DivElement inner = new DivElement();
container.append(inner);
Element element = new Element.html(elementHTML, validator: validator);
ViewFactory viewFactory = _compiler.call([element], _directiveMap);
if (_scope != null) {
Scope childScope = _scope.createProtoChild();
View newView = viewFactory.call(childScope, _directiveInjector);
newView.nodes.forEach((node) => inner.append(node));
Timer.run(() => childScope.apply());
} else {
print("scope is null");
}
}
}
EDIT
The package http://pub.dartlang.org/packages/bwu_angular contains this decorator/directive as bwu-safe-html
------
I use a custom directive for that
#NgDirective(
selector: '[my-bind-html]'
)
class MyBindHtmlDirective {
static dom.NodeValidator validator;
dom.Element _element;
Compiler _compiler;
Injector _injector;
DirectiveMap _directiveMap;
MyBindHtmlDirective(this._element, this._injector, this._compiler, this._directiveMap) {
validator = new dom.NodeValidatorBuilder.common()
..allowHtml5()
..allowImages();
}
#NgOneWay('my-bind-html')
set value(value) {
if(value == null) {
_element.nodes.clear();
return;
}
_element.setInnerHtml((value == null ? '' : value.toString()),
validator: validator);
if(value != null) {
_compiler(_element.childNodes, _directiveMap)(_injector, _element.childNodes);
}
}
}
It can be used like
my-bind-html='ctrl.somehtml'
Angular issue
I created an issue to include this functionality into Angulars ng-bind-html https://github.com/angular/angular.dart/issues/742 (declined)

Resources