How do I call methods on other elements? - javascript

<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="my-thing">
<script>
Polymer('my-thing', {
athing: function () { return 'hello' }
});
</script>
</polymer-element>
I want the use the element defined above in the element below and have access to the athing property.
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="./mything.html">
<polymer-element name="my-hello"">
<template>
<my-thing id="mything"></my-thing>
</template>
<script>
Polymer('my-hello', {
ready: function () {
this.$.mything.athing() // returns undefined
}
});
</script>
</polymer-element>

Nodes with id's are reflected in the $ hash, not in this, so
this.$.mything.athing(); // returns 'hello'
[Poster changed his example to include the missing .$]
After fixing the syntax, I cannot recreate your problem.
http://jsbin.com/tegefura/1/edit

Related

Polymer: paper-button on-click does not work when the button is created in javascript

I created 2 buttons. Both have the same on-click. The first is created by writing a html button inside a div. This one works. The second is created by having an empty div with the inner-h-t-m-l property returning the button. This one does not work. Why?
<link rel="import" href="bower_components/polymer/polymer-element.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<dom-module id="x-custom">
<template>
<div inner-h-t-m-l="[[getButton()]]"></div>
<div><paper-button on-click='didClick'>Does Work</paper-button></div>
</template>
<script>
class XCustom extends Polymer.Element {
static get is() {
return 'x-custom';
}
static get properties() {
return {}
}
getButton() {
return "<paper-button on-click='didClick'>Does Not Work</paper-button>";
}
didClick() {
alert("Did Click");
}
}
customElements.define(XCustom.is, XCustom);
</script>
</dom-module>

Using this.updateStyles() after this.classList.add()

I have a component like this (tiny, short and sweet):
<link rel="import" href="/bower_components/polymer/polymer.html">
<dom-module id="my-app">
<template>
<style include="my-shared-styles">
:host(.main-ent) {
--primary-color: var(--paper-blue-600);
}
:host(.main-all) {
--primary-color: var(--paper-purple-700);
}
</style>
<an-element-using-primary-color></an-element-using-primary-color>
</template>
<script>
Polymer({
is: 'my-app',
properties: {
siteInfo: {
type: Object,
notify: true,
},
attached: function() {
console.log("SITEINFO (SHORT):", this.siteInfo.short );
this.classList.add('main-' + this.siteInfo.short);
//this.async( function() {
this.updateStyles();
//});
},
});
</script>
</dom-module>
The problem I am having is that without that this.async(), sometimes (say one time out of 8) this.updateStyles() doesn't seem to work: the primary colour stays "wrong".
I am not even 10000% sure the problem is solved with this.async(), or only mitigated.
So...
What's the root of the problem?
Does this.async() actually fix it?
If not, what does?
Try to clean up your CSS Classes. First Remove the one you donĀ“t need anymore then set the new one.
this.classList.remove('unneeded_class');
this.classList.add('new_class');

Polymer 1.6 and Polymer-cli, access app property from within a custom element

Using the polymer-cli tool, and the shopping cart boilerplate as a starting point, I made a simple mock-up to illustrate the use case.
Assume your index.html file includes "test-app.html" and the matching tag
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>My App</title>
<link rel="shortcut icon" sizes="32x32" href="/images/app-icon-32.png">
<meta name="theme-color" content="#fff">
<link rel="manifest" href="/manifest.json">
<script>
// setup Polymer options
window.Polymer = {lazyRegister: true, dom: 'shadow'};
// load webcomponents polyfills
(function() {
if ('registerElement' in document
&& 'import' in document.createElement('link')
&& 'content' in document.createElement('template')) {
// browser has web components
} else {
// polyfill web components
var e = document.createElement('script');
e.src = '/bower_components/webcomponentsjs/webcomponents-lite.min.js';
document.head.appendChild(e);
}
})();
// load pre-caching service worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}
</script>
<!-- <link rel="import" href="/src/bewi-app.html"> -->
<link rel="import" href="/src/test-app.html">
<style>
body {
margin: 0;
font-family: 'Roboto', 'Noto', sans-serif;
line-height: 1.5;
min-height: 100vh;
background-color: #eee;
}
</style>
</head>
<body>
<span id="browser-sync-binding"></span>
<test-app id="test"></test-app>
</body>
</html>
Now, assume test-app.html containing the following (again a mere simplified copy of my-app.html):
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<link rel="import" href="test-element.html">
<dom-module id="test-app">
<template>
<app-location route="{{route}}"></app-location>
<app-route
route="{{route}}"
pattern="/:page"
data="{{routeData}}"
tail="{{subroute}}"></app-route>
test-element is loaded bellow
<test-element></test-element>
<div>
</div>
</template>
<script>
Polymer({
is: 'test-app',
properties: {
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged'
},
baseUrl: {
type: String,
value: '/'
},
siteUrl: {
type: String,
value: 'http://fqdn.local'
}
},
observers: [
'_routePageChanged(routeData.page)'
],
_routePageChanged: function(page) {
this.page = page || 'view1';
},
_pageChanged: function(page) {
// load page import on demand.
this.importHref(
this.resolveUrl('my-' + page + '.html'), null, null, true);
}
});
</script>
</dom-module>
Now, the test-element.html
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="test-element">
<template>
<div> I am a test </div>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'test-element',
ready: function() {
console.log('READY');
console.log('find #test using document.querySelector', document.querySelector('#test')); // OK
console.log('find #test .siteUrl using document.querySelector', document.querySelector('#test').siteUrl); // undefined
console.log('find #test .siteUrl using Polymer.dom', Polymer.dom(document.querySelector('#test')).siteUrl); // undefined
console.log('find #test .siteUrl using Polymer.dom().node', Polymer.dom(document.querySelector('#test')).node.siteUrl); // undefined
console.log('find #test .siteUrl using Polymer.dom().properties', Polymer.dom(document.querySelector('#test')).node.properties); // {object} but, I'm guessing not the computed values of the properties
// So, how may I access the #test app's "siteUrl" property from within a custom element?
}
});
})();
</script>
</dom-module>
So, the real question is, how may test-element access the property "siteUrl" in the main app?
I'm planning to make this variable readOnly, and access it from other custom elements.
I'ld prefer this approach VS passing the siteUrl as an attribute to the test-element element..
What do you think?
The right way to pass information through elements is using the Data Binding system, i.e. "passing the siteUrl as an attribute to the test-elemet element"
You'll accomplish the Read Only requirement surrounding the variable with square brackets, like this [[siteUrl]] as described in Property change notification and two-way binding.
You can set a variable in a global environment as you said like
<script>
var myGlobalVar = 'is accessible in any element'
Polymer({
is: 'test-app',
// ...
});
</script>
and you can access it in every element.
BUT, global variables are not recommended as you may know. References about why in the links below.
Global Variables Are Bad
Why are global variables considered bad practice?
I've Heard Global Variables Are Bad, What Alternative Solution Should I Use?

