Using polymer with external js files - polymer

I want to use trumbowyg.js in my polymer element, it includes jquery.js and trumbowyg.js. It works fine in Firefox but not in chrome.
It gives error, may be because shadow dom lookup/separation in chrome. The error happens where ever trumbowyg.js uses "this".
Whats going wrong here? What should I do differently?
I am using Polymer 2.0
error:
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
at trumbowyg.js:1544
my-notes.html
<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="../bower_components/trumbowyg/trumbowyg.html">
<dom-module id="my-notes">
<template>
<link rel="stylesheet" href="../bower_components/trumbowyg/dist/ui/trumbowyg.min.css">
<firebase-auth user="{{user}}" signed-in="{{signedIn}}"></firebase-auth>
<div class="card">
<div id="trumbowygd">hello</div>
</div>
</template>
<script>
class MyNotes extends Polymer.Element {
static get is() { return 'my-notes'; }
static get properties() {
return {
user: {
type: Object,
observer: '_shownotearea'
},
};
}
_shownotearea(){
var myFineElement = this.$.trumbowygd;
myFineElement.innerHTML="hello nice meeting you";
$(myFineElement).trumbowyg({});
}
</script>
</dom-module>
trumbowyg.html
<script src="../jquery/dist/jquery.min.js"></script>
<script src="dist/trumbowyg.js"></script>
This doesnt seem to be working
jQuery plugins and Polymer elements

The short answer is this plugin probably won't work with native Shadow DOM.
Likely trumbowyg is trying to query the document to look for some element. Shadow DOM creates markup encapsulation so you can't use $() or document.querySelector to look for things inside of shadow roots. In general I recommend not using jQuery plugins inside of Shadow DOM for this reason.

Related

Polymer2.0- Trying to download DIV content of custom element

I am trying to download div content of custom element using document.getElementById of the div and trying to implement download option from the JS FIddle - http://jsfiddle.net/evx9stLb/
From console, I am getting below error
pen.js:6 Uncaught TypeError: Cannot read property 'innerHTML' of null
at download (pen.js:6)
at HTMLButtonElement.onclick (index.html:15)
HTML:
<head>
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-collapse/iron-collapse.html">
</head>
<body>
<x-foo></x-foo>
<button onClick="download()">Download</button>
<dom-module id="x-foo">
<template>
<button on-click="toggle">toggle collapse</button>
<div id="content">
<iron-collapse id="collapse">
<div>Content goes here...</div>
</iron-collapse>
</div>
</template>
</dom-module>
</body>
JS:
function download(){
var a = document.body.appendChild(
document.createElement("a")
);
a.download = "export.html";
a.href = "data:text/html," + document.getElementById("content").innerHTML;
a.click();
}
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
static get properties() {
return {};
}
toggle() {
this.$.collapse.toggle();
}
}
customElements.define(XFoo.is, XFoo);
Code which I am below - https://codepen.io/nagasai/pen/ZyRKxj
Make some updates, and help this would help,
HTML
<head>
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-collapse/iron-collapse.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<button on-click="download">Download</button>
<button on-click="toggle">toggle collapse</button>
<div id="content">
<iron-collapse id="collapse">
<div>Content goes here...</div>
</iron-collapse>
</div>
</template>
</dom-module>
</body>
JS
class XFoo extends Polymer.Element {
static get is() { return 'x-foo'; }
static get properties() {
return {};
}
toggle() {
this.$.collapse.toggle();
}
download(){
var a = document.body.appendChild(
document.createElement("a")
);
a.download = "export.html";
a.href = "data:text/html," + this.$.content.innerHTML;
a.click();
console.log(this.$.content.innerHTML);
}
}
customElements.define(XFoo.is, XFoo);
https://codepen.io/renfeng/pen/BZOQro
a document query (on light dom) won't pierce the shadowDom. To do that you have to specifically select the element and query it's shadowRoot.
it would look something like this
a.href = "data:text/html," + document.getElementsByTagName('x-foo')[0].shadowRoot.querySelector('#content').innerHTML;
BUT only do this if you can't modify the element itself. It's not nice to stir around in someone else's shadowRoot.
As shown by Frank R. its far better to modify the element itself and provide a download functionality.
You can trigger this easily from an external element with something like
document.getElementsByTagName('x-foo')[0].download();
DOM under the shadow Root, or the shadow DOM, can not be accessed via innerHTML. It is not supposed to be. Just the way it is.
So, No, you simply can not get the shadow DOM contents via innerHTML.
There used to be access now deprecated to shadowDOM via vanilla javascript earlier
and also discussed here
However, with shadow DOM V1 beig the norm now, you may have to just wait and watch if you can pierce the shadowDOM
An alternative would be, to move your entire DOM in the custom element, outside of it, Using Slots.
Slots distribute content, so, the page that uses your element, can access it via innerHTML.
You could possibly try hacky ways like the one mentioned here

Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'paper-button'

