When is the removed lifecycle method called for Dart web components? - dart

Latest edit:
This is an open issue in web-ui: https://github.com/dart-lang/web-ui/issues/245
Previously:
I'm trying to figure out how to get removed() from the web component lifecycle methods to be called. Looking through the generated code for my below example, I see there's a call to autogenerated.dispatch(); after replaceElement() which I hoped would be what calls removed(), but I don't see my print statement output.
Maybe related: I glanced through the spec trying to understand what the output of build.dart is doing for the lifecycle methods. Perhaps the spec is out of date? I still don't see composeChildren() listed in the instantiation section of the spec (which is mentioned in this web-ui issue comment) even though composeChildren() gets called in the autogenerated code from build.dart.
The reason behind this question is my interest in a Dart webapp able to load and unload web components within a single parent html file programmatically (via the instantiation instructions in the spec), instead of having to declare web components in the html. I'm running with web_ui-0.2.11. Thanks!
webcomponent:
<!DOCTYPE html>
<html><body>
<element name="x-lifecycle-test" constructor="LifecycleTest" extends="div">
<template> {{foo}} </template>
<script type="application/dart">
import 'dart:html';
import 'package:web_ui/web_ui.dart';
var foo = "testing lifecycle methods";
class LifecycleTest extends WebComponent{
inserted() => print("inserted");
removed() => print("removed");
}
</script>
</element>
</body></html>
Parent html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"><title>Lifecycle</title>
<link rel="components" href="lifecycle_test.html">
</head>
<body>
<div>
<button on-click="replaceElement()">replace element</button>
</div>
<div id='holder'>
<x-lifecycle-test></x-lifecycle-test>
</div>
<script type="application/dart">
import 'dart:html';
void replaceElement() {
query('#holder').replaceWith(new DivElement()
..id = 'holder'
..text = 'replaced');
}
main() {}
</script>
<script type='text/javascript' src="https://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
</body>
</html>

Adding an answer here for completeness: web components are used in Dart using Polymer. When an instance of a custom element is removed from the DOM, the leftView life cycle method triggers. You can read more about this at https://www.dartlang.org/docs/tutorials/polymer-intro/#life-cycle-methods.

Related

Simple Dart Web Component Not Working

Short Version: The custom web component example in the first link isn't working for me. Why not? I'm running this in Dartium.
Long Version:
I copied and pasted this Dart Web UI example from this tutorial into the Dart Editor and tried to run it. Nothing showed up on the page. I've used dart before but not with web components, so I noticed that one difference between this code and other code I've written is that there was no <script src="packages/browser/dart.js"></script>, so I added that at the bottom. Now I got the error:
Internal error: Dart_Invoke: did not find top-level function 'main'.
I put a print statement in the main() function, and the text was printed before the error, which is strange. I guessed and tried adding main() {} inside the <script> tag that was in the custom component. That is, the script tag looked like:
<script type="application/dart">
import 'package:web_ui/web_ui.dart';
main() {print("in main in component");}
class CounterComponent extends WebComponent {
int count = 0;
void increment() { count++; }
}
</script>
Now that error goes away, and both print statements are printed, but nothing happens.
Here is the original tutorial code for your convenience:
<!DOCTYPE html>
<!--
Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
for details. All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.css">
</head>
<body>
<element name="click-counter" constructor="CounterComponent" extends="div">
<template>
<button on-click="increment()">Click me</button>
<span>(click count: {{count}})</span>
</template>
<script type="application/dart">
import 'package:web_ui/web_ui.dart';
class CounterComponent extends WebComponent {
int count = 0;
void increment() { count++; }
}
</script>
</element>
<div class="well">
<div is="click-counter"></div>
</div>
<script type="application/dart">
main(){}
</script>
</body>
</html>
Web UI applications need to be "built" (usually by a script called build.dart in the project root, see this article for more details).
If I go to the Dart Editor, create a new test project using the wizard and selecting the Web Project (using the web_ui library) option, this creates the boilerplate including the build script.
Open up the html file and paste in the code from the github tutorial, replacing what is there already. When you save the file, the build.dart will be invoked, outputting the build version to /web/out/
Hit the run button, and the Dart Editor will open the app in Dartium (it knows to add /out/ to the URL).

