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 :)
Related
In ASP.NET i have the following
public class TestController : Controller
{
public IActionResult Index()
{
return View(new MyModel()
{
Activities = new Activity[]
{
new Activity(){ },
new Activity(){ }
}
});
}
}
public class MyModel
{
public IList<Activity> Activities { get; set; }
}
public class Activity
{
public bool IsActive { get; set; }
}
cshtml
#model Metatasker.Integration.UI.Controllers.MyModel
<form id="myform">
#for (int i = 0; i < Model.Activities.Count; i++)
{
#Html.CheckBoxFor(x => x.Activities[i].IsActive)
}
</form>
<button id="btn">Click Me</button>
<script type="text/javascript">
$(function () {
function validate() {
var kendoValidator = $('#myform').kendoValidator().data("kendoValidator");
return kendoValidator.validate();
}
$("#btn").click(function () {
alert(validate());
})
})
</script>
I am using Kendo's Validate method to validate form. In code above when i have multiple CheckBoxes The validate() method always returns false. If i have single check box then it works.
I have jsfiddle demo. The html in jsfiddle is a rendered Razor view.
DEMO
Try the following snippet.
<form id="form1">
<!-- Kendo UI Checkbox -->
<input type="checkbox" id="checkboxMale" name="Gender" required />
<label for="checkbox">Male</label>
<span class="k-invalid-msg" data-for="Gender"></span>
<input type="checkbox" id="checkboxFemale" name="Gender" required />
<label for="checkbox">Female</label>
<span class="k-invalid-msg" data-for="Gender"></span>
<button>Validate</button>
</form>
<script>
$(document).ready(function() {
var validator = $("#form1").kendoValidator().data("kendoValidator");
});
</script>
You will notice that the validator treats only true values as inputs which are filled, else it serves up the required validation message. Each check box is validated individually.
So, I suggest using a custom rule.
<form id="myform">
<ul validationMessage="You must enter a gender">
<li>
<input id="activity1" name="activity" type="checkbox" value="activity1" />
<label for="activity1">Activity1</label>
</li>
<li>
<input id="activity2" name="activity" type="checkbox" value="activity2" />
<label for="activity2">Activity2</label>
</li>
</ul>
<button>Validate</button>
</form>
<script>
$("#myform").kendoValidator({
rules: {
customRule1: function(input) {
if (input.is("[name=activity]")) {
return $("[name='activity']:checked").length > 0;
}
}
},
messages: {
customRule1: "Atleast one activity should be selected."
}
});
</script>
There is also a demo which uses radio buttons, which you can refer to.
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.
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)
What is the proper way of binding an input field to an int property on an object (e.g. input box changes and updates int property of an object causing another element who is binding to the same property to update)
Example code is below; I may be thinking the wrong way going this route but need some clarification.
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="import" href="components/calc.html">
<script type="application/dart">export 'package:polymer/init.dart';</script>
<script src="packages/browser/dart.js"></script>
</head>
<body>
<my-calc></my-calc>
</body>
</html>
<!-- calc.html -->
<polymer-element name="my-calc">
<template>
<label>Price</label>
<input value='{{ price }}'>
<label>Qty</label>
<input value='{{ qty }}'>
<label>Total</label>
<input value='{{ price * qty }}'>
</template>
<script type="application/dart" src="calc.dart"></script>
</polymer-element>
.
// calc.dart
import 'package:polymer/polymer.dart';
#CustomTag('my-calc')
class CalcElement extends PolymerElement {
#observable int price = 0;
#observable int qty = 0;
CalcElement.created() : super.created();
}
You can define a two-way transformer of polymer expression that will convert String to int :
class StringToInt extends Transformer<String, int> {
String forward(int i) => '$i';
int reverse(String s) => int.parse(s);
}
Then you add an attribute asInteger to your PolymerElement (you can alternativelly add the transformer globally as decribed in this other answer).
// calc.dart
import 'package:polymer/polymer.dart';
#CustomTag('my-calc')
class CalcElement extends PolymerElement {
#observable int price = 0;
#observable int qty = 0;
final asInteger = new StringToInt();
CalcElement.created() : super.created();
}
And finally use this transformer :
<!-- calc.html -->
<polymer-element name="my-calc">
<template>
<label>Price</label>
<input value='{{ price | asInteger }}'>
<label>Qty</label>
<input value='{{ qty | asInteger }}'>
....
</template>
<script type="application/dart" src="calc.dart"></script>
</polymer-element>
You're on the right track here. The only problem is that the value attribute of the input element is a string. One way to do it is like this:
<!-- calc.html -->
<polymer-element name="my-calc">
<template>
<label>Price</label>
<input value='{{ price }}'>
<label>Qty</label>
<input value='{{ qty }}'>
<label>Total</label>
<input value='{{ int.parse(price) * int.parse(qty) }}'>
</template>
<script type="application/dart" src="calc.dart"></script>
</polymer-element>
//calc.dart
import 'package:polymer/polymer.dart';
#CustomTag('my-calc')
class CalcElement extends PolymerElement {
#observable String price = "0";
#observable String qty = "0";
CalcElement.created() : super.created();
}
I think the answer above is the right way, but I am using this instead of the Transformer:
class MyPolymerExpressions extends PolymerExpressions {
MyPolymerExpressions(): super(globals: {
'intToString': (int input) => '$input',
});
#override
prepareBinding(String path, name, node) => Polymer.prepareBinding(path, name, node, super.prepareBinding);
}
and add this line in de calc.dart :
#override PolymerExpressions syntax = new MyPolymerExpressions();
Note: in order to use PolymerExpressions, you need:
import 'package:polymer_expressions/polymer_expressions.dart';
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();
}
}