I came through DART custom elements, from dartlang.org site, here and here.
If I understood correctly,this is a vanilla DART custom element, not related to Polymer custom tags.
I wrote the below code,
class CustomElement extends HtmlElement {
factory CustomElement() => new Element.tag('x-custom');
CustomElement.created() : super.created() {
print('CustomElement created!');
}
}
void main() {
document.registerElement('x-custom', CustomElement);
}
and got the "CustomElement created!" statement printed in the console, which means the element had been created!
my question is, what else? how can I use this customs element, and what can I do with it can I write HTML template, if yes, how?
I read this but unfortunately could not how to do same with DART.
any thoughts!
This is also used by Polymer. Polymer is just the combination of Custom Element, HTML Imports, Template, Polymer, Polyfills and some builerplate to connect these parts and provider a nice API.
If you want to reinvent the wheel you can go with CustomElement alone.
Change your main to
void main() {
document.registerElement('x-custom', CustomElement);
var elem = new Element.tag('x-element');
elem.appendText('x-element');
document.body.append(elem);
elem.onClick.listen((e) {
print('clicked');
});
}
and you can react to click events
I was ableto write the below, which had been worked, feel I did it the long way,
I could not use the tag
Not sure if the way I used to callback the elements in the custumElement in the correct way, as I was forced to use .append for all the items, and not sure if there is an easier way to do it.
my index.html file is
pick a color:<input type="color" name="colorname" id="colorname"> the color you selected is: <output id="picked-color"></output> click it !
<div id='my-element'></div>
my index.dart file is:
import 'dart:html';
class CustomElement extends HtmlElement {
factory CustomElement() => new Element.tag('x-custom');
CustomElement.created() : super.created() { }
Element launchElement(Element o1){
o1.onClick.listen((e) => window.alert('the input color is: ${o1.text}'));
print('CustomElement created!');
var output = new Element.html('<div></div>');
var statement = new Element.html('<div></div>');
var bind = new Element.html('<div></div>')
..text='this text will be dynamically replaced by what you are entering down';
var input = new InputElement()
..id ='input'
..type ='text'
..placeholder='enter data here';
input.onInput.listen((e) => bind.text=input.value);
var element = new Element.html('<span>content: </span>')
..style.color='red';
var button = new ButtonElement()
..id = 'awesome'
..classes.add('important')
..onClick.listen((e) => pop(input.value)) // "Hi There!!!")
..text = 'Click Me man!'
..style.color='orange';
statement.innerHtml="<b>I'm an x-custom-with-markup!</b> ";
output.node..add(statement)..add(bind)..add(input)..add(element)..add(button);
return (output);
}
var button1 = new ButtonElement()
..id = 'awesome2'
..text = 'External Click Me man!';
void pop(i){ window.alert("input is: $i"); }
}
void main() {
document.registerElement('x-custom', CustomElement);
var xFoo = new Element.tag('x-custom');
InputElement colorname = querySelector('#colorname');
Element theColor = querySelector('#picked-color');
xFoo = xFoo.launchElement(theColor);
theColor.text = colorname.value;
Element myDiv=querySelector('#my-element');
myDiv.children.add(xFoo);
colorname.onInput.listen((Event e) {
theColor.text = colorname.value;
});
}
Not available now
document.registerElement is deprecated: https://developer.mozilla.org/zh-CN/docs/Web/API/Document/registerElement
window.customElements.define with Dart is blocked by https://github.com/dart-lang/sdk/issues/35829
Related
I have a list of models that I need to create a mini reflective system.
I analyzed the Serializable package and understood how to create one generated file per file, however, I couldn't find how can I create one file for a bulk of files.
So, how to dynamically generate one file, using source_gen, for a list of files?
Example:
Files
user.dart
category.dart
Generated:
info.dart (containg information from user.dart and category.dart)
Found out how to do it with the help of people in Gitter.
You must have one file, even if empty, to call the generator. In my example, it is lib/batch.dart.
source_gen: ^0.5.8
Here is the working code:
The tool/build.dart
import 'package:build_runner/build_runner.dart';
import 'package:raoni_global/phase.dart';
main() async {
PhaseGroup pg = new PhaseGroup()
..addPhase(batchModelablePhase(const ['lib/batch.dart']));
await build(pg,
deleteFilesByDefault: true);
}
The phase:
batchModelablePhase([Iterable<String> globs =
const ['bin/**.dart', 'web/**.dart', 'lib/**.dart']]) {
return new Phase()
..addAction(
new GeneratorBuilder(const
[const BatchGenerator()], isStandalone: true
),
new InputSet(new PackageGraph.forThisPackage().root.name, globs));
}
The generator:
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:glob/glob.dart';
import 'package:build_runner/build_runner.dart';
class BatchGenerator extends Generator {
final String path;
const BatchGenerator({this.path: 'lib/models/*.dart'});
#override
Future<String> generate(Element element, BuildStep buildStep) async {
// this makes sure we parse one time only
if (element is! LibraryElement)
return null;
String libraryName = 'raoni_global', filePath = 'lib/src/model.dart';
String className = 'Modelable';
// find the files at the path designed
var l = buildStep.findAssets(new Glob(path));
// get the type of annotation that we will use to search classes
var resolver = await buildStep.resolver;
var assetWithAnnotationClass = new AssetId(libraryName, filePath);
var annotationLibrary = resolver.getLibrary(assetWithAnnotationClass);
var exposed = annotationLibrary.getType(className).type;
// the caller library' name
String libName = new PackageGraph.forThisPackage().root.name;
await Future.forEach(l.toList(), (AssetId aid) async {
LibraryElement lib;
try {
lib = resolver.getLibrary(aid);
} catch (e) {}
if (lib != null && Utils.isNotEmpty(lib.name)) {
// all objects within the file
lib.units.forEach((CompilationUnitElement unit) {
// only the types, not methods
unit.types.forEach((ClassElement el) {
// only the ones annotated
if (el.metadata.any((ElementAnnotation ea) =>
ea.computeConstantValue().type == exposed)) {
// use it
}
});
});
}
});
return '''
$libName
''';
}
}
It seems what you want is what this issue is about How to generate one output from many inputs (aggregate builder)?
[Günter]'s answer helped me somewhat.
Buried in that thread is another thread which links to a good example of an aggregating builder:
1https://github.com/matanlurey/build/blob/147083da9b6a6c70c46eb910a3e046239a2a0a6e/docs/writing_an_aggregate_builder.md
The gist is this:
import 'package:build/build.dart';
import 'package:glob/glob.dart';
class AggregatingBuilder implements Builder {
/// Glob of all input files
static final inputFiles = new Glob('lib/**');
#override
Map<String, List<String>> get buildExtensions {
/// '$lib$' is a synthetic input that is used to
/// force the builder to build only once.
return const {'\$lib$': const ['all_files.txt']};
}
#override
Future<void> build(BuildStep buildStep) async {
/// Do some operation on the files
final files = <String>[];
await for (final input in buildStep.findAssets(inputFiles)) {
files.add(input.path);
}
String fileContent = files.join('\n');
/// Write to the file
final outputFile = AssetId(buildStep.inputId.package,'lib/all_files.txt');
return buildStep.writeAsString(outputFile, fileContent);
}
}
I have some code:
// main.dart:
void main{
initPolymer();
var view = new ChatAppConsumer();
}
//chat_app.dart
#CustomTag('chat-app')
class ChatApp extends PolymerElement{
ChatApp.created():super.created();
}
class ChatAppConsumer{
final ChatApp view = new Element.tag('chat-app');
}
as far as I can tell I have all my files properly referenced and Im calling initPolymer(); before I attempt to create my custom tag, but I get the type error that the HtmlElement returned by new Element.tag('chat-app'); is not of typeChatApp` but I use this exact same pattern in another package I have and it works perfectly there. Anyone come across something like this before?
initPolymer is not enough, you should pass a closure to initPolymer.run(() => ...) which executes your Polymer related code.
See how to implement a main function in polymer apps for more details
= Polymer 0.16.0
// main.dart:
void main{
initPolymer().then((zone) => zone.run(() {
var view = new ChatAppConsumer();
}));
}
< Polymer 0.16.0
// main.dart:
void main{
initPolymer().run(() {
var view = new ChatAppConsumer();
});
}
I know that it is really easy to create a FileDownloader and call extend with a Button. But how do I start a download without the Button?
In my specific situation right now I have a ComboBox and the file I'd like to send to the user is generated after changing its value, based on the input. The file should be sent immediately without waiting for another click. Is that easily possible?
Thanks
raffael
I found a solution myself. Actually two.
The first one uses the deprecated method Page.open()
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
Page.getCurrent().open(res, null, false);
}
}
The javadoc here mentions some memory and security problems as reason for marking it deprecated
In the second I try to go around this deprecated method by registering the resource in the DownloadComponent. I'd be glad if a vaadin expert comments this solution.
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
private static final String MYKEY = "download";
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
setResource(MYKEY, res);
ResourceReference rr = ResourceReference.create(res, this, MYKEY);
Page.getCurrent().open(rr.getURL(), null);
}
}
Note: I do not really allow the user to open all my files on the server and you should not do that either. It is just for demonstration.
Here is my work-around. It works like a charm for me. Hope it will help you.
Create a button and hide it by Css (NOT by code: button.setInvisible(false))
final Button downloadInvisibleButton = new Button();
downloadInvisibleButton.setId("DownloadButtonId");
downloadInvisibleButton.addStyleName("InvisibleButton");
In your theme, add this rule to hide the downloadInvisibleButton:
.InvisibleButton {
display: none;
}
When the user clicks on menuItem: extend the fileDownloader to the downloadInvisibleButton, then simulate the click on the downloadInvisibleButton by JavaScript.
menuBar.addItem("Download", new MenuBar.Command() {
#Override
public void menuSelected(MenuBar.MenuItem selectedItem) {
FileDownloader fileDownloader = new FileDownloader(...);
fileDownloader.extend(downloadInvisibleButton);
//Simulate the click on downloadInvisibleButton by JavaScript
Page.getCurrent().getJavaScript()
.execute("document.getElementById('DownloadButtonId').click();");
}
});
I'm using dart to develop an app and i want to get the value of a clicked element. I.e:
Html:
<div id="blah">Value!!</div>
Dart:
void main(){
query("#blah").onClick.listen(showValue);
}
void showValue(Event e){
//Get #blah's innerHtml based on the Event(Something like e.target.innerHtml or e.target.value)
}
Anyone? I know how to do it in JS, but I want to know if there's a way to do it in DART!
Edit
Thanks to all of you, I'll try to be a little bit more clear. I have a loop that generates 9 elements dynamically and add them to a container.
Code:
var j = 0;
var optionsSquare = query("#optionsPanel");
while(j < 9){
DivElement minorSquare = new DivElement();
var minorSquareHeight = optionsSquare.clientHeight/3;
var minorSquareWidth = optionsSquare.clientWidth/3;
minorSquare
..attributes = {"class": "miniSugg"}
..style.width = (minorSquareWidth.round()-2).toString().concat("px")
..style.height = (minorSquareHeight.round()-2).toString().concat("px")
..style.float = "left"
..style.border = "1px solid"
..innerHtml = (j+1).toString();
..onClick.listen(showOptionsSquare);
optionsSquare.children.add(minorSquare);
j++;
}
If I try using #Pandian's way, it works, but I only get the value of the last element inside the loop. What I want is to somehow, track down the element clicked and get its value!
EDIT 2
Guys, just solved it!
I'll let the code here as a repo if someone needs this information:
void showOptionsSquare(Event e){
window.location.hash = "#optionsPanel";
mainDiv.style.opacity = (0.2).toString();
DivElement clicked = e.target;
window.alert(clicked.innerHtml);
}
[]'s
Using your example code you could just write
print(e.target.innerHtml);
inside of your showValue function and it would work. Do you get an error or something? If you are worried about the warning you could add a cast to Element or DivElement:
print((e.target as Element).innerHtml);
Try like below... it will help you...
DivElement div;
void showValue(){
window.alert(div.innerHTML);
}
void main() {
div = query('#blah');
div.on.click.add((Event e) => showValue());
}
Like the question at Dynamic class method invocation in PHP I want to do this in Dart.
var = "name";
page.${var} = value;
page.save();
Is that possible?
There are several things you can achieve with Mirrors.
Here's an example how to set values of classes and how to call methods dynamically:
import 'dart:mirrors';
class Page {
var name;
method() {
print('called!');
}
}
void main() {
var page = new Page();
var im = reflect(page);
// Set values.
im.setField("name", "some value").then((temp) => print(page.name));
// Call methods.
im.invoke("method", []);
}
In case you wonder, im is an InstanceMirror, which basically reflects the page instance.
There is also another question: Is there a way to dynamically call a method or set an instance variable in a class in Dart?
You can use Dart Mirror API to do such thing. Mirror API is not fully implemented now but here's how it could work :
import 'dart:mirrors';
class Page {
String name;
}
main() {
final page = new Page();
var value = "value";
InstanceMirror im = reflect(page);
im.setField("name", value).then((_){
print(page.name); // display "value"
});
}
You can use Serializable
For example:
import 'package:serializable/serializable.dart';
#serializable
class Page extends _$PageSerializable {
String name;
}
main() {
final page = new Page();
var attribute = "name";
var value = "value";
page["name"] = value;
page[attribute] = value;
print("page.name: ${page['name']}");
}