How do I structure a "Controller" in Dart's web_ui?

I have the following code
xviewcontainer.html
<!DOCTYPE html>
<html>
<head>
<title>xviewcontainer</title>
<link rel="components" href="xsearch.html">
<link rel="components" href="xcard.html">
</head>
<body>
<element name="x-view-container" constructor="ViewContainerComponent" extends="div">
<template>
<template instantiate="if view == 'SEARCH_VIEW'">
<x-search></x-search>
</template>
<template instantiate="if view == 'CARD_VIEW'">
<x-card></x-card>
</template>
</template>
</element>
<script type="application/dart" src="xviewcontainer.dart"></script>
<!-- for this next line to work, your pubspec.yaml file must have a dependency on 'browser' -->
<script src="packages/browser/dart.js"></script>
</body>
</html>
xviewcontainer.dart
import 'package:web_ui/web_ui.dart';
class ViewContainerComponent extends WebComponent {
String view = 'SEARCH_VIEW';
}
I have the event handling code within some other currently rendered sub-component of x-search. How do I get a reference to the containing x-view-container instance? I wish to change the .view property so that x-view-container will render x-card instead of the currently rendered x-search. I would be specifically interested in how to do so from my event handlers relative position, how to do it in a absolute fashion, as well as how to do so in any other manner.
void openCardView(){
WHAT_DO_I_PUT_HERE.view = 'CARD_VIEW';
}
You can query for the element you have on the DOM with query() method. Simplest example is query('x-view-container'). Or assign a class or an id on it and query against that. Then access the xtag property to get the actual web component instance.
Here's an example:
import 'package:web_ui/watcher.dart' as watchers;
main() {
// I'm assuming that the HTML tag is somewhere on the page.
query('x-view-container').xtag.view = 'CARD_VIEW';
watchers.dispatch(); // You may need to call this, or use #observable stuff.
}

dart clipboardData always null

The following
main.html
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<p id="test" draggable="true">hello world</p>
<script type="application/dart" src="main.dart"></script>
<!-- for this next line to work, your pubspec.yaml file must have a dependency on 'browser' -->
<script src="packages/browser/dart.js"></script>
</body>
</html>
and main.dart
import 'dart:html';
void main() {
var elem = query('#test');
elem.onDragStart.listen((evt) {
evt.clipboardData.setData('text/html', elem.innerHtml);
});
}
are producing the exception
The null object does not have a method 'setData'.
NoSuchMethodError : method not found: 'setData'
Receiver: null
Arguments: ["text/html", "hello world"]
I've searched, but can find no relevant information about what I could possibly be doing wrong, or about clipboardData in dart at all (even the API is silent on the issue, and the source dart:html file just points to "native code"
(From my comment to the original question)
Use this instead:
evt.dataTransfer.setData('text/html', elem.innerHtml);
It is an attribute on MouseEvent (api ref) rather than the base Event class, and you can get autocomplete and remove editor warnings by explicitly declaring that evt is of type MouseEvent:
elem.onDragStart.listen((MouseEvent evt) {
evt.dataTransfer.setData('text/html', elem.innerHtml);
});
clipboardData seems to have been deprecated without warning. In web_ui components (where I first observed this), the dataTransfer attribute is not recognised by the editor as a valid attribute on instances of Event. I can't find any reference on the web as to why this change was made (the API docs don't say anything on the matter and I couldn't find any recent posts on the discussion board)...

Loading a web component in Dart M2 (web_ui)

