How to call a function from inside nested components - javascript

I have this code in index.html:
<core-pages selected="{{welcomPage}}">
<div class="blueBackground">
<h1>asd</h1>
<h3>asd</h3>
<paper-button on-tap="{{welcomPagePlus}}">
Keep Going
<core-icon icon="forward"></core-icon>
</paper-button>
</div>
<div>welcom 2</div>
</core-pages>
and I want to call a function when the user clicks the button. I have tried this in my app.js:
function welcomPagePlus() {
...
}
this polymer code is locate in my primary file so I can't use the Polymer({...}) function. Also the button is deep inside my shadow-dom so it looks like that is the problem. Please help me find how to call a function from the shadow-dom

You can access shadow-dom elements from the "outside" like this:
First: Give your paper-button an id-Attribute: <paper-button id="paper-button-id" ...>
var button = document.querySelector("core-pages")
.shadowRoot
.querySelector("#paper-button-id");
There is no polymer required for this code. Be aware, that the 'shadowRoot' and 'querySelector' methods may not work in every browser. There may be better solutions, using polymer-methods.

You can also do it this way. Although sometimes it's useful, I hate piercing shadow boundaries and I avoid it if I can.
Codepen example
<link rel="import" href="https://www.polymer-project.org/0.5/components/core-pages/core-pages.html">
<link rel="import" href="https://www.polymer-project.org/0.5/components/core-icon/core-icon.html">
<link rel="import" href="https://www.polymer-project.org/0.5/components/paper-button/paper-button.html">
<link rel="import" href="https://www.polymer-project.org/0.5/components/core-icons/core-icons.html">
<paper-button>
Keep Going
<core-icon icon="forward"></core-icon>
</paper-button>
<core-pages selected="second">
<div name="first" class="blueBackground">
<h1>asd</h1>
<h3>asd</h3>
</div>
<div name="second">welcome 2</div>
</core-pages>
JavaScript in the Light DOM
document.querySelector('paper-button').addEventListener('click', function(e){
var currentPage = document.querySelector('core-pages');
currentPage.selected = currentPage.selected == 0 ? 1 : 0;
});

Related

Polymer: on-click event on dom-repeat item is not identified in index.html

I have a polymer app with entry point index.html . For some reason i had to use dom-repeat inside index.html itself instead of a polymer element. The code is like this
<dom-bind id="mainbody">
<template>
<app-drawer-layout>
<app-drawer slot="drawer">
<template is="dom-repeat" id="mainDemoBody">
<paper-item data-value={{item.is}} id="demoItem" on-tap="onElementSelect">
{{item.is}}
</paper-item>
</template>
</app-drawer>
<div> Main content
<div>
</app-drawer-layout>
</template>
</dom-bind>
And i have on-tap function defined in the script tag like this
<script>
function onElementSelect(e) {
console.log('here');
this.selectedElement = e.model.item;
this.elementTags = this.selectedElement.tags;
this.demoLoaded = false;
}
</script>
But i am getting following error on click of any item of dom-repeat on user interface
listener method onElementSelect not defined
Can someone help me out here, Thanks in advance.
"onElementSelect" doesn't seem to be binded with the dom-bind#mainbody.
My suggestion is to create a function that has binding with mainbody. That seemed to work for me.
Code :-
var mainbody = document.getElementById('mainbody');
mainbody.onElementSelect = function(e){
console.log('here');
this.selectedElement = e.model.item;
this.elementTags = this.selectedElement.tags;
this.demoLoaded = false;
}
Edit: Please note that the solution provided is not proper or necessary for a polymer element. This particular fix is needed in this scenario because polymer components are being used in a html file.

Polymer 2.0 getElementById in different ShadowDom

