Access Polymer inner element programmatically - dart

I'm enclosing my app in a Polymer element and I want to use another polymer element inside it. To call all the method of the inner element I'm trying to use $[].
Insider the external polymer element I have this:
ImageEditor ime;
DivElement div2;
ImageTool.created(): super.created(){
div2 = $["secondDiv"];
ime = $["imageEditor1"]
}
In the Html I simply have:
<polymer-element name="da-imagetool">
<template>
<div class="images" id="mainDiv">
<da-imageeditor id="imageEditor1" name="ied"></da-imageeditor>
with the script src at the end.
For some reason I get an exception when I assign the imageEditor1 to ime.
Exception: type 'HtmlElement' is not a subtype of type 'ImageEditor' of 'value'.

It looks like the browser hasn't upgraded the <da-imageeditor> elements.
Make sure that you <import> the <da-imageeditor> element, and have the correct #CustomTag annotation on the ImageEditor class declaration.

This is most likely an issue with the import path.
If you don't use the right path the type is not recognized (canonicalization problem)
This bug should be solved since a while
https://code.google.com/p/dart/issues/detail?id=15953
but I haven't worked with Polymer since.
Show your import paths (HTML and Dart) and the directory structure of your app (where is your entry page and your Polymer elements) then I'll take a look.

Which version of dart-polymer are you using? With the 0.9.5, the following lines:
XElement.created(): super.created() { print($['el-id']); }
void enteredView() { print($['el-id']); }
In created(), the referred element gives nothing whereas in enteredView(), it does refer to the specific element of the shadow root.
The behavior disappears if shadowRoot.querySelector('#el-id') is used in lieu of the shorthand map $['el-id'].

Related

Moving PolymerElement components around programmatically

I have been working on a component to streamline a series of other components. The reason I wanted to do this is pretty much to create 1 place where the implementations would be since the code is the same, we don't have to worry about maintaining 17 html files, just 1.
I was trying to find a way to programmatically move 1 web component into another. some sort of A.appendHtml(B); but i was not 100% sure if that worked with WebComponents.
My goal is to move mine-b's template contents into ele-a before it renders out to the page. Essentially unwrapping the mine-b wrapper and injecting it to where it is suppose to go
<template>
<ele-a></ele-a>
<div>
<mine-b></mine-b>
</div>
</template>
<ele-a></ele-a> accepts only 2 tag types: sub-a and sub-b. sub-b can accept form tags.
<ele-a>
<sub-a></sub-a>
<sub-b>
<form></form>
</sub-b>
</ele-b>
so i thought to myself to create a component which would allow me to streamline all the attribute setting
<mine-a>
<ele-a>
<content></content>
</ele-a>
</mine-a>
<mine-b>
<sub-a></sub-a>
<sub-b>
<content></content>
</sub-b>
</mine-b>
which would allow me to do something like:
<mine-a>
<mine-b>
<form></form>
</mine-b>
</mine-a>
THe issue i have been having is that since ele-a only accepts sub-a and sub-b so i cant define it as a child of ele-a. The reason is the select attribute inside of ele-a which will prevent me from stamping out mine-b. So i tried to make it a sibling:
<mine-a>
<ele-a></ele-a>
<mine-b></mine-b>
</mine>
So this is where i am right now. In the dart for mine-a which extends PolymerElement. Is there a way to move the stamped out contents of the template of mine-b to ele-a? IE: the sub-a, and sub-b?
I was thinking to do something like:
<mine-a>
<ele-a id="targetEle"></ele-a>
<div id="sourceEle" hidden>
<content select="mine-b"></content>
</div>
</mine-a>
class MyElementA extends PolymerElement {
DivElement get _source => $['sourceEle'];
ElementA get _target => $['targetEle'];
MyElementA.created() : super.created(){
_target.appendHtml(_source.children());
}
}
or something to just move 1 WebComponent into another? I have been having some issues with this.
When looking at the PolymerLife Cycle, I was thinking I might be able to do it prior to the dom being initialized, by doing it in the created function.