Through my journey of dart, I stumbled upon a "blocker" in terms of loading a component.
While having my component defined as followed:
<!DOCTYPE html>
<element name="x-foo" constructor="FooComponent" extends="button">
<template>
<button type="button" class="btn {{classes}}"> {{text}} </button>
</template>
<script type="application/dart">
import 'package:web_ui/web_ui.dart';
String classes = '';
String text = '';
class FooComponent extends WebComponent {
}
</script>
</element>
and referencing the component as followed:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<!-- '../web/foo.html' or '../web/out/foo.html.dart' -->
<link rel="components" href='foo.html'>
</head>
<body>
<h1>example</h1>
<p>Hello world from Dart!</p>
<x-foo></x-foo>
<script type="application/dart">void main() { }</script>
<script type="text/javascript" src="dart.js"></script>
</body>
</html>
and my build script not creating a html file (output folder: foo.html.dart), I'm not sure to which file I have to reference.
The manual is also not declarative enough to solve my issue:
http://www.dartlang.org/articles/dart-web-components/spec.html#loading-components
Referencing to either the definition of the component (foo.html) or it's generated output (foo.html.dart) is not working. I've also double checked the paths of both files through inspection, which just downloaded both files with chromium.
My concluding question:
Is this reference (link element href) pointing to an internal intelligence or to a "physical" available file at runtime? And if secondly, which one (generated (html/dart) or source)?
To avoid misunderstandings, I've added a list of my repo:
foo
packages
examples
assets
dart.js
example.html
web
out
foo.html.dart
foo.html
build.dart
Component file (foo.html) is missing the <html><body>...</body></html> tags:
<!DOCTYPE html>
<html>
<body>
<element name="x-foo" constructor="FooComponent" extends="button">
...
</element>
</html>
</body>
Both files (examples.html and foo.html) must be in the same base directory:
web
examples.html
foo.html
...
Then, examples.html need be used as argument inside build.dart:
build(new Options().arguments, ['web/example.html']);
And, finally, foo.html (that is, web/foo.html) must be the one to be linked:
<link rel="components" href='foo.html'>
The way you have it in your main HTML file is correct. You reference foo.html because the referencing HTML document needs to be compiled with dwc. dwc will take the main HTML file and compile it and all the the components it includes. The component are completely compiled to Dart and they .html files won't be used anymore.
If you're trying to edit example.html to include your component, you'll need to compile example.html, and not foo.html. You'll still generate foo.html.dart, but also example.html.dart and a bootstrap script to load everything up.

How can I link to an external Dart library containing the constructor for my web component?

I've been following the Dart web-ui codelab. When I embed dart source code inside a web component .html file, I'm not getting any static analysis or autocomplete support in the Dart Editor (there's an open bug for this http://code.google.com/p/dart/issues/detail?id=7449 ). Hence, I'm looking for a temporary workaround by using the src attribute.
According to the spec, the src attribute is supported for web components in Dart:
https://www.dartlang.org/articles/dart-web-components/spec.html#behavior. I tried linking to an external Dart library: given a foo.html web component for
<element name="x-foo-component" constructor="FooComponent" extends="div">
I'd like to link to a separate foo_embed.dart file in the same directory as my web component, which defines FooComponent, by adding:
<script type="application/dart" src="foo_embed.dart"></script>
within foo.html. Following the spec's suggestions, foo_embed.dart needs to be a Dart library, and would contain:
library foo_embed;
import 'package:web_ui/web_ui.dart';
class FooComponent extends WebComponent {
...
}
When I try this, running build.dart (from these instructions http://www.dartlang.org/articles/dart-web-components/tools.html) ends up only putting foo_embed.dart in out/ and there's no out/foo.html.dart generated for importing in application.dart.
As expected, pasting the contents of foo_embed.dart as an inline script inside foo.html directly (as done in the codelab) works with build.dart, and I can launch my webapp in Dartium, so I don't seem to have any other syntax problems in my project.
Do I probably have a simple syntax mistake somewhere? Or is this a temporary limitation of the Dart web components compiler? Thanks.
I can't reproduce your problem.
This works for me:
lib/foo.dart
library foo;
import 'package:web_ui/web_ui.dart';
class FooComponent extends WebComponent {
var foo = 'asddfg';
}
lib/foo.html
<element name="x-foo" constructor="FooComponent" extends="div">
<template>
<input value="{{ foo }}" />
</template>
<script type="application/dart" src="foo.dart"></script>
</element>
example/test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="components" href="packages/foo/foo.html" />
</head>
<body>
<x-foo></x-foo>
<script type="application/dart">main() {}</script>
<script type="text/javascript" src="https://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
</body>
</html>
Then I open up Dartium and go to .../example/out/test.html and I see an input with the data bound to it properly.

Resources