pretty much simple things in DartAngular 1.0 & Dart 1.7 - dart

I'm trying to create a component in AngularDart 1.0:
index.html:
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>data_generator_front</title>
</head>
<body>
<my-form></my-form>
<label>Name: </label>
<input type="text" ng-model="myProperty" placeholder="Enter your name here">
<hr>
<h1 ng-cloak>Hello {{myProperty}}</h1>
<input type="submit" ng-click="method1()">
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
index.dart:
import "package:angular/angular.dart";
import "package:angular/application_factory.dart";
import "my_form.dart";
#Injectable()
class RootContext{
String myProperty = "jeahhhhhhhh";
void method1(){
print("method1");
}
}
main(){
applicationFactory()
.rootContextType(RootContext)
.addModule(new DateFormModule())
.run();
}
my_form.html
<form>
<label>Years:</label>
<input type="text" placeholder="begin">
<input type="text" placeholder="end">
<input type="checkbox">
<input type="submit">
</form>
my_form.dart
import "package:angular/angular.dart";
#Component(
selector: "my-form",
templateUrl: "my_form.html")
class DateFormComponent {}
class DateFormModule extends Module {
DateFormModule(){
bind(DateFormComponent);
}
}
Please correct what i'm saying.
I have a class "RootContext" that holds the property 'myProperty' and a method "method1". This class is annotated by #Injectable() which enable the class to be handle by angulardart. like that all the properties/methods are availlable in the html in {{}}, ng-model, ng-click.... last, rootContextType(RootContext) makes RootContext the rootcontext of the app. Is that correct ?
Now I would like to create a Component. (my_form.dart and my_form.html)I succeed to display the html of my component which is great.
I would to pre fill the input (the one with placeholder="begin") with a value like "1980"
here is my attempt:
my_form.dart:
import "package:angular/angular.dart";
#Component(
selector: "my-form",
templateUrl: "my_form.html")
class DateFormComponent {
String years_begin = "1980";
}
class DateFormModule extends Module {
DateFormModule(){
bind(DateFormComponent);
}
}
my_form.html
<form>
<label>Years:</label>
<input type="text" placeholder="begin" ng-model="years_begin">
<input type="text" placeholder="end">
<input type="checkbox">
<input type="submit">
</form>
And that crash with :
...
Missing getter: (o) => o.years_begin
...
ok let's create a getter then: String get years_begin => _years_begin;
but still have the same error...
so #Component() is not like #Injectable() it doesn't turn on all the field/methods to be handle by the view. so how to turn them on ? it's seems like #NgAttr(attrName),
#NgOneWay(attrName), #NgTwoWay(attrName) do the job
let's try this
class DateFormComponent {
#NgAttr("years_begin")
String years_begin = "1980";
}
--> no more exception but the field is not filled
class DateFormComponent {
#NgOneWay("years_begin")
String years_begin = "1980";
}
--> do the job !
class DateFormComponent {
#NgTwoWay("years_begin")
String years_begin = "1980";
}
--> as well
is NgOneWay synchronize model to view ?
is NgTwoWay synchronize model to view and view to model ?
ngAttr seems more to be for the attribute passed in in the HTML like and just at init time ?
let's switch to method now here is my change
my_form.html
<form>
<label>Years:</label>
<input type="text" placeholder="begin" ng-model="years_begin">
<input type="text" placeholder="end">
<input type="checkbox">
<input type="submit" ng-click="method2()">
</form>
my_form.dart
import "package:angular/angular.dart";
#Component(
selector: "my-form",
templateUrl: "my_form.html")
class DateFormComponent {
#NgTwoWay("years_begin")
String years_begin = "1980";
method2(){
print("method2");
}
}
class DateFormModule extends Module {
DateFormModule(){
bind(DateFormComponent);
}
}
it crash with : No getter for 'method2'.
What is the equivalent of NgOneWay ngTwoway for methods ?
Do not hesitate to give me UP TO DATE links and information about angulardart & dart as there are not a lot of documentation up to date even the angulardart website...