How to query for an element inside a dom-repeat

I have been scouring the web for a clear answer on how to query for an element generated by a dom-repeat element from Dart code.
sample.html
<dom-module id="so-sample>
<style>...</style>
<template>
<template is="dom-repeat" items="[[cars]] as="car>
...
<paper-button on-click="buttonClicked">Button</paper-button>
<paper-dialog id="dialog">
<h2>Title</h2>
</paper-dialog>
</template>
</template>
sample.dart
I'll omit the boilerplate code here, such as imports or the query to my database to fill the cars property ; everything works fine.
...
#reflectable
void buttonClicked(e, [_])
{
PaperDialog infos = this.shadowRoot.querySelector("#dialog");
infos.open();
}
This generates the following error :
Uncaught TypeError: Cannot read property 'querySelector' of undefined
I have tried several 'solutions', which are not, since nothing works.
The only thing I saw on quite a lot of threads is to use Timer.run() and write my code in the callback, but that seems like a hack. Why would I need a timer ?
I understand my problem may be that the content of the dom-repeat is generated lazily, and I query the items 'before' they are added to the local DOM.
Another advice I didn't follow is to use Mutation Observers. I read in the polymer API documentation that the observeNodes method should be used instead, as it internally uses MO to handle indexing the elements, but it again seems a bit complicated just to open a dialog.
My final objective is to bind the button of each generated model to a dedicated paper-dialog to display additional information on the item.
Has anyone ever done that ? (I should hope so :p)
Thanks for your time !
Update 1:
After reading Gunter's advices, although none of them actually worked by themselves, the fact that the IDs aren't mangled inside a dom-repeat made me think and query paper-dialog instead of the id itself, and now my dialog pops up !
sample.dart:
PaperDialog infos = Polymer.dom(root).querySelector("paper-dialog");
infos.open();
I now hope that each button will call the associated dialog, since I'll bind data inside the dialog relative to the item I clicked ~
Update 2:
So, nope, the data binding didn't work as expected: All buttons were bound to the item at index 0, just as I feared. I tried several ways to query the correct paper-dialog but nothing worked. The only 'workaround' I found is to query all the paper-dialog into a list and then get the 'index-th' element from that list.
#reflectable
void buttonClicked(e, [_])
{
var model = new DomRepeatModel.fromEvent(e);
List<PaperDialog> dialogs = Polymer.dom(this.root).querySelectorAll("paper-dialog");
dialogs[model.index].open();
}
This code definitely works, but it feels kind of a waste of resources to get all the elements when you really only need one and you already know which one.
So yeah, my initial problem is solved, but I still wonder why I couldn't query the dialogs from their id:
...
<paper-dialog id="dialog-[[index]]">
...
</paper-dialog>
#reflectable
void buttonClicked(e, [_])
{
var model = new DomRepeatModel.fromEvent(e);
PaperDialog dialog = Polymer.dom(this.root).querySelector("dialog-${model.index}");
dialog.open();
}
With this code, dialog is always null, although I can find those dialogs, correctly id-ied, in the DOM tree.
You need to use Polymers DOM API with shady DOM (default). If you enable shadow DOM your code would probably work as well.
PaperDialog infos = new Polymer.dom(this).querySelector("#dialog")

Determining the type of a standard jQueryUI widget

