HTMl Import own WebComponent - javascript

In my index.html I import an external HTML file with an Template, Shadow DOM etc. A custom web Component.
// index.html
...
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.4/platform.js"></script>
<link rel="import" href="/html-components/userlogin-header.html" >
<head>
<body>
<userlogin-header username="Test User"userimage="http://domain.com/img.jpg"></userlogin-header>
...
And the other file userlogin-header.html:
// userlogin-header.html
<template id="userlogin-header">
<div class="imgbox">
<img src="" class="userimage">
</div>
<div class="userinfo">
<div class="name"><span class="username"></div>
</div>
</template>
<script>
var doc = this.document.currentScript.ownerDocument,
UserLoginProto = Object.create( HTMLElement.prototype );
UserLoginProto.createdCallback = function() {
var template = doc.querySelector( "#userlogin-header" ),
box = template.content.cloneNode( true );
this.shadow = this.createShadowRoot();
this.shadow.appendChild( box );
var username = this.shadow.querySelector( '.userinfo .username' );
username.innerHTML = ( this.getAttribute( 'username' ) || 'Unbekannt' );
var imageurl = this.shadow.querySelector( 'img.userimage' );
imageurl.src = 'https://secure.gravatar.com/avatar/' + this.getAttribute( 'userimage' ) + '1?s=40&d=http://s3-01.webmart.de/web/support_user.png';
};
var Xuserlogin = doc.registerElement( 'userlogin-header', { 'prototype' : UserLoginProto } );
</script>
The problem is that there is the following error on call index.html
Uncaught TypeError: Cannot read property 'content' of null
If I enable HTML Import in my Chrome everything works correctly. But then I disable this and use platform.js instead there is this error.
Is there any solution for this problem? I do not want to use the whole polymer framework.

This is a symptom of this caveat of the polyfill.
In a native HTML Imports, document.currentScript.ownerDocument
references the import document itself. In the polyfill use
document._currentScript.ownerDocument (note the underscore).
Once you change that, you also need to use document.registerElement instead of doc.registerElement. You want to register the element such that it's visible to the importing document, not the imported one.
var Xuserlogin = document.registerElement(...);
Here's a working plunk.

Related

Embed SharpSpring form into React component

I'm trying to embed a Sharpspring form script into my React (page.jsx) component. For this form to load succesfully it needs to be placed outsite the <head></head> element, and inside the <div> where I want to display the form.
The original HTML code I need to embed looks like this:
<!-- SharpSpring Form -->
<script type="text/javascript">
var ss_form = {'account': 'MzawMDE3tzQzBQ', 'formID': 'szBIMrFMSzbXTUm0TNM1MTc107VMNbfQTTRJTExOTUoySk4zAA'};
ss_form.width = '100%';
ss_form.domain = 'app-3QNK98WC9.marketingautomation.services';
// ss_form.hidden = {'field_id': 'value'}; // Modify this for sending hidden variables, or overriding values
// ss_form.target_id = 'target'; // Optional parameter: forms will be placed inside the element with the specified id
// ss_form.polling = true; // Optional parameter: set to true ONLY if your page loads dynamically and the id needs to be polled continually.
</script>
<script type="text/javascript" src="https://koi-3QNK98WC9.marketingautomation.services/client/form.js?ver=2.0.1"></script>
I'm trying to embed it into page.jsx this way:
import React from "react";
function myComponent() {
var ss_form = {'account': 'MzawMDE3tzQzBQA', 'formID': 'szBIMrFMSzbXTUm0TNM1MTc107VMNbfQTTRJTExOTUoySk4zAAA'};
ss_form.width = '100%';
ss_form.domain = 'app-3QNK98WC9Y.marketingautomation.services';
return (
<main>
<div className="form">
{ss_form}
<script src="https://koi-3QNK98WC9Y.marketingautomation.services/client/form.js?ver=2.0.1" type="text/javascript" />
</div>
</main>
);
}
export default myComponent;
However, I get this error:
Error: Objects are not valid as a React child (found: object with keys {account, formID, width, domain}). If you meant to render a collection of children, use an array instead.
I know I'm supposed to use "arrays instead" but I could not find any documentation that solved this error. Any suggestions on how I could make this embed code to work?
Thank you.
I was able to embed the form using helmet.
First installed:
npm install helmet
My working code looks like this:
import React from "react";
import ReactDOM from "react-dom";
import { Helmet } from 'react-helmet';
function myComponent() {
return (
<main>
<Helmet>
<script
src="https://koi-3QNK98WC9.marketingautomation.services/client/form.js?ver=2.0.1"
/>
<script>
{`
var ss_form = {'account': 'MzawMDE3tzQzBQ', 'formID': 'szBIMrFMSzbXTUm0TNM1MTc107VMNbfQTTRJTExOTUoySk4zAA'};
ss_form.width = '100%';
ss_form.domain = 'app-3QNK98WC9Y.marketingautomation.services';
ss_form.target_id = 'form';
ss_form.polling = true;
`}
</script>
</Helmet>
<div id="form"> </div>
</main>
);
}
export default myComponent;
Turns out SharpSpring embed code supports the variant ss_form.target_id, which displays the form on the designated ID.
I'm sure the above solution will work for other javascripts and embed codes as well.

