Polymer 2.0 getElementById in different ShadowDom - javascript

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>

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.

Why Vue.js template can't interact it's script?

I'm using vue.js with axios and I'm trying to make an ajax call when I click a certain button. My problem is that my button's onclick event can't find it's function. Can someone explain to me Why can't my template interact with my script in my view?
Here's a short example of what I'm trying to achieve.
Example.vue
<template>
<button onclick="someClickFunction();"></button>
</template>
<script>
function someClickFunction(){
console.log("You've pressed the button");
}
export default {
name: "button-view",
}
</script>
<style scoped>
</style>
in vue you must write functions in the methods object and onclick == #click
<template>
<button #click="someClickFunction();"></button>
</template>
<script>
export default {
name: "button-view",
methods: {
someClickFunction(){
console.log("You've pressed the button");
}
}
}
</script>
<style scoped>
</style>
That's because in vue, you don't use the native onclick event.
Instead you use the
v-on:click
or the
#click
Better check the documentation. It is written very thoroughly
https://v2.vuejs.org/v2/guide/events.html
EDIT:
You also have error on your script. All functions must be declared inside the methods of the vue instance

vue.js - escape html inside slot

I am currently working on a component that looks like this:
<pre v-highlightjs>
<code>
<slot></slot>
</code>
</pre>
So the problem I have is that when I am writing html inside the slot, this html is rendered and not shown as a string or code-sample in my case. I have tested it with escaped < and > and it works. How can I access the html inside the slot and escape it automatically?
Thank you
EDIT:
I use highlight.js for that component to highlight the code inside my component. highlight.js can highlight html aswell. When I put e.g.
<html><head></head><body></body></html>
inside my slot, the box is shown, but the input is rendered as html. So I want to escape the html-Tags (and other code-snippets) so that it is shown and ofc highlighted. Hope that specifies my problem a bit more.
An important limitation to be aware of is that your HTML is not HTML, it is input to Vue's templating engine, so what a component sees in the slot may not be exactly what is in the HTML file.
Writing a directive to take HTML content and replace it with a text version of that content is pretty straightforward. Putting that in a component is also pretty straightforward. You can see these together in the snippet below.
What you will also see is that the Vue templating engine strips out tags that shouldn't be inside the body: the html, head, and body tags don't make it to the component. Their contents, if any, remain.
If it is important to be able to use those tags (or, for that matter, possibly invalid HTML), you will not be able to do it in a slot. You will need to have the HTML as a data string, which you can easily interpolate using the normal curlies.
new Vue({
el: '#app',
data: {
headContent: 'Something in the head'
},
components: {
htmlEscaper: {
template: '#html-escaper',
directives: {
escapeContent: {
bind(el) {
const html = el.innerHTML;
el.textContent = html;
}
}
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<html-escaper>
<html>
<head>
{{ headContent }}
</head>
<some-junk>
Custom tags are ok
</some-junk>
<body>
<div>This part is legit</div>
</body>
</html>
</html-escaper>
</div>
<template id="html-escaper">
<code v-escape-content>
<slot>
</slot>
</code>
</template>

Get element content without displaying on page in Polymer

I am building a custom element with Polymer 1.0 and need to get the content inside the tag using javascipt without it being displayed on the page. I tried using the <content> tag and fetching it inside the javascript with a query selector. This works except it displays on the page even if I use a style="display: none;" attribute. How can I get the content inside the tag without it displaying on the page?
Not sure what exactly your use-case is, but how about simply wrapping your <content> tag with a hidden <div>?
<dom-module id="x-test">
<template>
<div hidden>
<content id="content"></content>
</div>
</template>
<script>
Polymer({
is: "x-test",
attached: function () {
// access distributed content like this
var myContent = Polymer.dom(this.$.content).getDistributedNodes();
}
});
<script>
</dom-module>

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