I want to make a web component tag which consists of an editor with some added functionality. I am using ACE-JSON editor for now.
The main code is this, i do have some other js file with it.
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor</title>
<meta charset="utf-8">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="app.js"></script>
<!-- <script src="worker.js"></script> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
html,
body {
font: 11pt sans-serif;
}
#jsoneditor {
width: 700px;
height: 600px;
}
#paste,
#link,
#file {
margin-top: 25px;
align-content: center;
}
</style>
</head>
<body>
<div class="container-fluid">
<h1 align="center">Load and save JSON documents</h1>
<br><br><br>
<div class="row">
<div class="col">
<div id="jsoneditor"></div>
</div>
<div class="col col-centered">
<div class="row">
<div class="col">
<select id="test" name="form_select" onchange="showDiv(this)">
<option value="paste">paste json</option>
<option value="file">Upload file</option>
<option value="link">use link</option>
</select>
</div>
<div class="col">
<p>
Save a JSON document: <input type="button" id="saveDocument" value="Save" />
</p>
</div>
</div>
<div class="row">
<div class="col">
<div id="file" style="display: none;" class="col-sm col-centered">
Load a JSON document: <input type="file" id="loadDocument" value="Load" />
<button class="button" onclick="readFile()">LOAD JSON</button>
</div>
<div id="paste" style="display: none;" class="col-sm col-centered">
<h3>Paste JSON data </h3>
<textarea id="myText" rows="4" cols="50"></textarea>
<button class="button" onclick="loadText()">LOAD JSON</button>
</div>
<div id="link" style="display: none;" class="col-sm col-centered">
<h3>URL</h3>
<input type="text" id="url">
<button class="button" onclick="urlOnclick()">LOAD JSON</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
var options = {
mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
onError: function (err) {
alert(err.toString());
},
onModeChange: function (newMode, oldMode) {
console.log('Mode switched from', oldMode, 'to', newMode);
}
};
// create the editor
var editor = new JSONEditor(document.getElementById('jsoneditor'), options);
// Save a JSON document
document.getElementById('saveDocument').onclick = function () {
// Save Dialog
fname = window.prompt("Save as...");
// Check json extension in file name
if (fname.indexOf(".") == -1) {
fname = fname + ".json";
} else {
if (fname.split('.').pop().toLowerCase() == "json") {
// Nothing to do
} else {
fname = fname.split('.')[0] + ".json";
}
}
var blob = new Blob([editor.getText()], { type: 'application/json;charset=utf-8' });
saveAs(blob, fname);
};
</script>
</html>
How can I wrap it up in a web-component? I tried it with JS but most of the tutorials were giving a small example of a simple tag. Most of the site was pointing towards polymer, but I didn't find any proper reference of what I want to do. please can you guide me or provide m some reference for it.
Third party libraries are usually not designed to be used with Web Components.
The problem you are going to run into is the use of jQuery and the jQuery plugins. When you create a Web Component you are creating a #document-fragment
in a #shadowRoot
component in the shadowDOM
. What all that means is the standard DOM statements we use to select elements (document.getElementById(...)
) won't work to select elements in the shadowDOM
. That's because the shadowDOM
is isolated from the root document. That's why you only find examples of simple tags.
JSONEditor, for example, uses document.createElement()
extensively.
I've converted your HTML/JS into a Web Component that won't work for the reasons stated above. This will at least show you how to proceed with a more complex example.
As you can see in the sample below, external scripts and stylesheets are easily loaded into the component. Module import
syntax can be used rather than creating script tags, but these libraries don't support that syntax.
Here are the key moving parts:
<template>
tag which is used to hold the DOM elements of the custom elementcustomElements.define('my-editor', MyEditor);
<my-editor></my-editor>
into the HTML fileRefer to the source code comments for details.
class MyEditor extends HTMLElement {
constructor () {
super();
this.requiredScripts = [
'https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js',
'https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.js',
'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js',
];
// Grab a reference to the custom element
let template = document.getElementById('my-custom-editor');
// Get the #document-fragment
let templateContent = template.content;
// Place the template from the Web Component in to the active DOM
this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
}
// lifecycle hook that fires when custom element is placed into DOM
connectedCallback () {
// load required external resources
this.loadScripts(0);
}
loadScripts (idx) {
const tag = document.createElement('script');
tag.src = this.requiredScripts[idx];
tag.onload = () => {
if (idx < this.requiredScripts.length - 1) {
// when a script has finished, go get the next one
this.loadScripts(++idx);
} else {
// Once all the script files are loaded, initialize the working parts of the component
this.initEditor();
}
}
tag.onload.bind(this);
document.head.appendChild(tag);
}
initEditor () {
// Need a reference to the #document-fragment
// Every instance of "document" in this method has been replaced with "component"
const component = document.getElementById('my-custom-editor').content;
const options = {
mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
onError: function (err) {
alert(err.toString());
},
onModeChange: function (newMode, oldMode) {
console.log('Mode switched from', oldMode, 'to', newMode);
}
};
// create the editor IN THE compoent (rathar than the DOM)
var editor = new JSONEditor(component.getElementById('jsoneditor'), options);
component.getElementById('saveDocument').onclick = function () {
fname = window.prompt("Save as...");
if (fname.indexOf(".") == -1) {
fname = fname + ".json";
} else {
if (fname.split('.').pop().toLowerCase() == "json") {
} else {
fname = fname.split('.')[0] + ".json";
}
}
var blob = new Blob([editor.getText()], {
type: 'application/json;charset=utf-8'
});
saveAs(blob, fname);
};
}
}
customElements.define('my-editor', MyEditor);
html,
body {
font: 11pt sans-serif;
}
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor</title>
<meta charset="utf-8">
<link href="styles.css" rel="stylesheet">
<script defer src="lib/MyEditor.js"></script>
<!-- <script src="app.js"></script> -->
<!-- <script src="worker.js"></script> -->
</head>
<body>
<my-editor></my-editor>
<template id="my-custom-editor">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
#jsoneditor {
width: 700px;
height: 600px;
}
#paste,
#link,
#file {
margin-top: 25px;
align-content: center;
}
</style>
<div class="container-fluid">
<h1 align="center">Load and save JSON documents</h1>
<br><br><br>
<div class="row">
<div class="col">
<div id="jsoneditor"></div>
</div>
<div class="col col-centered">
<div class="row">
<div class="col">
<select id="test" name="form_select" onchange="showDiv(this)">
<option value="paste">paste json</option>
<option value="file">Upload file</option>
<option value="link">use link</option>
</select>
</div>
<div class="col">
<p>
Save a JSON document: <input type="button" id="saveDocument" value="Save"/>
</p>
</div>
</div>
<div class="row">
<div class="col">
<div id="file" style="display: none;" class="col-sm col-centered">
Load a JSON document: <input type="file" id="loadDocument" value="Load"/>
<button class="button" onclick="readFile()">LOAD JSON</button>
</div>
<div id="paste" style="display: none;" class="col-sm col-centered">
<h3>Paste JSON data </h3>
<textarea id="myText" rows="4" cols="50"></textarea>
<button class="button" onclick="loadText()">LOAD JSON</button>
</div>
<div id="link" style="display: none;" class="col-sm col-centered">
<h3>URL</h3>
<input type="text" id="url">
<button class="button" onclick="urlOnclick()">LOAD JSON</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</body>
</html>