I am having trouble determining the type of a given jQueryUI widget instance.
The jQueryUI documentation for the Widget Factory suggests two techniques. From the "Instance" section:
The widget's instance can be retrieved from a given element using the
instance() method. [...]
If the instance() method is called on an element that is not
associated with the widget, undefined is returned.
the :data selector can also determine whether an element has a given
widget bound to it.
Based on their examples, let's say I initialize a datepicker and later code checks if it is a datepicker:
<p>Date: <input type="text" id="datepicker"> </p>
$(function() {
$("#datepicker").datepicker();
// ...
var i = $("#datepicker").progressbar("instance"); // i is undefined as expected
console.log(i);
var b = $("#datepicker").is(":data('ui-datepicker')"); // b = false, not sure why
console.log(b);
var i2 = $("#datepicker").datepicker("instance"); // this throws an exception
console.log(i2);
});
Based on the documentation I expected the .is call to return true, and the last line to return the instance (not throw an exception.)
JSFiddle is here. (You will need to open the browser's console to see the logged output.)
It turns out the techniques I listed above do work for many jQueryUI widgets, e.g. button, progressbar.
But datepicker is kind of weird. Looking at the DOM after a datepicker is initialized, I see the datepicker is inserted as a new element after the named element.
To get the datepicker widget instance I'd need to navigate the DOM starting from the named element. To check if the input field has a datepicker on it we can simply check the element for the class hasDatepicker:
var isDatePicker = $("#datepicker").is(".hasDatepicker");
This works with jQueryUI 1.11.2, and based on other SO questions it's been working since 2009. So I guess it's a reliable technique, but I'm not sure if its documented anywhere, or guaranteed for future versions.

How to remove "on-click" from a custom Polymer component

I have a custom button component done in Polymer Dart:
<div id="buttonDiv">
<my-button id="traceButton"
mode="icon" faicon="fa-comment-o"
toolTip="Print a simple comment"
disabled="false" on-click="{{ traceSomething }}">
</my-button>
</div>
I'm trying to copy/paste this button somewhere else. So a user defines it somwhere, and I basically move it by way of getting $['buttonDiv'].children then inserting it somewhere else. The problem is that {{ traceSomething }} is now irrelevant since it's not part of the new parent. I get errors saying that the parent object, which is another polymer component doesn't have an instance getter "traceSomething".
My question is, is there a way to remove "traceSomething" before I insert it somwhere else? I tried removing the "onClick" event listeners, but the buttons still wants to call that function upon click. Also, I've tried adding a preventDefault, etc, like in: In Dart, if I listen to a click event with two listeners, how do I know which happens first?
But, no luck.
I'm not sure what you mean by copy/past. Do you clone the element, or do you just append it to some other elements children.
Anyway, I don't think you can remove the event listener if it was added declaratively. If you add it imperatively it is easy to remove and readd later.
import 'dart:async';
...
StreamSubscription subsc;
#override
attached() {
super.attached();
subscr = onClick.listen((e) => (this.parentNode as ShadowRoot).host.traceSomething(e));
}
#override
detached() {
super.detached();
if(subscr != null) {
subscr.cancel();
}
}
See also https://stackoverflow.com/a/22168745/217408 about accessing the parent of a Polymer element (for Dart Polymer <= 0.16.x)

How to pass "scrollTarget" to "core-list" / scrolling

sorry for my silly question.
I have a problem with the "core-list-dart" element. Appart from the fact that it does not create the "infite" elements when needed, it seems to populate the "content" initially. (I am sure it didn't do that earlier this year ;) and it worked as expected -> creating elements as you scroll down)
Seems to be broken in polymer/js too, or do I missunderstand anything about that: http://www.polymer-project.org/components/core-list/demo.html
Experimenting around with the core-list-dart, I stumbled upon scrollTarget which will have an Element as parameter:
How do I pass an Element to the core-list-dart? Are there any examples which do data-binding on other Elements?
Many thanks for now .. hope somebody can understand my problem :D
Working with Dart 1.6
and:
dependencies:
core_elements: ">=0.2.0 <0.3.0"
paper_elements: ">=0.1.0 <0.2.0"
polymer: ">=0.13.0 <0.14.0"
You can do that for example with
<core-list scrollTarget="{{$['id_of_other_element']}}">...</core-list>
in this case the element has to be in the same shadow DOM (same Polymer element) as the <core-list> and it must be statically available (not within <template if=...> or generated by <template repeat=... nor added imperatively.
Another variant is to create a field
<core-list scrollTarget="{{scrollTarget}}">...</core-list>
In the class of your Polymer element you need
#observable
Element scrollTarget;
attached() {
super.attached();
scrollTarget = shadowRoot.querySelector('...');
}

Resources