I'm trying to learn Polymer 2.0 but am stuck with the problem of getting an element from a different Shadow Dom. This worked in Polymer 1 but no longer in Polymer 2.0. What is the correct way of writing this? It just tells me that the targetText = Null.
Thanks for your help!
This is a MWE:
Polymer WC 1:
<dom-module id="sc-navdrawer">
<template>
<style is="custom-style">
p {
font-weight: bold;
}
.changed {
color: red;
}
</style>
<p>Some text in normal p tag</p>
<div id="test" class="htmltextcontent" inner-h-t-m-l="{{inputText}}"></div>
</template>
<script>
Polymer({
is: 'sc-navdrawer',
properties: {
inputText: {
type: String,
value: "<p>Some innerhtml text in p tags</p>"
}
}
});
</script>
</dom-module>
Polymer WC 2:
<dom-module id="sc-testpage">
<template>
<button onclick="{{changeColor}}">Click here to change color</button>
</template>
<script>
Polymer({
is: 'sc-testpage',
changeColor: function() {
var targetText = document.getElementById("test");
console.log(targetText);
targetText.classList.add("changed");
}
});
</script>
</dom-module>
Well first thing that I see is you use document.getElementById("test"); and if you say this worked you have used Shady Dom. Polymer 2 forces you to use Shadow Dom so this command should be replaced by Polymer.dom(this.root).querySelector("#test"). Because Shadow Dom encapsulates your Component you cant access its content with the document Object
But this should not fix your Problem. This Encapsulation means you canĀ“t access the Content of a WebComponent so you cannot access an element with id:xyz from another Component. Have a look at these links they will explain to you how shadowDom works:
1. https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/
2. https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM
3. https://glazkov.com/2011/01/14/what-the-heck-is-shadow-dom/
Try using paper-input and setting it's value:
<paper-input id="test" label="input" value="{{inputText}}"></paper-input>
Then you can access the variable like this:
var targetText = this.$.inputText;
(this should work with other elements other than paper-input)
Instead of using getElementById you should be using Automatic node finding This works if your two Elements have a child parent relation to each other.
I also believe instead of using a onclick on your button in WC 2, you should be using a on-tap. This is the recommended way in the Polymer documentation.
Further on, I do not really understand why you are using two way data binding on your onclick attribute. I might be missing something but your code should work perfectly fine with a normal function call.
<dom-module id="sc-testpage">
<template>
<button on-tap="changeColor">Click here to change color</button>
</template>
<script>
Polymer({
is: 'sc-testpage',
changeColor: function() {
var targetText = this.$.sc-navdrawer.$.test;
console.log(targetText);
targetText.classList.add("changed");
}
});
</script>
</dom-module>

Adding a div on clicking a button but the divs which are added are not responding same

I am performing that On Button Clicked a div is created but issue is that it is not performing as same as main div is performing like resizing & draggable.Please Help?
<html>
<head>
<link rel="stylesheet" href="test.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script>
$(function () {
$("#box").resizable({
alsoResize:"#main",
alsoResize:"#title_bar",
alsoResize:"#container"
});
$('#main').draggable();
$("#button").click(function () {
if ($(this).html() == "-") {
$(this).html("+");
} else {
$(this).html("-");
}
$("#box").slideToggle();
});
$("#NewWidget").click(function() {
$("#container").append('<div class="main" id="main"><div id="title_bar" ><div id="button">-</div></div><div id="box"><div><h4>Hi user</h4><p>Hello Users. How are YOU?</p> </div></div>');
});
});</script>
</head>
<body>
<input type="button" id="NewWidget" value="Add New Widget"/>
<div id="container">
<div class="main" id="main" >
<div id="title_bar" >
<div id="button">-</div>
</div>
<div id="box">
<div>
The ID's needs to be unique, so if you create a lot of elements, either make ID's unique or use classes or data-id attribute to recognize which box is which - in the example in codepen i showed you how to create ID's with simple counter variable, that is available in this scope (remember about closures).
What you did in your code is only appending a new structure to DOM, there is no event handlers/hooks attached to this element, that's why you either need to create new event handler/hooks when adding the element to the DOM, or after, in my example, i will to it before adding the element to the DOM.
Here's link to codepen:
https://codepen.io/anon/pen/GEyPXr
Additional hint: whenever possible, avoid creating anonymous function, always either name them, or reffer to them, meaning:
$(".main").find('.button').on('click',function(){
// this looks weak, plus anonymous function doesn't tell you what it does
});
use this instead:
$(".main").find('.button').on('click',makeButtonWork);
function makeButtonWork(){
//this looks much better, plus you named the function and you know the purspose of it, without looking through code
}
To respond to comments:
changing starting position of given element can be done by adding:
$('#main-' + counter).css({'top': 100, 'left' : 20}) //your positions here
in the makeButtonWork
see updated codepen for more info
Javascript events don't work this way. Take it as that in the moment when you call $('#main').draggable();, then browser finds matching element (here the one with ID 'main') and does some action with it (here enables the draggable functionality).
If you later add another element, which would also have been matching, it doesn't mean anything - it is just a plain div, until you call some script again.
Also, keep in mind that ID's must be unique on your page, you can't have two id="main" divs on same page. Use classes instead.
$("#NewWidget").click(function() {
var $newElement = $('<div class="main"><div class="title_bar" ><div class="button">-</div></div><div class="box"><div><h4>Hi user</h4><p>Hello Users. How are YOU?</p> </div></div>');
$newElement.find('.main').draggable();
$newElement.find('.button').click( /* add the click handler function here */ );
$newElement.find('.box').resizable( /* resizable params goes here */ );
$("#container").append($newElement);
});

