I have a problem with differences in order of lifecycle events in Polymer.dart
Events happen in different order when dart code is run in Dartium and when compiled JavaScript is run in Chrome.
I have 2 Polymer elements: Parent and Child and I added output in created and enteredView functions.
The output is:
Dartium:
ChildElement created
ChildElement enteredView. Variable value: InitMsg
ParentElement created
ParentElement enteredView
Chrome:
ChildElement created
ParentElement created
ParentElement enteredView
ChildElement enteredView. Variable value: InitMsg
The questions are:
is this result completely arbitrary, or is there some order that can be relied upon?
if a variable is assigned in Parent's created method, new value it is obviously not visible in Child's enteredView. I need to do some calculations based on new value. Is PathObserver in child the only solution to get notified of this assignment, or is there some moment in time/lifecycle callback happening after Parent's created() when this value is visible in child?
My code:
parentelement.dart:
import 'package:polymer/polymer.dart';
#CustomTag('parent-element')
class ParentElement extends PolymerElement {
#observable String msg = "InitMsg";
ParentElement.created() : super.created() {
print('Parent created');
msg = "Changed msg";
}
#override
void enteredView() {
super.enteredView();
print('ParentElement enteredView');
}
}
parentelement.html
<link rel="import" href="childelement.html">
<polymer-element name="parent-element">
<template>
<div>
<span>Parent Msg: {{msg}}</span>
</div>
<child-element msg="{{msg}}"></child-element>
</template>
<script type="application/dart" src="parentelement.dart"></script>
</polymer-element>
childelement.dart:
import 'package:polymer/polymer.dart';
#CustomTag('child-element')
class ChildElement extends PolymerElement {
#published String msg;
ChildElement.created() : super.created() {
print('ChildElement created');
}
#override
void enteredView() {
super.enteredView();
print('ChildElement enteredView. Variable value: $msg');
}
}
childelement.html
<polymer-element name="child-element">
<template>
<div>
<span>Child msg: {{msg}}</span>
</div>
</template>
<script type="application/dart" src="childelement.dart"></script>
</polymer-element>
The created constructor is not suitable if you want rely on the order they are called.
As far as I know the polymerCreated callback should be a better fit for you requirement.
I don' really know because enteredView attached fulfilled all my requirements and I therefore never used something else (entereView attached even provides two different slots for own code: 'before super.attached()' and 'after super.attached()')
I had a similar problem and described it in a blog post ( http://www.roberthartung.de/animatr-gui-structure-nesting-polymer-elements/ ). The trick for me was to put the <link rel="import">-statements not in a central place, but into the custom elements itself. My App only has one import for my custom GUI element. The GUI imports its direct custom child elements and so on.
Hope this helps
Robert
Related
Need update a table that looks like that:
<template is="dom-repeat" items="{{mainList}}" index-as='mainListIndex'>
<template is="dom-repeat" items="{{mainList}}" index-as='secondListIndex'>
{{getValueFromListOfLists(mainListIndex, secondListIndex)}}
</template>
</template>
When mainList a changed, function getValueFromListOfLists not call again.
#PolymerRegister('matrix-component')
class MatrixComponent extends PolymerElement {
#Property(reflectToAttribute: true)
List<List<Map>> matrix;
#Property(reflectToAttribute: true)
List mainList;
MatrixComponent.created() : super.created();
#reflctable
getValueFromListOfLists(firstIndex, secondIndex){
return matrix[statusFromIndex][statusToIndex]['info'];
}
}
How i can update that?
If you want to make sure that the function gets called when mainList updates, you have to pass that as an argument to the function (docs on dependent properties).
{{getValueFromListOfLists(mainListIndex, secondListIndex, mainList.*)}}
I have a class defined in dart that looks like this:
class Page extends Object with Serializable {
String name;
Page(this.name);
String toString() {
return name;
}
}
and a custom polymer element structured like this:
<polymer-element name="sidebar-list">
<template>
<ul>
<template repeat="{{page in pages | enumerate}}">
<li>{{page.value}}</li> // what do I call here to get the name of the page?
</template>
</ul>
</template>
</polymer-element>
and a method that defines the polymer object:
#CustomTag('sidebar-list')
class SidebarList extends PolymerElement {
final List<Page> pages = <Page>[new Page('Page 1'), new Page('Page 2'), new Page('Page 3')];
SidebarList.created() : super.created();
}
Pages is a List of Page defined in the custom polymer.
My question is this: how do I reference a method inside of a class from a polymer element placeholder? I tried all the logical things like {{page.value.toString()}} and {{page.value.name}} and {{page.name}} but nothing works.
Interestingly, if the List is of Strings and not pages, {{page.value}} returns a String as expected.
Is this even possible?
Thank you so much for you help! I can offer any clarification if needed.
With | enumerate you should use
<li>{{page.value.name}}</li>
without | enumerate
<li>{{page.name}}</li>
If you not initialize the field like
final List<Page> pages = <Page>[new Page('Page 1'), new Page('Page 2'), new Page('Page 3')];
you need to add #observable so Polymer recognizes when a new value was assigned.
#observable
final List<Page> pages;
I have a page with simple component:
<!DOCTYPE html>
<html ng-app>
<head>
<title>Test</title>
</head>
<body index-page>
<div>
<h1>Status</h1>
<h2>{{ 1 | enum }}</h2>
</div>
<script type="text/javascript" src="packages/web_components/platform.js"></script>
<script type="text/javascript" src="packages/web_components/dart_support.js"></script>
<script type="application/dart" src="index.dart"></script>
<script type="text/javascript" src="packages/browser/dart.js"></script>
</body>
</html>
The filter 'enum' use loads data that using XHR. Therefore, at the page load time the data is available (say, it takes a second). So, while data is not there the filter returns null. How can I trigger the controller to re-evaluate the template when the data is received and the filter is able to return meaningful values?
In the example below I use the Timer to simulate XHR:
import 'dart:html';
import 'dart:convert';
import 'dart:async';
import 'package:angular/application_factory.dart';
import 'package:angular/angular.dart';
#Controller(selector: '[index-page]', publishAs: 'ctrl')
class IndexPageController {
}
const DELAY = true;
#Formatter(name: 'enum')
class EnumNameFormatter {
Map names = new Map();
EnumNameFormatter() {
if (DELAY) {
new Timer(new Duration(milliseconds:2000), fillNames);
} else {
fillNames();
}
}
void fillNames() {
names[1] = "One";
names[2] = "Two";
names[3] = "Three";
}
String call(enumValue) {
var enumName = names[enumValue];
if (enumName != null) {
return enumName;
}
}
}
class MyAppModule extends Module {
MyAppModule() {
// needed for https://github.com/angular/angular.dart/issues/1272
// this will be fixed in 14.0
Binding.printInjectWarning = false;
// Main controller
bind(IndexPageController);
// Formatter
bind(EnumNameFormatter);
}
}
void main() {
applicationFactory().addModule(new MyAppModule()).run();
}
In the example below, If I set DELAY = true - "One" is not displayed on the page. If I set DELAY=false - everything works (as it should). How can I force page refresh/re-rendering when the XHR (Timer) was completed?
In AngularDart, you no longer need to use $apply or $digest to re-render the page. We use Dart Zones to dirty-check your model automatically after any operation.
What you are seeing, is a different bug/feature -- #Formatters are idempotent. That is, we assume that if we have formatted a value once, formatting it again will produce the same result.
Since the expression being formatted: 1 has not changed, we don't re-run the formatter because we assumed it would give the same value.
An easy work-around would be to use a function instead of a formatter.
I want to know if there's some way to style polymer element dynamically, for example :
coba.dart
#CustomTag('hello-world')
class HelloWorld extends PolymerElement {
HelloWorld.created() : super.created();
}
coba.html
<polymer-element name="hello-world">
<template>
<div class="somediv">
<h1>hello world!</h1>
</div>
</template>
</polymer-element>
I want to style .somediv, but without using <style> tag. I tried querying it after HelloWorld instantiation.
HelloWorld.create() : super.create() {
var el = querySelector('.somediv');
el.style.color = 'blue';
}
But it does nothing.
You need to query on the shadowRoot :
HelloWorld.create() : super.create() {
var el = shadowRoot.querySelector('.somediv');
el.style.color = 'blue';
}
You could also assing an id to the element <div id="someId"> and access it using $['someId'] instead of using querySelector.
You should have got an error like
The null object does not have a getter 'style'.
NoSuchMethodError : method not found: 'style'
Receiver: null
Arguments: []
but that error was probably swallowed due to a bug
https://code.google.com/p/dart/issues/detail?id=16372
You was error when call shadowRoot in function created. You can use it in function enteredView().
My example code :
void enteredView() {
super.enteredView();
new Timer(new Duration(milliseconds:10), () {
var el = shadowRoot.querySelector('.somediv');
el.style.color = 'blue';
});
}
In Dart I am attempting something like:
<element name="x-facet-select" constructor="SelectOptions" extends="div">
<template>
<div>
<select bind-value="str" on-click="update()" on-load="init()" id="outputitems" multiple="multiple">
I can't get the on-load (or onload, or anything) method to run in the SelectOptions call. It's jus a simple print Hello World line to console as a test.
Is there a way in Dart's WebUI to invoke a method on the initial loading of an element?
If you want to run code after the user changes the drop down value:
<select id="list" on-change="selectionChanged($event)">
<option>one</option>
<option>two</option>
<option>three</option>
</select>
class SelectOptionsComponent extends WebComponent {
selectionChanged(Event e) {
print(__list.value);
}
}
That would be all.
Update: Looks like you also want to run some code after the component is ready, try inserted():
class SelectOptionsComponent extends WebComponent {
selectionChanged(Event e) {
print(__list.value);
}
inserted() {
// populate __list here.
(__list as OListElement).innerHtml = '<option>bar</option>'; // Just an example.
}
}