We have a custom element that is making an AJAX call to fetch some html generated on the server side and then injected into its light dom via Polymer.dom(this).innerHTML. The response coming from the server has another custom element in it that exposes a CSS property for theming purposes. On the main page, we're setting the value for the property, but it doesn't appear to be working. How do we get Polymer to style dynamically added light DOM elements that are distributed by another element.
index.html
<style is="custom-style">
x-bar {
--mixin-property: {
background: red;
};
}
</style>
...
<body>
<x-baz>
</x-baz>
</body>
x-baz.html
<dom-module id="x-baz">
<template>
<x-foo></x-foo>
</template>
</dom-module>
<script>
Polymer({
is: "x-baz"
});
</script>
x-foo.html
<dom-module id="x-foo">
<template>
<iron-ajax auto url="..." last-response="{{response}}"></iron-ajax>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: "x-foo",
properties: {
response: {
type: String,
obeserver: 'responseChanged'
}
},
responseChanged: function(newVal)
Polymer.dom(this).innerHTML = newVal;
}
});
</script>
x-bar.html
<dom-module id="x-bar">
<style>
.elementToStyle {
#apply(--mixin-property);
}
</style>
<template>
<div class="elementToStyle">
...
</div>
</template>
</dom-module>
</script>
Polymer({
is: "x-bar"
});
</script>
The iron-ajax call returns <x-bar> ... </x-bar>.
I would expect the div inside the x-bar that comes back from the AJAX response to have a red background, but it doesn't seem to be working. What do we need to adjust to make this work correctly?
Thanks in advance!
Related
I have a set of Polymer 1.x components which act as fillable forms. Each form can be called via <form-one></form-one>, <form-two></form-two> etc...
<dom-module id="form-one">
<template>
form content
</template>
</dom-module>
<script>
Polymer({
is: "form-one"
});
</script>
I'm looking for a solution to combine them and to have only one element and call the forms like:
<form-handler form="form-one"></form-handler>
Where to start? And is it also possible to keep the dom modules in separated files?
Thanks in advance.
You can have your element like this:
<dom-module id="form-handler">
<template>
<div id="formContainer">
</template>
</dom-module>
<script>
Polymer({
is: "form-handler",
properties:{
form: {type:String, observer:'_formChanged'}
},
_formChanged: function(){
var formElement = document.createElement(this.form);
this.$.formContainer.empty();
this.$.formContainer.append(formElement);
}
});
</script>
Considering defining a polymer element
<dom-module id="custom-element">
<template>
<h1>I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
},
ready: function() {
this.style.color = this.color;
}
});
</script>
</dom-module>
I would expect that the following two would produce the same result:
(in markup)
<body>
<custom-element color="green"></custom-element>
</body>
(in JS)
var customElement = document.createElement('custom-element');
customElement.color = 'green';
document.body.appendChild(customElement);
But in fact it doesn't, as it seems that the properties are set and the polymer 'ready' function is triggered before the customElement is appended to document.body.
So basically I cannot dynamically create (in JS) custom elements and set them initial properties, different than the default properties.
How would you suggest I should do that?
Thanks!
Set the color in attached callback instead of ready. Attached is called after the element has been appended in dom.
<base href="https://polygit.org/components/">
<script src="wecomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<dom-module id="custom-element">
<template>
<h1>I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
},
attached: function() {
this.style.color = this.color;
}
});
</script>
</dom-module>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var customElement = document.createElement('custom-element');
customElement.color = 'green';
document.body.appendChild(customElement);
</script>
</body>
</html>
In your case, I would avoid altering the DOM and use a simple attribute binding.
Here is a proof of concept: http://jsbin.com/jozejemumu/1/edit?html,js,output
As you can see, I used attribute binding for the style attribute on the h1 element, which simply sets the CSS color property to whatever the value of the elements' color property is.
The code is faily simple, and looks like this:
<dom-module id="custom-element">
<template>
<h1 style$="color: [[color]];">I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
}
});
</script>
</dom-module>
Using the element remains unchanged:
<custom-element color="green"></custom-element>
Or:
var customElement = document.createElement('custom-element');
customElement.color = 'orange';
document.body.appendChild(customElement);
Just make sure that the color property contains a valid HTML color name/value.
Having trouble getting my data to work across elements. Say I have an object "records" in my host element. It is usable in that element no problem. But when I try to spin off the view into a separate element, it no longer works.
Here's an example snippet of code. The .template part works fine but I'm not able to replicate the functionality in the child element .my-list. When I try, nothing happens.
<dom-module id="host-element">
...
<template is="dom-repeat" items="{{records}}">
<p>{{item.userName}} - {{item.number}}</p>
</template>
<my-list></my-list>
<script>
Polymer({
is: 'host-element',
ready: function() {
this.records = [
{userName: 'Bob'},
{userName: 'Sally'}
];
}
});
</script>
</dom-module>
If I try simply taking the current .template code and placing it into .my-list, it doesn't work.
I assume I need someway to bind the data into the child element, but I'm not able to figure this out. Adding a: record="{{records}}" to the tag, and then using that in the child element didn't work.
Imagine this is pretty simple, just can't find the answer in the documentation.
It's important that each element's top-level template is a plain template (not is="dom-repeat" or other specialization), otherwise, it should be straightforward:
<link rel="import" href="//polygit.org/components/polymer/polymer.html">
<i>(Requires Chrome)</i>
<host-element></host-element>
<dom-module id="my-list">
<template>
<template is="dom-repeat" items="{{records}}">
<p>{{item.userName}} - {{item.number}}</p>
</template>
</template>
<script>
Polymer({
is: 'my-list'
});
</script>
</dom-module>
<dom-module id="host-element">
<template>
<my-list records="{{records}}"></my-list>
</template>
<script>
Polymer({
is: 'host-element',
ready: function() {
this.records = [{userName: 'Bob'}, {userName: 'Sally'}];
}
});
</script>
</dom-module>
The below code does not show in the browser. This works in Polymer 0.5. Is there code difference as I am using 1.0?:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="my-name">
<template>
<h1> Hello {{name}}</h1>
</template>
<script>
Polymer('my-name', {
ready: function() {
this.name = "Brown";
}
});
</script>
</polymer-element>
Basically you need to rewrite your element based on the new requirements. You can easily follow it in the migration guide, registration element section.
You should rewrite it like following:
<dom-module id="my-name">
<template>
<!--Keep in mind in polymer 1.0 you can't have whitespaces in bound tags-->
<h1>Hello <span>{{name}}</span></h1>
</template>
<script>
Polymer({
is: "my-name",
ready: function () {
this.name = "Brown";
}
});
</script>
</dom-module>
I did a Plunker where you can reproduce it.
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="my-name">
<style>
/*your styles go here*/
<style>
<template>
<!-- Things to show in element view -->
<h1> Hello <span>{{name}}</span></h1>
</template>
<dom-module>
<script>
// Your script goes here
Polymer({
is: 'my-name',
properties: {
name: {
type: String,
value: 'Brown'
}
}
});
</script>
There are many differences when migrating from Polymer 0.5 to Polymer 1.0 +. They changed the old polymer-element to dom-module and name attribute to id. The constructor is also changed as i shown in the example. Read https://www.polymer-project.org/1.0/docs/migration.html to get more info on migrating.
polymer 1.0 changes <polymer-element name="my-name"> to <dom-module id="my-name">.
I think you should follow the documentation of polymer 1.0
Polymer 1.0 documentation
i want to inject a template into an polymer component like this :
<polymer-element name="foo-bar">
<template>
<content></content>
<!-- content is expected to contain a template with id="layout"-->
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
usage of the component :
<foo-bar>
<template id="layout">another content template</template>
</foo-bar>
unfortunately the template provided as content of the element is not taken over for some reason.
when simluate the wished behaviour using
<polymer-element name="foo-bar">
<template>
<template id="layout">
custom content template
</template>
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
the referenced template(id="layout") is used as expected.
Any help is appreciated :-)
<template ref="layout"> says use the template#layout for my content. So I would expect the template in your shadow dom to use the content of the light dom template. This is what you see in http://jsbin.com/takipi/1/edit.
However, if you want to use render the light dom <template> the user provides, you must activate it using template.createInstance(). By default, templates are inert. For this use case, you also don't need <content>. That's for rendering and in this case, it doesn't really make sense.
The example below also show how to set things up. It also shows how you can use {{}} bindings in the light dom <template> and fill them when the instance is created.
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
attached: function() {
var template = this.querySelector('template');
if (template) {
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
Full code:
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="foo-bar">
<template>
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
</template>
<script>
Polymer({
showDefault: true,
attached: function() {
var template = this.querySelector('template');
if (template) {
// Allow Polymer expressions in the template's {{}}.
if (!template.bindingDelegate) {
template.bindingDelegate = this.element.syntax;
}
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
});
</script>
</polymer-element>
<foo-bar>
<template>
<b>another</b> content template. Also supports data: {{foo}}
</template>
</foo-bar>