getElementById in Polymer element - javascript

How can I use getElementById in a Polymer custom element?
Here is my element:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/shared-styles.html">
<dom-module id="bb-calendar">
<template>
<style is="custom-style" include="shared-styles"></style>
<div class="card">
<paper-toolbar>
<div title>Calendar</div>
</paper-toolbar>
<div id="hideme">
<div>this should be hidden</div>
</div>
</div>
</template>
<script>
Polymer({
is: 'bb-calendar',
ready: function() {
document.getElementById("hideme").style.display = 'none';
}
});
</script>
</dom-module>
When I run the code I get this error message: Uncaught TypeError: Cannot read property 'style' of null
Obviously I'm doing something wrong but I don't know what.

I'd use
ready: function() {
this.$.hideme.style.display = 'none';
}
of when the element is inside <template dom-if...> or <template dom-repeat...>
ready: function() {
this.$$('#hideme').style.display = 'none';
}
In the end, I'd use class binding and bind a class to the element and update a property to reflect that change and use CSS to set style.display
<template>
<style>
.hidden { display:none; }
</style>
...
<div class$="{{hiddenClass}}">
<div>this should be hidden</div>
</div>
Polymer({
is: 'bb-calendar',
properties: {
hiddenClass: String,
},
ready: function() {
this.hiddenClass = 'hidden';
}
});

Your problem is actually that your element is not attached to the document DOM when the ready callback is fired. For simply showing/hiding an element you may use the hidden attribute like this: <div hidden$="{{!shouldShow}}">

Related

Why the JavaScript function doesn't work?

If you click the button, it should have showed, but it doesn't.
Is any wrong here?
I have written many JavaScript files in this way, and tried many ways like changing the position of JavaScript code anywhere. But all the files I wrote don't work
Thanks in advance!
An instance :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Debug</title>
</head>
<style>
.debug {
display : none;
}
</style>
<body>
<div class = "debug">
<p>Welcome!</p>
</div>
<button class = "show" onclick = "JavaScript : show();">Show</button>
<script type = "text/JavaScript">
function show() {
document.querySelector("debug").style.display = "flex";
}
</script>
</body>
</html>
Thanks to all of you!
About .querySelector()
The Document method querySelector() returns the first Element within the document that matches the specified selector. [...] The selector is a CSS selector string.
- MDN web docs
You should, therefore, put in your code:
document.querySelector(".debug")
You can also select HTML elements by their tags, for example, you want to select the first div:
document.querySelector("div")
document.querySelector("div").style.color = "lightgreen"
<div>Hello World</div>
Imagine you had your own HTML tag: <hello>, then you can select all hello elements with:
document.querySelector("hello")
document.querySelector("hello").style.color = "lightblue"
<hello>Hello World</hello>
Side note on inline eventListeners
Also in HTML for inline event listener instead of:
<button class = "show" onclick = "JavaScript : show();">Show</button>
you can simply write:
<button class = "show" onclick = "show();">Show</button>
It is recommended to use JavaScript to initiate these eventListeners instead of having them inline inside your HTML markup. Use the .addEventListener() method:
document.querySelector(".show").addEventListener('click', show)
↑ ↑
event function
type
Back to your code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Debug</title>
</head>
<style>
.debug {
display : none;
}
</style>
<body>
<div class = "debug">
<p>Welcome!</p>
</div>
<button class ="show">Show</button>
<script type = "text/JavaScript">
document.querySelector(".show").addEventListener("click", show)
function show() {
document.querySelector(".debug").style.display = "flex";
}
</script>
</body>
</html>
Last thing
Also it's better to keep HTML, JavaScript and CSS all in separate files, for instance:
- index.html
- style.css
- script.js
And call the CSS and JavaScript files in your HTML file with the link (preferably inside <head>) and script (at the bottom of <body>) tags:
<link rel="stylesheet" type="text/css" href="style.css">
And
<script src="script.js"></script>
For class selector you need to add a dot (.) e.g. .debug
Also, in HTML, you can simply have onclick as onclick="show();"
function show() {
document.querySelector(".debug").style.display = "flex";
}
.debug {
display: none;
}
<div class="debug">
<p>Welcome!</p>
</div>
<button class="show" onclick="show();">Show</button>
You were not passing class to querySelector. Set ".debug" instead of "debug".
Below is working code:
function show() {
document.querySelector(".debug").style.display = "flex";
}
.debug {
display: none;
}
<div class="debug">
<p>Welcome!</p>
</div>
<button class="show" onclick="JavaScript : show();">Show</button>
queryselectors requires . and # for class and ID selector:
querySelector(".debug")

How to implement a paper-styled "<select multiple>" box with Polymer, without "paper-dropdown-menu"?

