I am creating a (my first!) AngularDart app. I have a List of objects of a class Procedure in a procedure_list_component.dart component (modeled after the sample ToDo app's list component). This is displayed in a MaterialListComponent and it all works fine.
I am using Dart SDK 2.1.0 and AngularDart ^5.2.0.
Now I want to develop a new component to display the details of the selected Procedure. The selection part works fine. My detail component currently looks like this:
#Component(
selector: 'procedure-item',
templateUrl: '''
<div>
{{procedure.packageName}}.{{procedure.name}}
</div>
''',
directives: [
],
)
class ProcedureItemComponent {
#Input()
Procedure procedure;
}
The component's usage looks like this:
<div *ngIf="selectedProcedure != null">
<procedure-item procedure="{{selectedProcedure}}"></procedure-item>
</div>
However, at run time I receive the error:
EXCEPTION: Type 'String' is not a subtype of expected type 'Procedure'.
STACKTRACE:
dart:sdk_internal 4000:19 check_C
package:tadpole/src/procedure_list/procedure_list_component.template.dart 345:44 detectChangesInternal
package:angular/src/core/linker/app_view.dart 404:7 detectCrash
package:angular/src/core/linker/app_view.dart 381:7 detectChanges
package:angular/src/core/linker/view_container.dart 64:21 detectChangesInNestedViews
package:tadpole/src/procedure_list/procedure_list_component.template.dart 136:13 detectChangesInternal
package:angular/src/core/linker/app_view.dart 404:7 detectCrash
package:angular/src/core/linker/app_view.dart 381:7 detectChanges
....many more lines
This error makes me suspect that passing a complex object between components is not supported, or there is some magic syntax for passing them.
I have tried using just "selectedProcedure" and {{selectedProcedure}} which result in compiler errors. Which then makes me think that complex objects are supported in this case.
Yes, my confusion is real.
Looking through the docs I cannot find any mention of whether or not this is possible. Every example I can find simply sends Strings, but never states specifically that only Strings are supported.
Is this really not supported? If it is, what am I doing wrong?
To pass inputs to a component, you only need to use square brackets around the input name. If you leave them off, Angular attempts to set the input as a String, which doesn't work since it is defined as taking a Procedure.
<div *ngIf="selectedProcedure != null">
<procedure-item [procedure]="selectedProcedure"></procedure-item>
</div>
Related
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.
[Dart+Polymer]
Hello,
I have PaperInput elements in a Polymer dom-repeat template. So, there are several, so on the #Listen I try to get the id, but it only retrieves id="labelAndInputContainer" (no matter what I do in the template).
Is there some trick to this? I've tried "everything" - over the past half a day!
Here is my HTML:
<template is="dom-repeat" items={{rgetThem}}>
<paper-card heading={{yyyy(item)}} >
<div class="card-content" >
<p style="color:red">ID:{{getID(item)}}</p>
<paper-input on-change="onchangepassword"
label='Password'
id={{getID(item)}}
floatingLabel>
</paper-input>
</div>
And the listener:
#Listen ('onchangepassword')
void onchangepassword(Event custEvent, var t) {
IronInput PI=custEvent.target;
Element yy=PI.parent;
String id=yy.id;
}
Any suggestions MOST welcome.
Thanks
Steve
You could try
Element yy=PI.parent.closest('paper-input');
The problem you're facing is paper-element encapsulates an iron-input element wrapped in div elements. Finding the closest paper-input will find the paper-input which the iron-input is encapsulated in, since that's the nearest one. I'm sure there are other ways to do it, but this works for me. In fact you could just do
Element yy=PI.closest('paper-input');
which will work just as well.
UPDATE:
Upon seeing the comment about dom-repeat event models, it occurs to me you may want a more Polymer Dart specific documentation link.
https://github.com/dart-lang/polymer-dart/wiki/data-binding-helper-elements#handling-events-in-dom-repeat-templates
As was suggested
model.item.id
And I'm not going to take credit for the updated part of my answer except the Dart specific link.
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")
app_element.dart
library attribute_binding.app_element;
import 'package:angular2/angular2.dart';
import 'package:attribute_binding/app_element.dart';
#Component(selector: 'app-element', templateUrl: 'app_element.html')
class AppElement {
#Input() String attr2 = 'foo';
}
app_element.html
<h2>app-element</h2>
<div my-attr="attr1">attr1</div>
<div [my-attr]="attr2">attr2 {{attr2}}</div>
so that both <div> get a green background color?
With the code above only the first <div> gets a green background.
If you want to bind to an attribute instead of a property of the element, you must use the form [attr.my-attribute]="expression".
For more info about it you can see the official cheatsheet and Template syntax - Attribute, Class, and Style Bindings from the official doc as well.
Regarding your finding, that seems to be from an old PR (15 July) and see that it's not being even exported, and most important you can't find that const anymore in the latest master (see dom_renderer).
Glad it helped.
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'].