In Polymer, why use `<input is="iron-input">` instead of `<iron-input>`? - html

In the Polymer document (https://elements.polymer-project.org/elements/iron-input), I found:
<input is="iron-input" bind-value="{{myValue}}">
And in another official document (https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html#type-extension) , I found:
<dom-module id="main-document-element">
<template>
<p>
Hi! I'm a Polymer element that was defined in the
main document!
</p>
</template>
<script>
HTMLImports.whenReady(function () {
Polymer({
is: 'main-document-element'
});
});
</script>
</dom-module>
<main-document-element></main-document-element>
I was just wondering why the first one <input is="iron-input" bind-value="{{myValue}}"> can't be written as <iron-input bind-value="{{myValue}}">.
Is it for compatibility, which makes it easier to polyfill?

The iron-input element does not contain any HTML in its source code. This means that doing:
<iron-input bind-value="{{myValue}}">
will not produce an actual input on the page for the user to interact with. The iron-input element is really a collection of behaviours that you can apply to a standard HTML input.

Related

Polymer Component not independent from each other?

Given this simplified component:
<dom-module id="poly-component">
<template>
<paper-button raised onclick="dialog.open()">Button</paper-button>
<paper-dialog id="dialog"><h1>Paper Dialog Here!</h1></paper-dialog>
</template>
<script>
Polymer({
is: 'poly-component'
})
</script>
which does nothing more than open the dialog on clicking the button.
This module works when it used once on a page.
But when it is inserted twice
[...]
<dom-module id="polyTest-app">
<template>
<h2>Hello [[prop1]]</h2>
<poly-component></poly-component>
<poly-component></poly-component>
</template>
[...]
it doesn't work anymore.
A click on the button leads to a:
(index):1 Uncaught TypeError: dialog.open is not a function
Am I missing something?
The code for this example can be found here: Example Code on GitHub
Your code cannot work because you're not binding the event handler correctly.
A built-in handler like onclick tries to execute the bit of code in global scope where dialog doesn't exist. Hence the error.
Here's how you can rewrite your code
<dom-module id="poly-component">
<template>
<paper-button raised on-click="_dialogOpen">Button</paper-button>
<paper-dialog id="dialog"><h1>Paper Dialog Here!</h1></paper-dialog>
</template>
<script>
Polymer({
is: 'poly-component',
_dialogOpen: function() {
this.$.dialog.open();
}
})
</script>
</dom-module>
First, notice how onclick changes to on-click - the Polymer event handling notation. PS. tap event is advised.
Second, you can only access other elements from code. Not directly in bindings. Hence the _dialogOpen function.
UPDATE
Ok, I know what's happening. When there is only one element with a given id, the browsers let's you use it simply by that id in global scope.
When you use Shady DOM, which I assume you do, two instances of your poly-component element render two <dialog id="dialog">. At this point window.dialog is not available anymore.
Again, with Polymer it's safer to use the this.$ notation aka Automatic node finding to reference elements in local DOM.

Call Method of Child Web Component

I'm really having difficulty trying to figure out how to call a function of a nested Polymer web component.
Here's the markup:
<rise-playlist>
<rise-playlist-item duration="5">
<rise-distribution distribution='[{"id":"VGZUDDWYAZHY"}]'></rise-distribution>
</rise-playlist-item>
</rise-playlist>
The rise-distribution component has a canPlay function that I would like to call from inside of rise-playlist.
The dom-module definition of rise-playlist looks like this:
<dom-module id="rise-playlist">
<template>
<content id="items" select="rise-playlist-item"></content>
</template>
</dom-module>
I can successfully access the rise-distribution element like this:
var distribution = Polymer.dom(this.$.items[0]).querySelector("rise-distribution");
However, when I try to call distribution.canPlay(), it says that distribution.canPlay is not a function.
I've defined the dom-module of rise-playlist-item like this:
<dom-module id="rise-playlist-item">
<content id="dist" select="rise-distribution"></content>
</dom-module>
Not sure if I need that <content> tag, although neither works.
Any ideas?
Thx.
I know that there have been a while but I am sure this problems still occurs as it is being viewed number of times.
Probably there is a problem with your component definition. Let me explain.
This is the way you put your child component inside DOM:
<your-child-component></your-child-component>
And and this should be the definition of your component:
Polymer({
is: 'your-child-component',
apiMethod: function() {
//some stuff
}
});
If you by mistake or due copy-paste error mistype the is: 'your-child-component' part, so it will not reflect the <your-child-component> you will get confused becouse your:
this.$$('your-child-component').apiMethod();
will tell you that there is no method you are willing to call.
Polymer correctly identified and selected from DOM <your-child-component> but if you have different is property (like for example is: your_child_component>) it will not attach its API to dom element you selected.
I hope that it will help if anyone ever will encounter this problem.

How do I listen to events for elements in Polymer 1.0?

I want to use Polymer's UI elements (e.g., iron-icons, paper-button, etc.) without making custom elements or templates.
For example, let's say I have:
<paper-button id="my-button">Click me</paper-button>
How do I listen for the 'click' event? Simply adding an event listener to 'click' for the ID 'my-button' doesn't work.
It should just work? I'm assuming you want to use Polymer UI elements in the main doc (index.html) without having to create any custom components. Say you have
<paper-button id="btn">Click me</paper-button>
in index.html. Via vanilla js,
document.querySelector("#btn").addEventListener("click", function (e) {...});
and via jQuery,
$("#btn").on("click", function (e, u) {...});
p/s: I'd write a quick jsbin as a demo, but rawgit seems to be having issues, and I'm not aware of alternative CDNs that host Polymer Elements.
Let me be clear: Polymer elements, and by extension web components, are designed to be framework-agnostic and, if properly coded, will work on their own - just like any other HTML element. Please do not dom-bind for the sake of dom-binding. You only do so if you a) require Polymer's sugaring (like data-binding) in your use-case; and b) you want to use Polymer's sugaring from your index.html - if you don't, please don't add additional complexity to your app.
I've found a cdn serving polymer elements, so:
Look, no dom-bind and elements are working with vanilla js.
Look, no dom-bind and elements are working with jQuery.
You can try:
<template is="dom-bind" id="t">
<paper-button id="my-button" on-click="buttonClicked">Click me</paper-button>
</template>
<script>
var template = document.querySelector('#t');
template.buttonClicked= function () {
alert("he clicked me :)");
};
</script>
$( "body" ).delegate( "#my-button", "click", function() {
alert();
});

How can I rewrite the native HTML input element with Polymer?

I want to rewrite the <input type="number"> element with Polymer so that i can <input is="number-input"> and style it in a way so that it looks and behaves the same on different browsers.
This is where I'm at now:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="number-input" extends="input" attributes="value">
<script>
Polymer('number-input', {
valueChanged: function(){
console.log(this.value)
}
});
</script>
</polymer-element>
... and using it by <input is="number-input">, but it doesn't fire the valueChanged function.
What am I doin wrong?
Teltrik did a recent article on styling inputs with shadow dom that was pretty interesting: http://developer.telerik.com/featured/comprehensive-guide-styling-file-inputs/
In your case, you're doing everything correctly. The problem however, is that input already has a .value property. You're trying to override the native property which creates unpredictable behavior. The second issues is that Object.observe() cannot observe native properties on elements. For example, if you added the hidden attribute, hiddenChanged would never be called. Likewise for title and titleChanged.

Polymer document.querySelector not working as expected

Either I am doing something horribly wrong or Polymer just doesn't like me. See following:
<polymer-element name="menu-paper-ui" noscript>
<template>
<paper-dialog heading="Dialog" transition="paper-dialog-transition-bottom">
[ .. ]
</paper-dialog>
<paper-button label="Dialog Bottom" on-tap="{{toggleDialog}}"></paper-button>
</template>
<script>
Polymer('menu-paper-ui', {
toggleDialog : function() {
var dialog = document.querySelector('paper-dialog');
console.log(dialog); //returns null
dialog.toggle();
}
})
</script>
</polymer-element>
Now, I have my reasons to use querySelector. So, if someone can tell me whats going wrong that will be great!
This question is nearly identical to Using querySelector to find nested elements inside a Polymer template returns null.
The short answer is that elements in a polymer-element's template are put into the ShadowDOM of that element, are not not visible to the anything outside of that element. This is so that you can control styling more easily, and element IDs are scoped.
You can either give the dialog an id and use Polymer's automatic node finding, or use this.shadowRoot.querySelector('paper-dialog').
The Problem is that you can not access the shadow DOM inside a custom element with document.querySelector. See my answer to a similar question.