Callback in Polymer(); when element is shown

Is there a callback available in the Polymer({}) object which fires everytime the element is shown ?
ready is not suitable because it's called when the element is created on initial page load.
I need an event or callback every time the route changes and my element is displayed.
Why do I need this ? I have an element which is behaving differently if a certain request parameter is set. So I need to check on each load whether the parameter is set or not.
Edit:
I worked around my requirement by doing the stuff I need to be done on element display in my routing functions:
page("/app/list", function() {
document.querySelector("my-list").$.loadList.generateRequest();
app.route = "list";
});
In the meantime I came also accross app-route which as well has functionality to call methods on route or view changes.
You can read about it here:
https://www.polymer-project.org/1.0/toolbox/routing#take-action-on-route-changes
Here is a working example:
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html" />
<link rel="import" href="bower_components/app-route/app-location.html" />
<link rel="import" href="bower_components/app-route/app-route.html" />
<link rel="import" href="bower_components/iron-pages/iron-pages.html" />
</head>
<body>
<container-element></container-element>
</body>
</html>
<dom-module id="container-element">
<template>
<app-location route="{{route}}" use-hash-as-path></app-location>
<app-route route="{{route}}" pattern=":view" data="{{routeData}}"></app-route>
Page 1 | Page 2
<iron-pages selected="[[routeData.view]]" attr-for-selected="name">
<div name="page1">This is Page 1.</div>
<x-element1 name="element1"></x-element1>
</iron-pages>
</template>
<script type="text/javascript">
Polymer({
is : "container-element",
observers : [ "_viewChanged(routeData.view)" ],
_viewChanged : function(view) {
if (view) {
if (view === "element1") {
document.querySelector("x-element1").test();
}
}
}
});
</script>
</dom-module>
<dom-module id="x-element1">
<template><p>This is Element 1.</p></template>
<script type="text/javascript">
Polymer({
is : "x-element1",
test : function() {
console.log("Callback of Element 1 called.");
}
});
</script>
</dom-module>
Maybe the attached callback is what you're looking for.
This lifecycle callback is called when an element is attached to the DOM and should therefore be the right choice. It is always called after the ready callback.
From the polymer docs:
https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html#initialization-order
attached: function() {
this.async(function() {
// access sibling or parent elements here
});
}

Polymer HTML Import into Custom Element

Hey I'm beginning with Webcomponents and I built a little HTML Import Example, where I import a calander from another Website with VanillaJs and it works perfekt.
As the 2. Step I wanted to HTML import into a Polymer element, so that I can use the element over and over again. Here is my code:
<link rel="import" href="http://www.testsite.com">
<link rel="import" href="bower_components/polymer/polymer.html">
<polymer-element name="event-calendar-element">
<template>
<div id="container" style = "width:220px;"></div>
</template>
<script>
var owner = document._currentScript.ownerDocument;
var link = owner.querySelector('link[rel="import"]');
var content = link.import;
var container = document.getElementById('container');
var el = content.querySelector('.slider-teaser-column');
container.appendChild(el.cloneNode(true));
</script>
</polymer-element>
In the other HTML document I use the custom element and I can see, that the import worked(the resources from testsite.com are loaded), but my Polymer element has no shadowDOM - the imported and selected element is not appended to my <event-calendar-element> :/
the container <div> is null and therefore the following error occurs: Cannot read property 'appendChild' of null
Any help appreciated ;)
The <div> is inside the <template> and since you're not using Polymer() you'd need to use template.content.querySelector() get at and modified it's content. Instead, you can do this in Polymer:
<link rel="import" href="http://www.testsite.com" id="fromsite">
<link rel="import" href="bower_components/polymer/polymer.html">
<polymer-element name="event-calendar-element">
<template>
<div id="container" style="width:220px;"></div>
</template>
<script>
(function()
var owner = document._currentScript.ownerDocument;
Polymer({
ready: function() {
var content = owner.querySelector('link#fromsite').import;
var el = content.querySelector('.slider-teaser-column');
this.$.container.appendChild(el.cloneNode(true));
}
});
})();
</script>
</polymer-element>

Categories

Resources