I'm working on a Polymer application that uses iron-form to submit a form to a back-end web-service. One of the elements in the form is a box where the user can select multiple elements.
Using the paper-dropdown-menu with a paper-listbox with multi set works, but the UX is horrible because the user can't see which elements are selected without opening the dropdown (and blocking other elements). Also - it requires more clicks to operate.
Ideally we'd just use the paper-listbox without the paper-dropdown-menu, as that is exactly the UI that we need - similar to HTML's classic <select multiple> but with a Material Design sheen. But without the paper-dropdown-menu wrapper, iron-form doesn't pick up on the paper-listbox selected values and will not submit those.
I've noticed that iron-form support classic HTML <select> (and even support the multiple behavior), but the UI for that is jarring in contrast with the rest of the form.
Is there something else that we can wrap around the paper-listbox to get the form to behave without modifying the original paper-listbox UI, or get paper-dropdown-menu to have an "always open" mode? If neither of those work (and I couldn't get either to work, BTW), what else can we do?
You could wrap the <paper-listbox> in a custom element that implements <iron-form-element-behavior>. The behavior exposes a value property, which could be bound to <paper-listbox>.selectedValues, allowing <iron-form> to submit the multiple listbox values:
<dom-module id="multi-listbox">
<template>
<paper-listbox multi selected-values="{{value}}">
<content></content>
</paper-listbox>
</template>
<script>
Polymer({
is: 'multi-listbox',
behaviors: [Polymer.IronFormElementBehavior]
});
</script>
</dom-module>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
_onResponse: function(e) {
this._response = JSON.stringify(e.detail.response, null, 2);
},
_submit: function() {
this._response = null;
this.$.form.submit();
}
});
Polymer({
is: 'multi-listbox',
behaviors: [
Polymer.IronFormElementBehavior
],
properties: {
value: {
type: Array,
value: () => [],
notify: true
},
invalid: {
type: Boolean,
reflectToAttribute: true
}
},
validate: function() {
const isValid = !this.required || !!(this.value && this.value.length > 0);
this.invalid = !isValid;
console.log('invalid', this.invalid);
return isValid;
},
_clearError: function() {
this.invalid = false;
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.1/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-form/iron-form.html">
<link rel="import" href="paper-button/paper-button.html">
<link rel="import" href="paper-checkbox/paper-checkbox.html">
<link rel="import" href="paper-listbox/paper-listbox.html">
<link rel="import" href="paper-item/paper-item.html">
<link rel="import" href="iron-form-element-behavior/iron-form-element-behavior.html">
<link rel="import" href="iron-validatable-behavior/iron-validatable-behavior.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
multi-listbox,
paper-checkbox,
paper-button {
margin: 0.5em;
}
</style>
<paper-checkbox active="{{_required}}">Required</paper-checkbox>
<form is="iron-form"
id="form"
action="//httpbin.org/get"
on-iron-form-response="_onResponse">
<multi-listbox name="listbox-values" required="[[_required]]">
<paper-item>Item 1</paper-item>
<paper-item>Item 2</paper-item>
<paper-item>Item 3</paper-item>
<paper-item>Item 4</paper-item>
</multi-listbox>
<paper-button raised
on-tap="_submit">Submit</paper-button>
</form>
<pre>[[_response]]</pre>
</template>
</dom-module>
<dom-module id="multi-listbox">
<template>
<style>
:host {
display: block;
}
paper-listbox {
border: solid 2px lightgray;
}
:host([invalid]) paper-listbox {
border: solid 2px var(--error-color, red);
}
</style>
<paper-listbox multi
selected-values="{{value}}"
on-iron-activate="_clearError">
<content></content>
</paper-listbox>
</template>
</dom-module>
</body>
codepen

polymer could not style custom tag in repeat template

trying to style the paper-button inside the template, I've tried different sectors and only one is worked so how can i do the styling correctly.
so in the index.html i call iron-ajax element and one the last-response i call a dom-repeat template
<iron-ajax id="aj" auto
url="url"
handle-as="json"
last-response="{{ajaxResponse}}"
contentType="text/HTML"
debounce-duration="300"></iron-ajax>
<div class="video">
<template is="dom-repeat" items="[[ajaxResponse]]" >
<paper-card image="[[item.fields.image]]">
<feed-bdy items="[[item]]"></feed-bdy>
and in the feed-bdy.html :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-styles/typography.html">
<dom-module is="feed-bdy">
<style >
:host{
--paper-button-ink-color: var(--paper-pink-a200);
paper-button.custom:hover{ background-color: var(--paper-indigo-100) !import; }
}
:host paper-button.rea:hover{
--paper-button-ink-color: var(--paper-pink-a200);
color: red
}
--paper-button.custom:hover {
background-color: var(--paper-indigo-100) !import;
color: white !important;
}
paper-button:hover{
background-color:red !important;
}
</style>
<template id="repeater" is="dom-repeat" items="{{items}}">
<div class="card-content">
<div class="ar-header">
<h3> [[items.fields.title]]</h3>
</div>
<div class="content-bdy"></div>
</div>
[[_renderHTML(items)]]
<div class="card-actions">
<paper-button class="custom">إقراء المزيد !</paper-button>
<paper-button>
شارك
<iron-icon icon="reply"></iron-icon>
</paper-button>
</div>
</template>
<script>
Polymer({
is: 'feed-bdy',
properties: {
artId:{
type : String,
observer: '_renderHTML'
}
},
listeners :{
},
_renderHTML: function(items) {
// firstp to get only the first pargarph to put in the home page
var ss= items.fields.body;
//console.log(this.$$(".card-content"));
var firstp = ss.substring(0,ss.search("</p>")+4);
this.$$(".content-bdy").innerHTML += firstp;
},
_toggle : function(e){
var id = Polymer.dom(e).localTarget.title;
//console.log(id);
var moreInfo = document.getElementById(id);
// console.log(moreInfo);
var iconButton = Polymer.dom(e).localTarget;
iconButton.icon = moreInfo.opened ? 'hardware:keyboard-arrow-up'
: 'hardware:keyboard-arrow-down';
moreInfo.toggle();
}
});
</script>
</dom-module>
There are a few issues with your CSS:
import! should be important!
Mixins and custom properties need to be defined within a selector:
INCORRECT
<style>
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
</style>
CORRECT
<style>
:host {
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
}
</style>
Mixins and custom properties are not selectors:
INCORRECT
<style>
--paper-button.special-css-class {
/** Some styles */
}
</style>
Instead, you can use the .special-css-class as your selector, and define your mixin/custom property for any element that matches:
CORRECT
<template>
<style>
.special-css-class {
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
}
</style>
<paper-button class="special-css-class"></paper-button>
<!-- This button won't have your custom styles! -->
<paper-button></paper-button>
</template>
At least for paper-button, you need not use custom properties/mixins if you just want to specify the color and background color:
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="paper-button/paper-button.html" rel="import">
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
paper-button {
background-color: purple;
color: red;
}
</style>
<template is="dom-repeat" items="{{items}}">
<paper-button>Click Me</paper-button>
</template>
</template>
<script>
Polymer({
is: 'x-foo',
properties: {
items: {
value: [1, 2, 3, 4]
}
}
});
</script>
</dom-module>

polymer 1.0 data binding not working as expected

I'm trying to bind some data in a custom element but to no avail. I have a system-menu.html that has my custom element:
system-menu.html
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-menu-behavior/iron-menubar-behavior.html">
<dom-module id="system-menu">
<template>
<template is="dom-repeat" items="{{data}}">
<li>{{item.name}}</li>
</template>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'system-menu',
behaviors: [
Polymer.IronMenubarBehavior
],
ready: function() {
console.log(this.data);
}
});
})();
</script>
This is how I use it (Note that i've done all imports for the other items)
<link rel="import" href="/themes/_components/custom_components/system-menu/system-menu.html">
<style>
.list {
display: inline-block;
padding: 8px 0;
}
.list li {
display: block;
padding: 8px;
}
.list li[disabled] {
color: #ccc;
}
</style>
<system-menu class="list flex horizontal end-justified layout" data="{{data}}"></system-menu>
Also, {{data}} in this file is json encoded data from php. Here it is
{"login":{"url":"/login","parent_id":"0"},"register":{"url":"/register","parent_id":"0"}}
My question is, how am I supposed to access and use this json data data in my system-menu.html module?
Currently i'm getting these error:
[dom-repeat::dom-repeat]: expected array for items, found
{
Uncaught TypeError: Cannot read property 'getKey' of undefined
First, you need to transform your json {{data}} into an array of objects readable by <template is='dom-repeat'>. I assume that you want
{"login":{"url":"/login","parent_id":"0"},"register":{"url":"/register","parent_id":"0"}}
to become something like
[ {name: "login", url: "/login", parent_id: "0"}, {name: "register", url: "/register", parent_id: "0"} ]
The actual code to do the above should be trivial and beyond the scope of this question.
Second, you need to publish the data property in your <system-menu> custom element since you are binding the data attribute from the parent template.
<system-menu class="list flex horizontal end-justified layout" data="{{data}}"></system-menu>
You can pass in a computed function (to perform the conversion from your json {{data}} into the dom-repeat-compatible array) into the items attribute in the <template is='dom-repeat'> tag.
Putting it all together, your system-menu.html might look something like that
<dom-module id="system-menu">
<template>
<template is="dom-repeat" items="{{_transformData(data)}}">
<li>{{item.name}}</li>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'system-menu',
behaviors: [
Polymer.IronMenubarBehavior
],
properties: {
data: Object
},
_transformData: function (d) {
// place transformation code here
return transformedDataThatIsNowAnArray;
},
ready: function() {
console.log(this.data);
}
});
</script>

