Accessing Data from Custom Object in a Repeated List - dart

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;

Related

Calling function in template repeat

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.*)}}

Observe changes to properties of items in a list in Polymer 1

I have a property
#property final List<Item> items = [
new Item('red', false),
new Item('green', true),
new Item('blue', false)
];
where class Item looks like
class Item extends JsProxy {
#reflectable String color;
#reflectable bool checked;
Item(this.color, this.checked);
}
The HTML looks like
<template is="dom-repeat" items="{{items}}">
<label><span>{{item.color}}</span>
<input type="checkbox"
value="{{item.color}}"
checked="{{item.checked::change}}">
</label>
</template>
I want to be notified when checked in any of the items was changed.
An observer can be set up using the #Observe('some.path') annotation.
If the path contains a .*, the handler is called with a change record which contains the actual path of the change.
#Observe('items.*')
void updateSelectedColors(Map record, [_]) {
String path = record['path'];
if (path == 'items' || path.endsWith('.checked')) {
// do something
}
}
}
path == 'items' applies for the initialization of the items property with the default value. path.endsWidth('.checked') ensures that the code (// do something) is only executed when actually the checked property was changed. All other changes are ignored.

Order of lifecycle events in Polymer.dart

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

How to style polymer element dynamically

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';
});
}

Can I apply Dart's string interpolation dynamically?

(from the Dart discussion mailing list by Tristan McNab)
I'm trying to build a server-side MVC framework and generating views based on templates and whatnot, and I was wondering if I could apply Dart's string interpolation dynamically. For example, this would be my view template:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${ViewData["Title"]}</title>
<link href="/Content/css/site.css" rel="stylesheet" />
</head>
<body>
<h1>${ViewData["Title"]}</h1>
<div id="container">
<p>Hello world!</p>
</div>
</body>
</html>
And I'd like to apply the ViewData variable using:
static String applyViewData(String html, Map ViewData) {
// apply interpolation here
}
Is this at all possible at the moment? My searching for the APIs indicates that it isn't.
(posted by Bill Hesse)
By wrapping the string literal in a function that takes the context as
a parameter, you can have a Function : context -> String that you can
pass around instead of a String. If you need to use some String
operations, like concat, on these objects, you can implement these
operations on a class encapsulating this type ("lifting" them). This
seems like a straightforward way to give the string literal in one
place, and give the data you want to interpolate in another.
String interpolation always happens dynamically, each time the literal
is used, and the data can easily come from a parameter to a function
rather than from the lexical context.
For example:
Function MyTemplate() {
return (Context context) {
return "<table><tr><td class=${context.leftColumnClass}>Red Sox</td><td>${context.data}</td></tr></table>";
}
}
...
var templateHere = MyTemplate();
...
var output = templateHere(context);
You could also skip a level of indirection and just create
String FillMyTemplate(Context context) => '''
<html><head><title>$context.title</title></head>
''';
and use FillMyTemplate where you need the template.
(posted by Sam McCall)
There's a trick involving noSuchMethod():
class Template {
var _context;
noSuchMethod(method, args) {
if (!method.startsWith("get:")) return super.noSuchMethod(method, args);
return _context[method.substring(4)];
}
abstract String template();
String evaluate(context) {
_context = context;
try {
return template();
} finally { _context = null; }
}
}
And then create a subclass:
class MyTemplate extends Template { template() => """
<title>$title</title>
<h1>$title</h1>
""";}
Finally, use it!
final renderedText = new MyTemplate().evaluate({"title": "Hello, world"})

Resources