Access variables defined in <head> or external script from React component

I am integrating a third-party library into my React app.
They provide this script I need to add to my <head>:
index.html
<head>
<script>
var externalVariable1 = externalVariable1 || {};
var externalVariable2 = externalVariable2 || {};
</script>
// tag.min.js gives value to these variables
<script async src="//example.com/tag.min.js"></script>
</head>
I need to use access these two variables from my component. I tried the following but I get 'externalVariable1' is not defined error. Any thoughts?
MyScreen.js
import React from 'react';
const MyScreen = () => {
return (
<React.Fragment>
<div>
<h2>Hello!</h2>
</div>
<div id='myId'>
{externalVariable.push(function() { externalVariable2.display();})}
</div>
</React.Fragment>
);
}
export default MyScreen;
If you want to access variables defined in the global scope from inside of a React component, you can typically do that by accessing the variable through the window object.
See the example below:
function App(){
return <h1>The secret is {window.secret}</h1>
}
ReactDOM.render(<App />, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- Adding some global variables outside of React -->
<script>
var secret = "hello";
</script>
<div id="root"></div>

how to queryselector a template object from javascript

Basically, I want to querySelect a <template> from javascript and I keep getting null.
JavaScript file:
class MyImportWebcomponent extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: "open" });
const template = document.querySelector("my-import-webcomponent-template");
const instance = template.content.cloneNode(true);
shadowRoot.appendChild(instance);
}
}
customElements.define("my-import-webcomponent", MyImportWebcomponent);
Template object from my vanilla webcomponent
<template id="my-import-webcomponent-template">
<div id="mydiv" name="mydiv">
<p>Trying html importing another javascript file</p>
</div>
</template>
<script src="/to-try/my-import-webcomponent.js"></script>
index.html
<my-import-webcomponent></my-import-webcomponent>
<link rel="import" href="./to-try/my-import-webcomponent.html" />
The main issue is that document.querySelector("my-import-webcomponent-template") returns undefinied.
IN case it adds something usefull, if I try keep both javascript and html in same file and instead of querySelector I create straight the element, I successfully can do it.
All in a single file
const templateString = `<div id="mydiv" name="mydiv"><p>Trying html plus javascript in same file</p></div>`;
const template = document.createElement("template");
template.innerHTML = templateString;
export class MyCompleteWebcomponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define("my-complete-webcomponent", MyCompleteWebcomponent);
My question would be exact the same as queryselector if it wasn't for two reasons: (1) they seemed to rely on Polifys which it isn't my case and (2) the answer accepted is based on document.currentScript.ownerDocument which demands an old library as far as I know.
*** edited after suggestion to use instead of
<!-- <link rel="import" href="./to-try/my-import-webcomponent.html" /> -->
<script type="module" src="./to-try/my-import-webcomponent.js"></script>
<my-import-webcomponent></my-import-webcomponent>
Nothing changed at all
*** edited after recommended to add "#". No changes at all
If you want to load HTML files with <link rel="import"> then you'll need to load the HTML Imports library before.
<script src="https://raw.githubusercontent.com/webcomponents/html-imports/master/html-imports.min.js"></script>
<link rel="import" href="./to-try/my-import-webcomponent.html">
...

