Polymer 1.0 add other polymer elements inside - javascript

Hello what is the difference of doing adding a child polymer element like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
<test-element></test-element>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element></app-element>
This works just fine.
The effect of adding html code (including other polymer elements) inside the app-element tag
<app-element>some html here</app-element>
like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element>
<test-element></test-element>
</app-element>
This ignores the test-element code. So in which cases can I add html code inside a polymer element? When will it be ignored? What would be the case where you want to add polymer elements inside other polymer elements inside the html code like this:
<app-element>
<test-element></test-element>
</app-element>
?? Thank you

In your first case you are using local dom, in the second light dom.
In local dom, the custom element that contains it is responsible for the content (in this case app-element). So the creator of the custom element decides the content of the local dom. In contrast, using light dom provides the user of the custom element with the option to specify the content. The creator of the custom element can specify where the light dom should go inside the custom element using the <content></content> tag. So to make your second example work you would need something like this:
<dom-module id="app-element">
<template>
<h1>Hello</h1>
<content></content>
</template>
<script>
Polymer({
is: "app-element"
});
</script>
</dom-module>
<app-element>
<test-element></test-element>
</app-element>
An example use case for light dom is the paper-dialog. Using light dom, the user of the dialog can decide the content of the dialog. For example, the specific buttons to use, the main content of the dialog, etc.
Have a look at this page in the documentation for more information on local and light dom.

Related

How to dynamically populate iron-list elements

