Iron-signal alternate in Polymer 2? - polymer

I have been using iron-signals almost everywhere in my application.
Now I was upgrading my polymer 1 application to polymer 2 and I found that <iron-signals> is not used anymore.
What is the alternate path to achieve the same. I basically want to pass data between different pages in my web app.

You should be able to simply dispatch events on window from one element and listen for them in other elements.
Example:
// Element 1
class FooElement extends Polymer.Element {
connectedCallback() {
super.connectedCallback()
}
ready() {
super.ready()
window.addEventListener('bar-was-called', e => {
console.log(e.detail) // logs 'hello-bar'
})
}
}
// Element 2
class BarElement extends Polymer.Element {
connectedCallback() {
super.connectedCallback()
}
ready() {
super.ready()
}
doBar() {
window.dispatchEvent(new CustomEvent('bar-was-called', {
detail: 'hello-bar'
}))
}
}
Side note
Keep in mind that iron-signals was removed for a reason. AFAIK it's that it promotes a hard-to-debug communications architecture.
From <iron-signals> README:
Note: avoid using iron-signals whenever you can use a controller (parent element) to mediate communication instead.

Iron Signals have been deprecated in polymer 1.
Replace uses of iron-signals with iron-meta.

Related

How to get inner content as a variable without rendering in LitElements

I am using my lit element like this
<my-header>MyHeading</my-header>
And I have my lit element's render method:
render() {
return html`
<h3><slot></slot></h3>
`;
}
which is working perfectly. Now I want the inner content i.e. "MyHeading" in my lit element's class as a value(not to render). Is there any way to get that innerHTML or as a text?
Note: my use case can be to set another property of rendered content like
render() {
return html`
<h3 id="${//How to get that 'MyHeading' here??}"><slot></slot></h3>
`;
}
Is it possible to get inner content as a value?
This is what you get when you learn new stuff starting with a Library or Framework;
You learn the Tool, not the Technology.
The child-elements of your customElement are not available yet
when the connectedCallback fires
so you wait till the EventLoop is empty (and thus know all children are parsed)
Or use any of the Library methods that (usually) fire even later than a setTimeout
Or, even more blunty, like many blogs show, execute the script that creates your Element
after the whole DOM is parsed by marking it a type="module" or async or defer
<script>
customElements.define("my-element", class extends HTMLElement {
constructor(){
super().attachShadow({mode:"open"}).innerHTML = `<h3><slot></slot></h3>`
}
connectedCallback() {
setTimeout(() => { // wait till innerHTML is parsed
let title = this.innerText;
console.log("Reflected from lightDOM:" , title);
this.shadowRoot.querySelector("h3").id = title;
})
}
})
</script>
<my-element>
Hello Web Components!
</my-element>

From Polymer3 to lit-element and material components: replacement for paper-tabs and iron-pages

I am porting a Polymer 3 app to lit-element stepwise and also want to replace the paper and iron elements by material web components. I very often am using the combination of paper-tabs and iron-pages to show property pages/dialogs.
What would be the replacement for paper-tabs/iron-pages in the material web components world?
I have found mwc-tab-bar but there is no example for actually displaying contents according to the selected tab.
Has anyone an example for how to build what sometimes is called a page-control (tabs plus contents)?
There are several options: (I would prefer 1 & 3)
You could just create a condition to render and eventually lazy load a certain page.
Use something like lion-steps (they also provide tabs)
Use a router like simple-wc-router
class MyElement extends LitElement {
static get properties() {
return {
page: String,
}
}
get _oneTemplate() {
return html`Page one`;
}
get _twoTemplate() {
return html`Page two`;
}
constructor() {
super();
this.page = 'one';
setTimeout(() => (this.page = 'two'), 5000);
}
render() {
return this.page === 'one' ? this._oneTemplate : this._twoTemplate;
}
}

how to force a Polymer.Element extended class to execute its lifecycle without attaching it to the dom?

Consider this element (minimal for the purpose of the question) :
class MyCountDown extends Polymer.Element
{
static get is () { return 'my-count-down'; }
static get properties ()
{
return {
time: { /* time in seconds */
type: Number,
observer: '_startCountDown'
},
remains: Number
}
}
_startCountDown ()
{
this.remains = this.time;
this.tickInterval = window.setInterval(() => {
this.remains--;
if (this.remains == 0) {
console.log('countdown!');
this._stopCountDown();
}
}, 1000);
}
_stopCountDown () {
if (this.tickInterval) {
window.clearInterval(this.tickInterval);
}
}
}
customElements.define(MyCountDown.is, MyCountDown);
If I get one instance and set the property time,
let MyCountDown = customElements.get('my-count-down');
let cd = new MyCountDown();
cd.time = 5;
the property time changes but the observer and the _startCountDown() function is not called. I believe Polymer is waiting for the Instance to be attached to the DOM because in fact when I appendChild() this element to the document the count down starts and after 5 seconds the console logs 'countdown!' as expected.
My goal is to execute this lifecycle without attaching anything to the document because the instances of MyCountDown are not always attached to the view but/and they need to be live-code between the different components of my web application.
One solution is to attach the new MyCountDown instances to an hidden element of the dom to force the Polymer lifecycle but I think this is not so intuitive.
I don't know the exact place to call, but the problem you have is that the property assessors are not in place.
I think you might get a clue from this talk https://www.youtube.com/watch?v=assSM3rlvZ8 at google i/o
call this._enableProperties() in a constructor callback?