Thanks to an answer here I found an answer regarding to the No getter for 'method2' problem.
The transformer struggled so we need to pass extra information: in my component I set the exportExpressions property like this:
my_form.dart
import "package:angular/angular.dart";
#Component(
selector: "my-form",
templateUrl: "my_form.html",
exportExpressions: const ["method2"])
class DateFormComponent {
#NgTwoWay("years_begin")
String years_begin = "1980";
method2(){
print("method2");
}
}
class DateFormModule extends Module {
DateFormModule(){
bind(DateFormComponent);
}
}
I think it's related to tree shaking and that way the transformer exact the 'method2'

I have a class "RootContext" that holds the property 'myProperty' and a method "method1". This class is annotated by #Injectable() which enable the class to be handle by angulardart. like that all the properties/methods are availlable in the html in {{}}, ng-model, ng-click.... last, rootContextType(RootContext) makes RootContext the rootcontext of the app. Is that correct ?
#Injectable() has nothing much to do with Angular binding ({{}}), it is only for the dependency injection system used in Angular and the transformer that generates code to avoid Mirrors/Reflection in production code (which has performance and code bloat issues)
You also need to add a transformers configuration to make this work
see https://github.com/vicb/angular.dart.tutorial/blob/1013-v1/Chapter_06/pubspec.yaml#L12 for an example.
(Angular.dart transformers need to be applied for development too, not only for production)

Related

is the parameter in #NgTwoWay("param") really does something?

I have created a angular dart component "Range" that a can be used in a form.
the form is a component as well
In my code I bind the value return by the component in the form but after renaming things it seems like the parameter given to #NgTwoWay(param), in my case #NgTwoWay("v1") is not doing anything it's still mandatory though.
Here is my code:
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
#NgTwoWay("v1")
String years = "eee";
submit() {
print(random);
print(years);
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
my_form.html
<form>
<range name="years" value="years"></range>
<div>
<label>Random:</label> <input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !" ng-click="submit()">
</div>
</form>
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgTwoWay("value")
String value;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
value = ranges.reduce((begin, item) {
return begin += ",$item";
});
}
info() {
print(range_begin);
print(range_end);
print(ranges);
print(value);
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
range.html
<div>
<label>{{name}}:</label> <input type="text" placeholder="begin"
size="8" ng-model="range_begin"> <input type="text"
placeholder="end" size="8" ng-model="range_end"> <input
type="submit" value="add" ng-click="addRange()"> <input
type="submit" value="info" ng-click="info()">
</div>
I thought that parameter had to bind a DOM attribute with a property of an instance ?
You need these attributes to bind the HTML-attribute of your custom element (component) to a field of your components class.
<body ng-app>
<my-component someattrib="somevalue"></my-component>
when you MyComponent class has a field
#NgAttr('someattrib')
String someField;
then 'someField' will be initialized with 'somevalue'.
You don't need such an attribute for each binding only for binding to attributes.

How can I retrieve value from my component

I have created a form component. In that form component I also have a range component.
I was wondering how can I retrieve my value from my range component and more generally how can I interact with a component from outside it. (even if the goal is to encapsulate things)
I don't know if there are components like that somewhere but for now I just want to learn how it works. thanks !
Here is my code
index.html
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>data_generator_front</title>
</head>
<body>
<my-form></my-form>
<div class="results"></div>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
index.dart
import "package:angular/angular.dart";
import "package:angular/application_factory.dart";
import "package:data_generator_front/component/my_form.dart";
import "package:data_generator_front/component/range.dart";
#Injectable()
class RootContext {
String myProperty = "jeahhhhhhhh";
void method1() {
print("method1");
}
}
main() {
applicationFactory()
.rootContextType(RootContext)
.addModule(new DateFormModule())
.addModule(new RangeComponentModule())
.run();
}
my_form.html
<form>
<range name="years" value="myProp"></range>
<div>
<label>Random:</label>
<input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !">
</div>
</form>
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
submit() {
print("hello");
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
}
info(){
print(range_begin);
print(range_end);
print(ranges);
print(ranges.reduce((begin, item){
return begin += ",$item";
}));
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
range.html
<div>
<label>{{name}}:</label>
<input type="text" placeholder="begin" size="8" ng-model="range_begin">
<input type="text" placeholder="end" size="8" ng-model="range_end">
<input type="submit" value="add" ng-click="addRange()" >
<input type="submit" value="info" ng-click="info()" >
<input type="submit" value="value" ng-click="range()" >
</div>
I guess changing NgOneWay to NgTwoWay should do the trick so the value gets updated inside the component. To get the value outside of the component bind
<range name="years" value="{{myProp}}"></range>
and create a field in your my-form component.
#NgTwoWay('myProp')
var myProp;
Alternatively you can implement ScopeAware to get the scope and then use scope.emit, scope.broadcast, scope.on... to send the data as event on submit to send it across the DOM not just to the immediate parent/child
almost :) but it's only works one way
I initialize the property in my_form.dart then the my_form.html has the value binded and finally the range component can use the value at init time.
but when I change the code inside the component the value is not binded anymore with the my_form.dart
here is the code
range.html didn't change
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
#NgTwoWay("v1")
String v1 = "eee";
submit() {
print(random);
print(v1);
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
my_form.html
<form>
<range name="years" value="{{v1}}"></range>
<div>
<label>Random:</label>
<input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !" ng-click="submit()">
</div>
</form>
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgAttr("value")
String value;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
value = ranges.reduce((begin, item){
return begin += ",$item";
});
}
info(){
print(range_begin);
print(range_end);
print(ranges);
print(value);
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
thanks for helping anyway :)

How to manipulate forms in Angular Dart?

I'm can't find any doc that explains how to manipulates forms in Angular Dart.
I've got the following code in my_component.html:
<form name="form" ng-submit="comp.save()">
<input type="text" required ng-model="comp.user.firstname">
<input type="text" required ng-model="comp.user.lastname">
<button ng-disabled="form.invalid">Save</button>
</form>
And the following one in my_component.dart:
#NgComponent(
selector : 'my-component',
templateUrl : 'my_component.html',
publishAs : 'comp'
)
class MyComponent {
#NgTwoWay('user')
User user;
#NgTwoWay('form')
NgForm form;
MyComponent() {};
void save() {
print(form);
}
}
The validation works well, but when clicking on the button, the print(form) statement always prints null.
Any idea?
Thanks
I guess this is what you want:
class MyComponent {
#NgTwoWay('user')
User user = new User();
Scope scope;
MyComponent(this.scope) {}
void save() {
var form = (scope.context['form'] as NgForm);
print(form.invalid);
}
}