So I have an iron-list element for a user's data history. The iron-list is not part of a custom element. It is simply on the page. I want to populate once the user has successfully logged in. Perhaps it is just my inexperience with polymer, but there doesn't seem to be a straightforward way to do this. First attempt (simplified for reading, e.g. I don't actually use jquery, there's lots of error-handling code I'm omitting, etc):
<iron-list as="item" style='height: 100%;' id='history-list'>
<template>
<div style='min-height: 140px;'>
<ul>
<!-- various fields for each record as list items -->
</ul>
</div>
</template>
</iron-list>
<script>
//once user is logged in
var items = $.getJSON('userhistoryscript');
//setAttribute doesn't work either
document.getElementById('history-list').items = items;
</script>
I would swear this worked in an earlier version of Polymer. But it doesn't seem to work now, which is fine, but I need an alternative.
Some alternatives I've considered:
Have iron-ajax element in same DOM scope and set '
the URL once the user is logged in to trigger the
xhr request. I'm not sure whether or not that'd work.
Wrap the list in a custom element and use an
iron-meta-query per chrisW's answer.
Those options are terrible. I cannot believe there is no simpler way to accomplish this feat. How do I conditionally fetch data based on user input and dynamically add an iron-list to the page (or update one that's already there)? Is there really no API for this use case?
UPDATE
Thank you for your answers. Turns out that my original code actually works fine: it was actually a build process issue. For some reason iron-list did not get installed when I installed the project dependencies through bower. I took out the vulcanized import (which must not have contained a ref to iron-list either) and imported all the elements directly, then I got the 404 and figured out what had happened.
I think that for best practices, you should use this.$.historyList to refeer id on this element. Anyway, when you get data to populate iron-listyou should use this.set('items', data); An example using your element looks like:
<iron-list>
<template is="dom-repeat" items="{{data}}" as="history">
<!--history.property-->
</template>
</iron-list>
<script>
Polymer({
properties:{
data:{type:Array, value:[],}
},
_functionToSetDataWhenUserIsLoggedIn: function(data){
this.set('data',data);
}
});
</script>
Edit
An example of iron-list
<template is="dom-bind">
<iron-ajax url="data.json" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div>
Name: <span>[[item.name]]</span>
</div>
</template>
</iron-list>
</template>
This example is using an ajax call that executes automatically and populates the iron-listwithout the need to create a customized element.
More about iron-list on:
https://elements.polymer-project.org/elements/iron-list
I didn't entirely understand your question. Hope this helps.
<iron-list items="[[data]]" as="item">
<template>
<div>
Name: <span>[[item.name]]</span>
</div>
</template>
</iron-list>
properties:{
data:{type:Array, value:[],}
},
// the attached function is automatically called
attached: function() {
// Use an iron meta in the element that you keep track in of login information
// or create an onLogin listener
var isLoggedIn = new Polymer.IronMetaQuery({key: 'isLoggedIn'}).value,
if (isLoggedIn) {
var jsonData = $.getJSON('userhistoryscript');
this.set('data',jsonData);
}
}
Side note, when access elements by ids in Polymer elements, make sure you do it this way:
this.$.elementId
or
Polymer.dom('#elementId')
Edit since you don't want to create a custom polymer element
Source Code
<template is="dom-bind">
<iron-list id="list">
</iron-list>
</template>
<script>
document.addEventListener('onLogin', function(event) {
var list = document.getElementById('#list');
var jsonDataObjects = $.getJSON('userhistoryscript');
for (var i = 0; i < jsonDataObjects.length; i++) {
var div = document.createElement('div');
div.textContent = jsonDataObjects[i].info; // change this line
list.appendChild(div);
}
});
</script>

Routing in polymer 1.0

I am new to web development and building an application using polymer 1.0.4. I am using the page.js routing similar to the example in start kit. Now many of the custom element that I built are using ajax and periodically refresh the data. The problem with page.js routing that It seems it loads all custom elements even if the element is not viewed by user. so all custom elements are loading the data even if it is not needed. my questions:
1- How could I fix this so the the elements load data only when they are viewed by the end users? Should I change the routing to another options like more-routing?
2- if the user filled the data in one custom element , then clicked on link to another element. The data will remains when the user goes back to the first custom element? How could I reset the polymer and html elements in the custom element when the use back to an old view?
Again, I'd recommend https://github.com/PolymerLabs/more-routing Eventually a 'carbon' (if I recall the name correctly) set of components will deal with this, according to the polymer summit videos, but until then this seems the standard approach.
Set up the pages via:
<more-routing-config driver="hash"></more-routing-config>
<more-route name="one" path="/one"></more-route>
<more-route path="/two">
<more-route name="two" path="/:name"></more-route>
</more-route>
Then the menu via:
<more-route-selector>
<paper-menu selected="0">
<paper-item route="{{urlFor('one')}}">One</paper-item>
<paper-item route="{{urlFor('two', {name: 'sup'})}}">Two</paper-item>
</paper-menu>
</more-route-selector>
And then the actual pages via:
<more-route-selector selectedParams="{{params}}">
<iron-pages selected="0">
<section route="one">
<div> Page one </div>
</section>
<section route="two">
<div> Page two: {{params.name}} </div>
</section>
</iron-pages>
</more-route-selector>
I used it when it was under the Polymore repository on github, and the samples above are from such, but it doesn't seem to have changed that much in its new home.
After you've set up the basics, listen for changes on the iron-pages, such as events that are available here. In such listeners, you can load the data for each section in iron-pages. One approach would be to use such listeners to call a method of a custom element, perhaps using a behaviour, that then brings down the data.
Try dna-router. You can create define states and routes in HTML only.
Setup routes by:
<dna-new-state state='home' route='/home'></dna-new-state>
<dna-new-state state='user' route='/user/:id/'></dna-new-state>
Create views by:
<dna-view
state='home'
element='home-template'></dna-view>
You can get all params inside your home-template polymer properties.
var params = this.params
For a detailed documentation, visit : https://github.com/Saquib764/dna-router
Firstly, the PolymerLabs/more-routing library is a nice alternative to page.js and is quite easy to implement. As this library is more declarative you can do things like:
routes.html
<more-routing-config driver="hash"></more-routing-config>
<more-route name="myRoute" path="/my-route-path/:id"></more-route>
app-element.html
<dom-module id="app-element">
<style>
iron-selector > * {
display: none;
}
iron-selector > .iron-selected {
display: block;
}
</style>
<template>
<more-route-selector>
<iron-selector>
<x-element></x-element>
</iron-selector>
</more-route-selector>
</template>
<script>Polymer({ ... });</script>
</dom-module>
x-element.html
<dom-module id="x-element">
<template>
<more-route id="route" context name="myRoute" params="{{params}}" active="{{activeRoute}}"></more-route>
</template>
<script>
Polymer({
is: 'x-element',
observers: [ '_paramsChanged(activeRoute, params.id)' ],
_paramsChanged: function(activeRoute) {
if (activeRoute) {
// Active route
} else {
// Inactive route
}
}
})
</script>
</dom-module>
Check out the polyfora app in the demo folder of the repository.
Otherwise, to use page.js I would consider:
Remove any auto iron-ajax queries in custom elements;
Pass a state attribute to custom elements;
Add an observer to any state changes within each custom element which triggers a function to run any iron-ajax queries.
As of Polymer 1.4, carbon-route (later renamed app-route) can be used:
https://github.com/polymerelements/carbon-route
https://blog.polymer-project.org/announcements/2016/03/28/carbon-route-released/
https://www.polymer-project.org/1.0/articles/routing.html
Here's an example taken from the polymer blog:
<carbon-location route="{{route}}">
</carbon-location>
<carbon-route route="{{route}}" pattern="/tabs/:tabName" data="{{data}}">
</carbon-route>
<paper-tabs selected="{{data.tabName}}" attr-for-selected="key">
<paper-tab key="foo">Foo</paper-tab>
<paper-tab key="bar">Bar</paper-tab>
<paper-tab key="baz">Baz!</paper-tab>
</paper-tabs>
<neon-animated-pages selected="{{data.tabName}}"
attr-for-selected="key"
entry-animation="slide-from-left-animation"
exit-animation="slide-right-animation">
<neon-animatable key="foo">Foo Page Here</neon-animatable>
<neon-animatable key="bar">Bar Page Goes Here</neon-animatable>
<neon-animatable key="baz">Baz Page, the Best One of the Three</neon-animatable>
</neon-animated-pages>
See also similar question: Polymer 1.0 - routing

How to create style scoping for arbitrary content with Polymer / Web Components

I am trying and failing to create a simple web component just for style scoping purposes.
The idea is that I would define a component - say <scoped-style> - which #imports a stylesheet so that any instance of <scoped-style> will scope the imported stylesheet for me. I just want to separate styles within elements and without.
So far I haven't even been able, using Polymer, to create a component which applies <style> based styles to the arbitrary content any instance might contain. It appears that content which goes in <content></content> can only be styled using
:host ::content [selector] {
/* shadowy styles */
}
This is extremely limiting and wrecks my #import plan too.
Here's the component definition so far:
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="scoped-style">
<style>
p {
background: red;
}
</style>
<template>
<div>
<p>Paragraph outside content (below) which _does_ go red</p>
<content></content>
</div>
</template>
<script>
Polymer({
is: "scoped-style"
});
</script>
</dom-module>
And here's the usage I intend:
<scoped-style>
<p>This paragraph should _also_ go red, but doesn't.</p>
</scoped-style>
Many thanks!
No, that’s right. On the Guide to Styling Elements it notes:
The distributed [element - <p>, in your case] remains [black] because it’s logically still in the parent page and therefore matching scoped-style > p. It’s simply being rendered elsewhere (over in Shadow DOM land).

sending json obj to polymer element

I have no idea why is this happening!
i want to send an object to polymer element and then use it.
im using something like this for the element
<polymer-element name="post-thumb" attributes="post">
<template>
<article>
<span>this is a post thumb</span>
<h1>{{post.title}}</h1>
<p>{{post.body}}</p>
</article>
</template>
<script>
Polymer('post-thumb');
</script>
</polymer-element>
and after HTML import, i'm calling it like this:
<post-thumb post='{"title":"post title 1","body":"post body"}'> </post-thumb>
it's weird cause when i use {{post}} it'll bring back the whole {"title":"post title 1","body":"post body"} but when i use {{post.title}} polymer simply returns nothing!
what's wrong here!? :/
I think you need to hint to the polymer that the attribute is of object type, ie try
<script>
Polymer('post-thumb', {
created: function() {
this.post = {};
}
}
);
</script>

Polymer - dynamic template rendering

is it somehow possible to render the template in a polymer element dynamically at runtime or when some light-dom elements are available?
I have the following situation:
index.html
<mega-menu>
<span class="menuTriggerText">Open Menu</span>
<ul class="test">
<li>TEST1</li>
<li>TEST2</li>
</ul>
<ul class="test">
<li>TEST1</li>
<li>TEST2</li>
</ul>
</mega-menu>
in my polymer-element.html i want to do something as follows:
<template>
<template repeat="{{temp}}"><p>I want to try this</template>
</template>
Polymer('mega-menu, {
created:function(){},
ready: function(){
//getting markup from light-dom
this.temp = document.getElementsByClassName('test');
},
attached:function(){},
detached: function(){},
attributeChanged: function(attrName, oldVal, newVal){}
});
Now, my question is - how do i get this to work? do i need to bind something on my template? or do i need some kind of event-listener or observer on something?
Thanks, Gbeschbacher
This is precisely what content insertion points are for. You can select top-level light DOM markup to render at specific locations in the Shadow DOM. <content select=""></content> takes a CSS selector and grabs nodes from the light DOM.
Your example would be:
<polymer-element name="mega-menu" noscript>
<template>
<content select=".test"></content>
</template>
</polymer-element>
You should not need to pry into the light DOM like this for such a simple case, but for the sake of completeness, we can get your example working with a few important tweaks:
document.getElementsByClassName('test') looks for nodes in the entire document. This is not what you want. You only want children of <mega-menu>. Instead of document use this (e.g. this.querySelectorAll('.test')).
You're giving <template repeat="{{temp}}"> a NodeList. It won't be able to stamp that out. It expects an Array. Something like this.temp = [].slice.call(this.querySelectorAll('.test')); would work.
http://jsbin.com/balodowi/2/edit

Categories

Resources