Polymer best practise for script in index.html - polymer

What is the best practice for linking a script to the index.html in polymer. I have a menu on in my index file and what to use dom-if to hide certain buttons depending on the users permission. That permission check uses ajax(iron-ajax). I am unsure how to link Polymer({}), to the index, as the index is not a custom element.

<template is="dom-bind" id="app">
<template is="dom-if" if="{{myProp}}">
</template>
</template>
<script>
var app = document.querySelector('#app');
app.myProp = true;
</script>

Related

How to access elements within dom-repeat in Polymer 3.0?

I have the following piece of code:
<dom-repeat id="template" items="{{chats}}">
<template>
<template is="dom-if" if="[[item.opened]]">
<section id$="msg-[[index]]"></section>
</template>
</template>
</dom-repeat>
How do can I access section with id=msg-3 and set scrollTop to 999 upon being rendered?
I know that in polymer 1 the best practice was to bind to on attached and wait on a dom-repeat event with a debouncer this no longer works in polymer 3, however.
If you know the index number you can access the element with ;
let el = this.shadowRoot.querySelector('#msg-'+<index>);
Remember, if item not rendered due to your filter with dom-if, you can not acces this element.
EDIT
In order to show on top of the selected item;
let screenPosition = el.getBoundingClientRect();
window.scrollTo(screenPosition);
Demo

dynamically edit template of iron-list

At first, i know, there are many questions about iron-list. But mostly about editing items and not whole template inside iron-list..
My code is really extremely complicated and posting it is pointless. I am working on data-tables which are using iron-list. I have element called diamond-listing and inside this diamond-listing i have iron-list.
You can image this like: Parent element define <template> with some content inside it, and child element (diamond-listing) will render this template as a table
Of course diamond-listing is used multiple times in my application and always with different template. For example: page users have columns with userID, userName etc.. and on page stations there are columns stationID, address etc.. with different number of columns. Every pagea has it's own <template> which i am trying to propagate to diamond-listing. For example:
<diamond-listing as="user" id="permissionsTable" type="pagination" pagination-items-per-page="6" header-data="{{headerData}}" address="/user/" loading="{{loading}}">
<div id="test" slot="content">
<template>
<div class="diamond-row" on-tap="_openUrl" info$="/user/[[user.id]]">
<diamond-item text="{{user.username}}"></diamond-item>
<diamond-item text="{{user.partner.name}}"></diamond-item>
</div>
</template>
</div>
</diamond-listing>
What i managed to do is to make it work in shadow dom using <slot> and simply rewrite <template> inside <iron-list>, but here we are.. For example using Firefox, which doesn't support webcomponents, there isn't <template> as a child of <iron-list> (because there is no shadow-dom) so there is no way how to update <template> and render iron-list.
What i tried:
1) Find template inside iron-list and use removeChild and appendChild functions.
var test = this.querySelector("#test template");
this.$$("#diamondList").removeChild(this.$$("#diamondList template"));
this.$$("#diamondList").appendChild(test);
Without success.
2) Define in HTML empty iron-list without any template inside it. And then in javascript add template dynamically. Without success. ( iron-list is crying it requires template)
3) Create dynamically iron-list using document.createElement
var test = this.querySelector("#test template");
var list = document.createElement("iron-list");
list.appendChild(test);
list.as = this.as;
list.items = [{"username":"test","partner":{"name":"Test partner","id":1}}];
list.id = "diamondList";
result: same as 2) ...
Is there a way, how to update template which is used to render all items in iron-list?
Or create iron-list with defined template inside JS ?
Or somehow do it with dom-repeat ? I won't have more than 10 items in listing, since it's fully pagination listing. ( this is propably simplest solution, but i don't know how to render <template> for every iteration
Here is one general answer, don't know if it will work for your case:
In Polymer, recommended way of manipulating the DOM is by manipulating the data, not by removeChild or appendChild.
For example,
if you have list of users as: var users_array = [....];
create the iron-list as:
<iron-list date="users_array">
<template>
...
<template>
</iron-list>
adding and removing elements in users_array will affect the iron-list
immediately.
Use a dom-if or use hidden inside the iron-list.
<iron-list items="[[items]]">
<template>
<template is="dom-if" if="[[item.isType1]]">
<!-- item1 -->
</template>
<template is="dom-if" if="[[item.isType2]]">
<!-- item2 -->
</template>
</template>
</iron-list>

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.

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

polymer not displaying html from import

I'm just getting started with building web-components with polymer, and was following the tutorial.
I'm just at the start, and am adding my component to my page via a script, but my html from my template isn't being displayed.
Here's what I've got so far.
document.addEventListener("DOMContentLoaded", function() {
if(!window.Polymer){
var poly = document.createElement('script');
poly.src = "http://cdnjs.cloudflare.com/ajax/libs/polymer/0.3.4/platform.js";
document.head.appendChild(poly);
}
var template = document.createElement('link');
template.setAttribute("rel", "import");
template.setAttribute("href", "http://localhost:8081/first-widget.html");
document.body.appendChild(template);
var widget = document.createElement('my-widget');
document.body.appendChild(widget);
setTimeout(function(){
Polymer('my-widget');
},1000);
});
My widget is
<polymer-element name="my-widget">
<template>
<h1>This is from the Polymer</h1>
</template>
</polymer-element>
My understanding is that this should display the content of my html from the template in my my-widget tag. I've got the localhost:8081 serving the content of the template via CORS, so that isn't the issue, and I can see the template loaded into chrome via the element inspector. So I'm not sure why I'm not getting my content.
Is there a way I need to bootstrap polymer?
In your widget, you need to import polymer.html and either use the noscript attribute:
<link rel="import" href="path/to/polymer.html">
<polymer-element name="my-widget" noscript>
<template>
<h1>This is from the Polymer</h1>
</template>
</polymer-element>
or register your element:
<link rel="import" href="path/to/polymer.html">
<polymer-element name="my-widget">
<template>
<h1>This is from the Polymer</h1>
</template>
<script>
Polymer({});
</script>
</polymer-element>
More information on creating elements: http://www.polymer-project.org/docs/start/creatingelements.html
You'll need to run your html into a server.
I'm using http-server that is very simple.
npm install http-server
Basically you navigate through to index.html file and run "http-server".
Hope it helps
It turns out I was including the platform.js but not polymer.js
If anybody is loading polymer dynamically as I am (as we're building a widget which other people can include in their page), it seems it is best to use the noscript attribute as #pikanezi described, as you don't run into timing issues this way.