React upgrade: "this" visibility in getDefaultProps

I am upgrading some older react component I inherited (v0.10.0) to work with the latest version of react (v0.14.8).
The following scenario stopped working:
// within a react component
onClick: function() {
// DO SOMETHING
}
getDefaultProps: function () {
return {
someProp: 'prop',
onClick: this.onClick
}
}
This is easily resolved moving the code into an anonymous function, like the following:
getDefaultProps: function () {
return {
someProp: 'prop',
onClick: function() {
//DO SOMETHING
}
}
}
My question is: why has the visibility of 'this' changed at that level and what's the best way to refactor this code? And what if I had-to/wanted-to use 'this' at that level?
Any help appreciated, as a disclaimer I am a react super-beginner!
The result of getDefaultProps() is shared across all instances of a component. That means that the result can't rely on any particular instance of the component. The reason it changed is likely because of the performance benefit from caching, although I can't say for sure.
As for refactoring the code, I'm not sure there's a silver-bullet here. From my perspective what you currently have seems like an anti-pattern. Props are meant to be passed in by consumers that have no knowledge of the inner workings of the component, so it seems odd that a default value for a prop would depend on the inner workings. Without knowing exactly what you're doing, I would say your best bet is to just use null as the default value for the prop, then check the value at runtime when you do have access to the this context.
handleSomeAction() {
if (!this.props.onClick) {
// DO SOMETHING
}
}

2-way data binding in native web components

I've been reading up on web components and am pretty intrigued by the nascent spec. Does anyone know if there is any support for 2-way data binding in the DOM, without having to use Polymer? An example would be appreciated.
Object.observe is a potential new way to do databinding in javascript. This feature is scheduled for Ecmascript 7(javascript), but some browsers currently support it, check here. Also check out this html5rocks article on object.observe
No, data binding isn't part of the Web Components spec.
You can of course implement data binding yourself using native JavaScript event listeners, and possibly the Proxy object, but it's probably best not to re-invent the wheel: if you want data binding, choose one of the many JavaScript frameworks out there which supports that. Polymer, React, Angular, and Vue are some recent examples of such libraries.
I've been playing around with this over the last few days. You can create a StateObserver class, and extend your web components from that. A minimal implementation looks something like this:
// create a base class to handle state
class StateObserver extends HTMLElement {
constructor () {
super()
StateObserver.instances.push(this)
}
stateUpdate (update) {
StateObserver.lastState = StateObserver.state
StateObserver.state = update
StateObserver.instances.forEach((i) => {
if (!i.onStateUpdate) return
i.onStateUpdate(update, StateObserver.lastState)
})
}
}
StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}
// create a web component which will react to state changes
class CustomReactive extends StateObserver {
onStateUpdate (state, lastState) {
if (state.someProp === lastState.someProp) return
this.innerHTML = `input is: ${state.someProp}`
}
}
customElements.define('custom-reactive', CustomReactive)
class CustomObserved extends StateObserver {
connectedCallback () {
this.querySelector('input').addEventListener('input', (e) => {
this.stateUpdate({ someProp: e.target.value })
})
}
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
<input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>
fiddle here
I like this approach because it occurs directly between precisely those elements you want to communicate with, no dom traversal to find data- properties or whatever.
One way: $0.model = {data}; setter on $0 assigns $0.data, responding to the update, and the other way: $1.dispatchEvent(new CustomEvent('example', {detail: $1.data, cancelable: true, composed: true, bubbles: true})); with $0.addEventListenever('example', handler) gives 2 way data binding. The data object is the same, shared on 2 elements, events and setters allow responding to updates. To intercept updates to an object a Proxy works model = new Proxy(data, {set: function(data, key, value){ data[key] = value; ...respond... return true; }}) or other techniques. This addresses simple scenarios. You might also consider looking at and reading the source for Redux, it provides conventions that seem relatively popular. As Ajedi32 mentions reinventing the wheel for more complex scenarios is not so practical, unless it's an academic interest.