Access controller method from component and/or directive?

I have a component that performs a task, but then needs to refresh the data (a method callable from the controller).
Is it possible to access the controller methods and properties from a component?
Is it available through Scope? Parent/root scope?
(Also noticed I'm using a directive as well which would love to access the parent scope)
I used $broadcast ... Not sure if that's the proper way to do it or not. I imagine trying to access the controller from component/directive is circular? So maybe $broadcast is what I want?
...For methods it makes sense I guess...But I do feel like I should be able to get a property from the controller. I must be doing something wrong if I can't see the parent scope...
You have to set the visibility on the parent then you can inject the parent to the child. (I'm only on my phone and limited possibilities) AFAIK SO has a question+answer already.
It sounds like you have one controller and one component which is a child element of the controller. In this case you can inject the controller in the component's constructor:
#NgController(...)
class MyController {
refresh() {
...
}
}
#NgComponent(...)
class MyComponent {
MyController _myController;
MyComponent(MyController this._myController);
doSomething() {
_myController.refresh();
}
}
Components should basically be reusable and therefore shouldn't have any reference to the calling controller. Here is one solution where two separate controllers use one component to modify controller's property. I'm not sure have I used watch-function properly or is there better way to do this.
Idea comes from this question and answers:
AngularDart components and model binding
edit: ops, sorry: One controller and two different properties.
ang_testi.dart:
import 'package:angular/angular.dart';
import 'package:di/di.dart';
#NgComponent(
selector: 'my-component'
)
class MyComponent {
NgModel _ngModel;
Scope _scope;
MyComponent(this._ngModel, this._scope){
_scope.$watch(() => _ngModel.modelValue, (value) => onC(value));
}
onC(value){
if(value!=null) _ngModel.modelValue=value.toUpperCase();
return _ngModel.modelValue;
}
}
#NgController(
selector: '[main-test]',
publishAs: 'ctrl')
class MainTestController {
String msg;
String msg2;
Scope _scope;
MainTestController(this._scope){
_scope.$watch(() => msg, (value) => onMsgC(value));
}
onMsgC(value){
print("msg change:$value");
}
}
class MyAppModule extends Module {
MyAppModule() {
type(MainTestController);
type(MyComponent);
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
ang_testi.html:
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<title>ng-model test</title>
<link rel="stylesheet" href="ang_testi.css">
</head>
<body main-test>
<my-component ng-model="ctrl.msg"></my-component>
<my-component ng-model="ctrl.msg2"></my-component>
<p><input type="text" ng-model="ctrl.msg"></p>
<p>Hello world from {{ctrl.msg}}!</p>
<p><input type="text" ng-model="ctrl.msg2"></p>
<p>Hello world from {{ctrl.msg2}}!</p>
<script src="packages/shadow_dom/shadow_dom.min.js"></script>
<script type="application/dart" src="ang_testi.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
I'm sorry if I'm polluting this thread.
I found a much simpler way to create a component, which can manipulate data in the calling controller. In the following example the #NgComponent transforms the string from the calling controller to uppercase and preserves a twoway binding.
The key to preserve binding is to use the variable of type: List, Map or Class (I believe also Set and Queue will work). With these types Dart uses "pointers", not values (sorry if the terms are not correct).
The correct type of variable makes also following code work (if you use for example type: String, bindings are not working): https://github.com/angular/angular.dart/issues/264
ang_testi.dart
import 'package:angular/angular.dart';
import 'package:di/di.dart';
#NgComponent(
selector: 'my-component'
)
class MyComponent {
List _test;
#NgTwoWay('test')
set test(List list){
_test=list;
}
List get test{
_test[0]=_test[0].toUpperCase();
return _test;
}
}
#NgController(
selector: '[main-test]',
publishAs: 'ctrl')
class MainTestController {
List msg=[""];
List msg2=[""];
}
class MyAppModule extends Module {
MyAppModule() {
type(MainTestController);
type(MyComponent);
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
ang_testi.html
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<title>ng-model test</title>
<link rel="stylesheet" href="ang_testi.css">
</head>
<body main-test>
<my-component test="ctrl.msg"></my-component>
<my-component test="ctrl.msg2"></my-component>
<p><input type="text" ng-model="ctrl.msg[0]"></p>
<p>Hello world from {{ctrl.msg[0]}}!</p>
<p><input type="text" ng-model="ctrl.msg2[0]"></p>
<p>Hello world from {{ctrl.msg2[0]}}!</p>
<script src="packages/shadow_dom/shadow_dom.min.js"></script>
<script type="application/dart" src="ang_testi.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>

Build Polymer App with multiple elements using one single Dart script

Do you know how to use multiple "polymer-element" with only one Dart script ?
I succeeded but I am not sure it is the best solution.
My example is a Dart/Polymer implementation of this following example with Dart/WebUI:
https://www.dartlang.org/articles/web-ui/#loops
It displays a list of fruits in a polymer-element ("example-template1"), and where we can research a specific fruit in another polymer-element ("example-template2"). The second polymer-element must update the first with data binding.
To do that, I declared as follow my polymer elements. One parent polymer-element named "example-script" (because we can only use one script declaration in a polymer templates file), and children that extend from this parent :
<polymer-element name="example-script">
<script type="application/dart" src="tute.dart"></script>
</polymer-element>
<polymer-element name="example-template1" extends="example-script">
<template>
<div>
<p>Search fruit</p>
<input type="text" class="form-control" value="{{ research }}" on-input="{{ get_results }}">
</div>
</template>
</polymer-element>
<polymer-element name="example-template2" extends="example-script">
<template>
<div><ul>
<template repeat="{{ fruit in fruits }}">
<li>{{ fruit }}</li>
</template>
</ul></div>
</template>
</polymer-element>
My Dart script is as follow:
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('example-script')
class FruitsScript extends PolymerElement {
static List<String> fruitsList = new List();
#observable static List<String> fruits = toObservable(fruitsList);
#observable static String research = '';
FruitsScript.created() : super.created();
}
#CustomTag('example-template1')
class FruitsResearch extends FruitsScript {
FruitsResearch.created() : super.created();
String get research {
return FruitsScript.research;
}
String set research(String search) {
FruitsScript.research = search;
}
void get_results(Event e, var detail, Node target) {
FruitsScript.fruits.clear();
if (FruitsScript.research.length > 0) {
var lResearch = FruitsScript.research.toLowerCase();
var results = FruitsScript.fruitsList.where((v) => v.toLowerCase().contains(lResearch));
FruitsScript.fruits.addAll(results);
}
else {
FruitsScript.fruits.addAll(FruitsScript.fruitsList);
}
}
}
#CustomTag('example-template2')
class FruitsDisplay extends FruitsScript {
FruitsDisplay.created() : super.created() {
List<String> fruits = [ 'Apple', 'Apricot', 'Avocado'];
FruitsScript.fruitsList.clear();
FruitsScript.fruitsList.addAll(fruits);
FruitsScript.fruitsList.sort();
FruitsScript.fruits.clear();
FruitsScript.fruits.addAll(FruitsScript.fruitsList);
}
List<String> get fruits {
return FruitsScript.fruits;
}
}
I declare one parent Class "FruitsScript" to initialize the observable variables. Then, I create two other classes for my two polymer elements "example-template1/2". Hence I can access to my observable variables. But for that, I also need to declare them as static, and to make setters an getters in my subclasses, otherwise my polymer elements can not share the observable variables.
This method works, but do you think there is a better way to make this?
How do you add those elements to your page?
As far as I understand what you want to to, inheritance (extend) is not the appropriate solution.
I have not tried to run this code just edited your code here in the textfield.
If this is what you want to do but something doesn't work post a comment.
I didn't want to put to much time in it as long as it's not clear what exactly you want to achieve.
In your web page you lay out your elements like this:
<example-template1></example-template1>
<example-template2></example-template2>
<example-script></example-script>
Your elements
<polymer-element name="example-script">
<script type="application/dart" src="tute.dart"></script>
</polymer-element>
<polymer-element name="example-template1">
<template>
<div>
<p>Search fruit</p>
<input type="text" class="form-control" value="{{ model.research }}" on-input="{{ get_results }}">
</div>
</template>
</polymer-element>
<polymer-element name="example-template2">
<template>
<div><ul>
<template repeat="{{ fruit in model.fruits }}">
<li>{{ fruit }}</li>
</template>
</ul></div>
</template>
</polymer-element>
Your Dart script is as follow:
import 'package:polymer/polymer.dart';
import 'dart:html';
class Model extends Object with Observable {
#observable List<String> fruits = toObservable(new List<String>());
#observable String research = '';
}
#CustomTag('example-script')
class FruitsScript extends PolymerElement {
#published Model model = new Model();
FruitsScript.created() : super.created();
void attached() {
super.attached();
(document.querySelector('example-template1') as FruitsResearch).model = model;
(document.querySelector('example-template2') as FruitsDisplay).model = model;
}
}
#CustomTag('example-template1')
class FruitsResearch extends PolymerElement {
FruitsResearch.created() : super.created();
#published Model model;
void get_results(Event e, var detail, Node target) {
if (this.research.length > 0) {
var lResearch = this.model.research.toLowerCase();
var results = this.model.fruits.where((v) => v.toLowerCase().contains(lResearch));
this.model.fruits = toObservable(results);
}
}
}
#CustomTag('example-template2')
class FruitsDisplay extends PolymerElement {
#published Model model = new Model();
FruitsDisplay.created() : super.created() {
this.model.fruits = toObservable([ 'Apple', 'Apricot', 'Avocado']);
this.model.fruits.sort();
}
}

Resources