paper-input binding in dom-bind

I'm trying to combine 2 paper elements in my index.html (within a dom-bind) but can't find out the right syntax for this. I think I've tried all combinations mentioned in the Polymer binding documentation... In this simple example, the elevation of a paper-material element should be set by what's put into a paper-input (i.e. a value between 1 and 5). Can someone provide me the correct syntax for this?
My code:
<html>
<head>
...loading necessary components...
</head>
<body>
<template is="dom-bind">
<paper-input id="input" label="label"></paper-input>
<paper-material elevation$="{{this.$.input.value}}">
Some text here...
</paper-material>
</template>
</body>
</html>
When binding to elements that don't inherit/extend from native HTMLElements you shouldn't use the dollar sign. You can too bind directly an input to a property, below is an example:
<paper-input value="{{elevation::input}}">
<!-- or -->
<paper-input bind-value="{{elevation}}">
Here is a working example validating the elevation the user wants to set.

Polymer - Refresh Template With Bound Data

How do I refresh bound data in the order-items-list element from the post-card element?
I'm using Polymer (the polymer-elements are in the shadow DOM).
I've been trying to figure this out for hours, but to no avail (I'm new to web development). One of the thing I tried is this: (givers error: Cannot read property 'getElementsByTagName' of undefined)
this.$.orderitemstemplateparent.getElementsByTagName('template')[0].iterator_.updateIteratedValue();
I have the following 3 files:
index.html:
<html>
<body unresolved>
<core-header-panel>
<div id="container">
<div id="order-items-div>
<order-items-list id="order-items-list">
order-items-list.html:
<polymer-element name="order-items-list">
<template>
<div id="orderitemstemplateparent">
<template id="order-items-template" repeat="{{post in posts}}>
<script>
Polymer ({
// FUNCTIONS THAT UPDATE THE DATA {{posts}} HERE
});
</script>
post-card.html:
<polymer-element name="post-card">
<template id="card-template">
<div id="card-header">
<paper-ripple on-tap="{{cardClick}}"></paper-ripple>
<script>
Polymer ({
cardClick: function(event, detail, sender) {
// RELOAD #order-items-template FROM HERE
}
});
</script>
Any help would be appreciated.
When you have properties with a - in the key, you need to use bracket notation to access them.
this.$['order-items-template-parent'].getElementsByTagName('template')[0].iterator_.updateIteratedValue();
Otherwise, it's parsed like this:
this.$.order - items - template - parent.getElementsByTagName('template')[0].iterator_.updateIteratedValue();
You're doing some weird subtraction, and parent is undefined.

Categories