Polymer: Where exactly do I put my Javascript for an Element?

I have trouble loading Javascript in normal Polymer Elements:
Here is the test code that works perfectly fine, when executed without polymer:
<body>
<style>
#content {background-color: #f2f2f2;}
#button {padding: 10px 20px;}
</style>
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button id="button">Testbutton</button>
</div>
<script>
function popup2() {
alert("What's up brow?");
console.log("deine mudda");
};
var button = document.getElementById("button");
button.addEventListener("click", popup2, false);
</script>
</script>
</body>
But I want to use Javascript inside Polymer Elements and have tried the following insertions:
Nr. 1: Javascript inside the script tag, after the template tag:
<polymer-element name="my-element">
<template>
<style>
#content {background-color: #f2f2f2;}
#button {padding: 10px 20px;}
</style>
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button id="button">Testbutton</button>
</div>
</template>
<script>
Polymer('my-element', {
popup: function() {
alert('What the... dude?');
},
var button = document.getElementById("button");
button.addEventListener("click", popup, false);
});
</script>
</polymer-element>
And this doesn't work. I get the error message in firefox: "SyntaxError: missing : after property id.
Chrome instead says: "SyntaxError: Unexpected Identifier".
Both poin to the line "var button = document.getelementById("button");
According to the Polymer Documentation, javascript should just be placed at the end of the file:
https://www.polymer-project.org/docs/start/tutorial/step-1.html
So in a second attempt, I place my Javascript directly inside the template tags like this:
<polymer-element name="my-element">
<template>
<style>
#content {background-color: #f2f2f2;}
#button {padding: 10px 20px;}
</style>
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button id="button">Testbutton</button>
</div>
<script>
function popup() {
alert("jajaja");
};
var button = document.getElementById("button");
button.addEventListener("click", popup, false);
</script>
</template>
<script>
Polymer('my-element', {
});
</script>
</polymer-element>
But this time I get: "Uncaught TypeError: Cannot read property 'addEventListener' of null", which points agian to the line where I write: "button.addEventListener("click", popup, false);".
I guess this means, that the compiler can't see the button id, because it is in the Shadow-Dom?
Please instruct me.
<polymer-element name="my-element">
<template>
<style>
#content {background-color: #f2f2f2;}
#button {padding: 10px 20px;}
</style>
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button on-tap="{{popup}}">Testbutton</button>
</div>
</template>
<script>
Polymer('my-element', {
popup: function() {
alert('alert');
}
});
</script>
</polymer-element>
inside a polymer element you can bind directly to a function by using on-tap="{{function}}" attribute.
edited: all code didn't get into block
keeping eventlisteners in the js method
<polymer-element name="my-element">
<template>
<style>
#content {background-color: #f2f2f2;}
#button {padding: 10px 20px;}
</style>
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button id="button">Testbutton</button>
</div>
</template>
<script>
Polymer('my-element', {
ready: function () {
var button = this.$.button;
button.addEventListener("click", function () {
alert('alert');
});
}
});
</script>
</polymer-element>
edited again: OP wanted to keep html separate from JS
edited 1 more time: i think using a anonymous function is the easiest way to go here if not using the declarative method. code edited
script tag goes between closing template tag and closing polymer element tag or before the element definition but in this case when you call Polymer('my-element') you need to include tag name
Here is the example above with external js file, you can do the same with css
<polymer-element name="my-element">
<template>
<link rel="stylesheet" href="my-element.css">
<div id="content">
<h1 id="title">Title</h1>
<p>This example uses the addEventListener() method to attach a click event to the document.</p>
<button id="button">Testbutton</button>
</div>
</template>
<script src="my-element/my-element.js"></script>
</polymer-element>
The folder name and js file name can be whatever you want but I think good practices you would structure like this
File Folder Structure
-myelements -folder
--my-first-element -folder
--my-first-element.html
--my-first-element.css
--my-first-element.js
--my-second-element -folder
--my-second-element.html
--my-second-element.css
--my-second-element.js
<polymer-element name="ouch-button">
<template>
<button on-click="{{onClick}}">Send hurt</button>
</template>
<script>
Polymer({
onClick: function() {
alert('ouch', {msg: 'That hurt!'}); // fire(type, detail, targetNode, bubbles?, cancelable?)
}
});
</script>
</polymer-element>
<ouch-button></ouch-button>

Categories

Resources