I'm using polymer 1.2.1
I'm trying to create two polymer elements paper-button & paper-input.
I had imported following in head
<script src="third-party/js/bower/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="third-party/html/bower/polymer/polymer.html">
<link rel="import" href="third-party/html/bower/paper-button/paper-button.html">
<link rel="import" href="third-party/html/bower/paper-input/paper-input.html">
and added following in body
<paper-button>Flat button</paper-button>
<paper-button raised>Raised button</paper-button>
<paper-button noink>No ripple effect</paper-button>
<paper-button toggles>Toggle-able button</paper-button>
<paper-input label="total">
<div prefix>$</div>
<paper-icon-button suffix icon="clear"></paper-icon-button>
</paper-input>
<script>
Polymer({
is: "paper-button",
// add a callback to the element's prototype
created: function() {
console.log("inside pol1");
this.textContent = "I'm a proto-element!"
}
});
Polymer({
is: "paper-input",
// add a callback to the element's prototype
created: function() {
console.log("inside pol2");
this.textContent = "I'm a proto-elemente2!"
}
});
</script>
I'm expecting a change in text of respective elements with some console but none of these happens. I get an error saying
"Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'paper-button'. A type with that name is already registered."
I'm not quite sure what you are trying to achieve, but the answer to your question is this:
Your paper-input and paper-button have already been registered into Polymer by your <link rel="import"> tags in your <head> section, so naturally when you try to re-register them using Polymer({is:"paper-button"...}), it fails...
I also wouldn't recommend overriding a packaged element's created() callback - if you want to do your own custom tasks, create a new custom element that wraps your target element, and then call your new element instead.

How to force Polymer to use polyfill

Since Polymer 1.0 release I start to get a different initialization order between Chrome and other browsers (Firefox, barebone WebKit). Although the 1.0 docs say "there are no guarantees with regard to initialization timing", in version 0.5 I didn't have such issue.
index.html:
<script src="components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="name-tag.html">
<body onload="console.log('body onload');">
<name-tag></name-tag>
</body>
name-tag.html:
<link rel="import" href="components/polymer/polymer.html">
<dom-module id="name-tag">
<template></template>
<script>
Polymer({
is: "name-tag",
ready: function() {
console.log("polymer ready");
}
});
</script>
</dom-module>
Chrome 44:
polymer ready
body onload
Firefox 39, QWebView (Qt5.4, WebKit):
body onload
polymer ready
What I have already tried:
window.WebComponents = {flags: {register: true, polyfill: true}}; (register used to be in Polymer)
window.Polymer.Settings = {useNativeShadow: false};
attached callback with this.async()
window.Polymer.dom = 'shadow' forces Polymer to use the shadow DOM by default (either the polyfilled one if you used webcomponents.js or natively if you used webcomponents-lite.js instead).

Dart - Referencing outer HTML div using querySelector from Polymer class

I'm trying to get a reference of outer HTML(index.html)'s div from the polymer dart class. I know I can query the reference of app_element.html's div by the following code:
shadowRoot.querySelector('#select_this')
However, if I were to get a reference of index.html's div (#select_this), how can I do that from app_element.dart class? Is this even possible? If not, how can I design the polymer elements so that it can access DOM of other HTML pages and not only the ones that bind that particular polymer element?
app_element.dart
#CustomTag('app-element')
class AppElement extends PolymerElement {
#override
void attached() {
var my_div = shadowRoot.querySelector('#select_this'); // contains app_element.html's #select_this div
}
}
index.html
<html>
<body>
<head>
<link rel="import" href="../lib/app_element.html">
</head>
<app-element></app-element>
<div id="select_this"></div> <!-- Not sure how to select this... -->
<script type="application/dart">export 'package:polymer/init.dart';</script>-->
<script src="packages/browser/dart.js"></script>
</body>
</html>
app_element.html
<!DOCTYPE html>
<polymer-element name='app-element'>
<div id="select_this"> <!-- selectable via: shadowRoot.querySelector('#select_this') -->
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>
Use the documents querySelector instead:
import 'dart:html';
...
document.querySelector('#select_this');
You can get access to elements within other elements shadow DOM
// old
document.querySelector('* /deep/ #select_this');
// or new (probably not yet supported everywhere
document.querySelector('* >>> #select_this');

Polymer: how to parse the index to the elements using template repeat

I've been trying to use Polymer for a project I'm working on. And although I enjoyed it quite a lot so far, I ran into a problem I just can't solve.
I dumped it down to a simple example. Basically it's just a list element (item-list) that contains item elements (item-card) and i want to parse the items position to the element via the attribute pos. But for some reason the items attribute is allways undefined! Is this because the attribute is bound to the variable i, which dies after the template repeat? If so, how do I work around it? Is there a different approach I should be using here?
SOLUTION: You can find the solution by reading through all the comments, but to sum it up: apperantly there was a timing issue and the attribute wasn't ready at the ready callback. But I found out about the domReady callback (polymer lifecycle documentation). Using domReady it works just fine! Thanks to Günter Zöchbauer for the help!
This is the item-list.html:
<link rel="import" href="components/polymer/polymer.html">
<link rel="import" href="item-card.html">
<polymer-element name="item-list">
<template>
<style>
</style>
<template repeat="{{values, i in data.data}}">
<item-card pos="{{i}}"></item-card>
</template>
</template>
<script>
Polymer({
created: function()
{
this.num = 123456;
this.data = { "data":
[
{
"value":999
},
{
"value":666
},
{
"value":555
},
{
"value":222
}
]
};
}
});
</script>
</polymer-element>
This is the item-card.html
<link rel="import" href="components/polymer/polymer.html">
<polymer-element name="item-card" attributes="pos">
<template>
<style>
</style>
</template>
<script>
Polymer({
ready: function()
{
console.log("ready: " + this.pos);
}
});
</script>
</polymer-element>
I didn't bother putting the index.html in, since it just containts one item-list element.
Thanks alot!!
I think you need a pos field in <item-card> in addition to the attributes="pos" declaration.
The repeated element also references the bound model which can be accessed like querySelector('item-card').templateInstance.model property.
See https://github.com/PolymerLabs/polymer-selector/blob/master/polymer-selector.html#L286 for an example.
Info:
According to the comments it turned out to be a timing issue. The value wasn't yet assigned when the ready callback was called but using domReady worked.