Why isn't html running javascript I import when I use import-export

My code works fine when I add my module straight into the html code, but it won't load it when I try to first import the module to a different javascript file.
I've tried exporting everything, from my module.
HTML:
<html>
<head>
<title>
Hello world
</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Tradingpost, done by no css gang.</h1>
<div id="sidenav">Here be the links to other pages</div>
<br>
<footer id="footer">
Done whenever. Copyright is mine.
</footer>
<script src="js/app.js"></script>
</body>
</html>
app.js:
import * as sidebar from "./visualModules/sidebarmodule"
function cumulator() {
sidebar.createSidebar()
}
sidebarmodule.js:
function sidebarAdder(pages) {
const sidebar = document.getElementById("sidenav")
const list = document.createElement("UL")
for(index = 0; index < pages.length; index++) {
const ul = document.createElement("LI")
const a = document.createElement("A")
a.setAttribute("href", "/" + pages[index])
a.innerHTML = "" + pages[index]
ul.appendChild(a)
list.appendChild(ul)
}
sidebar.appendChild(list)
}
export function createSidebar() {
var pages = [
"home",
"tradingpost"
]
sidebarAdder(pages)
}
It should add elements to the div. But it wont do it unless I straight up use the sidebarmodule.js. I want to do it through the app.js
EDIT
Found the problem!
Didn't initialize index in the for loop.
EDIT2
And the type="module" which needed to be added
When you load your app.js in your html file, try to add:
<script type="module" src="js/app.js"></script>
That should work when you want to use ESModules. But please update us regardless :)
Update:
Ok after creating a project myself using your HTML and JS, I found a few errors.
First: When using ESModules, you can't use any functions in the JS through your HTML, you will have to inject everything from the app.js.
index.html:
<body>
<div id="sidenav">
Here be the links to other pages
</div>
<br>
<footer id="footer">
Done whenever. Copyright is mine.
</footer>
<script type="module" src="js/app.js"></script>
app.js:
import { createSidebar } from './visualModules/sidebarmodule.js';
cumulator();
function cumulator() {
createSidebar()
}
Notice two things: at the end of the import, since we are not using a compiler, the modules do not recognize files without their extension. So I had to add .js to sidebarmodule. Secondly, I had to invoke cumulator function within the app.js file (like I said earlier, you cannot use any module functions outside their scope. There are no global variables with ESModules).
sidebarmodule.js:
function sidebarAdder(pages) {
const sidebar = document.getElementById("sidenav")
const list = document.createElement("UL")
for(var index = 0; index < pages.length; index++) {
const ul = document.createElement("LI")
const a = document.createElement("A")
a.setAttribute("href", "/" + pages[index])
a.innerHTML = "" + pages[index]
ul.appendChild(a)
list.appendChild(ul)
}
sidebar.appendChild(list)
}
export function createSidebar() {
var pages = [
"home",
"tradingpost"
]
sidebarAdder(pages)
}
You did not declare index inside your for loop, so I just added a var.
Hope this helps.
import is asynchronous in Javascript (in a browser, not Node.js) so you're calling createSidebar() before the module is loaded. You can use import to return a promise so you can execute code once it is completed.
Remove the embedded Javascript from your html, but leave the link to app.js. Then change app.js to this...
import("./visualModules/sidebarmodule")
.then((sidebar) => {
sidebar.createSidebar();
});

div.getelementbyid(id).innerHTML = "" giving out error

I am facing an issue while setting the innerHTML of a div element to "". The element does exist when i first load it.
I use a drop down on my HTML page. On change in option i want to clear all the contents and replace it with new SVG elements.
Error: Uncaught TypeError: Cannot set property 'innerHTML' of null
I understand that the error is thrown because the Element it tries to retrieve is not found.
My question is: After initial load of the page, the element is created and the element "movieNetwork" has contents within it.
But when i a run the code to clear the innerHTML on change in dropdown options, it gives out Cannot set property 'innerHTML' of null error
Kindly let me know what might be the issue.
The below is the code snippet
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Customer Network</title>
<link rel="stylesheet" href="movie-network.css"/>
<link rel="shortcut icon" href="popcha.ico" type="image/x-icon">
<script type="text/javascript" src="movie-network.js"></script>
<script type="text/javascript" src="movieJson.js"></script>
<script>
// Sniff MSIE version
// http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/
var ie = ( function() {
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML='<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',all[0]
);
return v > 4 ? v : undef;
}() );
function takeAction() {
if( ie && ie < 9 ) {
D3notok();
} else {
// Load D3.js, and once loaded do our stuff
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "d3.v3.min.js";
script.addEventListener('load', D3ok, false);
script.onload = "D3ok();";
head.appendChild(script);
}
}
</script>
</head>
<body onload="takeAction();">
<div id ="selectoptionsMenu">
<select id="selectoption" onchange="changeGraph()">
<option value="eigen">Eigen Betweeness Centrality</option>
<option value="central">Eigen Centrality</option>
<option value="cluster">Cluster</option>
<option value="transaction">Transaction</option>
<option value="transaction">MediaSweep</option>
</select>
</div>
<div id="nocontent">
<h1>Sadly your browser is not compatible with this site</h1>
<div>You can use <a href="http://www.google.com/chrome/">Google
Chrome</a>, Mozilla Firefox
or <a href="http://windows.microsoft.com/en-us/internet-explorer/download-ie">Microsoft
Internet Explorer (v9 or above)</a> to access the PopCha Movie
Network</div>
</div>
<div id="movieNetwork"></div>
<div>
<script type="text/javascript">
function changeGraph()
{
document.getElementById(movieNetwork).innerHTML = ""; //ERROR
D3ok();
}
</script>
</div>
<div id="sidepanel">
<div id="title">
<br/>Customer Network<br/>
</div>
<div id="movieInfo" class="panel_off"></div>
</div>
</body>
</html>
Because you've written this line:
document.getElementById(movieNetwork).innerHTML = ""; //ERROR
... which is referencing a movieNetwork variable you never declared. So you're calling document.getElementById(undefined), which returns null, then effectively writing null.innerHTML = "";. Hence your Cannot set property 'innerHTML' of null error.
You probably need quotes around it:
document.getElementById("movieNetwork").innerHTML = "";
I believe you need to add quotes to the value in your getElementByID
change it to:
document.getElementById("movieNetwork").innerHTML = "";
Ok i did one hell of a stupid mistake.
I forgot the quotes and started looking at other section of the code for errors
document.getElementById("movieNetwork").innerHTML = "";
Should start listening to my dad and start wearing those glasses. Thank you guys for such a quick reply :)
The problem is you need to pass the id of the element to document.getElementById(), but you are passing a dom element reference(Since movieNetwork is the id of the element that gets copied as a property of the window object) so even if you have not declared movieNetwork that is referring to a dom element reference.
In your case you need to pass a string literal like
document.getElementById('movieNetwork')
Or in html5 browsers you could just say
movieNetwork.innerHTML = "";
movieNetwork should be a string. As movieNetwork is undefined, document.getElementById(movieNetwork) will just return null.
Working code:
function changeGraph()
{
// Changed movieNetwork to "movieNetwork".
document.getElementById("movieNetwork").innerHTML = "";
D3ok();
}
Note that the argument passed into document.getElementById() should always be a string.

Categories