how can i select an element in a template within a web component using vanilla javascript? - javascript

I'm having the hardest time selecting the ".recipe-type-menu-container" within the template in this component I built. I've tried using:
const container = typeofRecipe_template.content.querySelector(".recipe-type-menu-container");
but I keep getting an undefined error message. I'm trying to do all this with vanilla JS.
export class TypeofRecipe extends HTMLElement{
constructor(){
super();
} // end of constructor()
connectedCallback(){
var container;
var typeofRecipe_template = document.createElement('template');
typeofRecipe_template.innerHTML = `
<div class="recipe-type-menu-container" >
<div class="recipe-type-menu-row"></div>
<div class="recipe-type-menu-row"></div>
</div> <!---recipe-type-menu-container ->
`;
const container = typeofRecipe_template.content.querySelector(".recipe-type-menu-container");
this.parentNode.appendChild(typeofRecipe_template.content.cloneNode(true));
};
}

Related

Problem with using template on customElement together with <slot>

I'm trying to learn more on how to work with customElements and looking in to using together with it. When I'm trying to use with and surrounding the by another element the DOM seems to no look as expected, the shadowRoot is not getting the content for ?
I would love to know what I'm doing wrong and what is going on here? Hope the question makes sense!
Best regards
The customElement
customElements.define(
'test-element',
class extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow( {mode: 'open'} );
}
connectedCallback() {
this.shadow.appendChild(this._template().cloneNode(true));
}
_template() {
let template = document.createElement('template');
template.innerHTML = `
<div class="surrounding-element">
<slot name="content"></slot>
</div>
`;
return template.content;
}
}
)
In the rendered DOM
<test-element>
#shadow-root
<div class="surrounding-element">
<slot name="content"></slot>
</div>
<div slot="content" class="non-template">
<p>Some kind of content!</p>
</div>
</test-element>
I have been trying to using , and customElements together to have more control of where the content is put, and I would like to be able to wrap the content given to .

Javascript Class Inheritance not working as it should

Trying to create some Javascript classes and parent classes, and not sure if I'm doing this correctly, but super() in the child class isn't working as it should. Trying to get content in DivElement to work, but it keeps returning undefined.
Code:
class HTMLElement{
constructor(tag, content){
this.tag = tag;
this.content = content;
}
render(){
return `<${this.tag}>${this.content}</${this.tag}>`;
}
class DivElement extends HTMLElement{
constructor(content){
super(content);
this.tag = 'div';
}
}
let div1 = new DivElement('test');
console.log(div1);
console.log(div1.render());
The super call should match the signature of the target method. It should read super('div', content);:
class HTMLElement{
constructor(tag, content){
this.tag = tag;
this.content = content;
}
render(){
return `<${this.tag}>${this.content}</${this.tag}>`;
}
}
class DivElement extends HTMLElement{
constructor(content){
super('div', content); // changed here
this.tag = 'div';
}
}
let div1 = new DivElement('test');
console.log(div1);
console.log(div1.render());
// <div>test</div>
The constructor of the HTMLElement class is called with two parameters (tag & content). The extended class calls the constructor with only one parameter and assigns content to the tag parameter of the parent class. Note that JS does not allow constructor overloading.
See the answer of Glycerine.

datepicker as custom-calendar using native-web component

I wanted to use native web in order to have custom calendar. I created js file and wrote some class that extends HTMLElement. Calendar pops up properly but the problem is that I can't choose a day in the calendar. When I try to choose a date It throws this exception : "Uncaught Missing instance data for this datepicker".
My code looks like this :
class CustomCalendar extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({mode: 'open'});
const wrapper = document.createElement('div');
wrapper.setAttribute('class', 'wrapper');
const calendarInputLabel = wrapper.appendChild(document.createElement('label'));
calendarInputLabel.setAttribute('class', 'date-label');
const iconImg = calendarInputLabel.appendChild(document.createElement('img'));
iconImg.setAttribute('class', 'calendarIcon');
iconImg.src = this.hasAttribute('iconImgSrc') ? this.getAttribute('iconImgSrc') : 'api/theme/img/icons-calendar.png';
const calendarInput = calendarInputLabel.appendChild(document.createElement('input'));
calendarInput.setAttribute('type', 'text');
calendarInput.setAttribute('id', this.getAttribute('calendarName'));
shadowRoot.append(wrapper);
}
connectedCallback() {
$(this.shadowRoot.getElementById('from')).datepicker({
dateFormat: "dd-mm-yy"
, duration: "fast"
});
}
}
customElements.define('custom-calendar', CustomCalendar);
<custom-calendar calendarName="from"> </custom-calendar>
please help me. How can I fix this ?

How to render a mermaid flowchart dynamically?

I am using the mermaid library to build flowcharts. The principle of its work is that inside a block there is a pseudocode - commands of a special syntax, on the basis of which the flowchart is built in the block.
I want to be able to change the contents of the block dynamically, and the script rebuilds the block diagram every time.
How should I set up initialization? Perhaps I should add some callback function in the settings?
I initialized in this way:
mermaid.init({/*what setting parameters should be here?*/}, ".someClass"/*selector*/);
but the script doesn’t render any new commands. It only renders the commands that existed at the moment the document was loaded.
In other words, I want to edit a flowchart online.
function edit() {
const new_mermaid = document.createElement("div");
new_mermaid.classList.add("mermaid");
new_mermaid.classList.add(".someClass");
/*new_mermaid.innerHTML =
`graph TD
1[point 1] --> 2[point 2]`;*/
// it doesn't work when I append the new element dynamically!
new_mermaid.innerHTML = document.querySelector(".mermaid").innerHTML;
// it works always.
document.body.append(new_mermaid);
/* document.querySelector(".mermaid").innerHTML =
`
graph TD
A --> B`*/
// it doesn’t work with event listener
}
edit(); // it works
document.body.addEventListener("click", edit)
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
// how to do it correctly?
mermaid.init({
noteMargin: 10
}, ".someClass");
</script>
<div class="mermaid someClass">
graph TD
1--> 2
3 --> 2
2 --> 1
</div>
It seems, I know the answer. Look at the solution below:
document.querySelector("button").addEventListener("click", (e) => {
const output = document.querySelector(".flowchart");
if (output.firstChild !== null) {
output.innerHTML = "";
}
const code = document.querySelector(" textarea").value.trim();
let insert = function (code) {
output.innerHTML = code;
};
mermaid.render("preparedScheme", code, insert);
});
<script src="https://unpkg.com/mermaid#7.1.0/dist/mermaid.min.js"></script>
<p>Input your data:</p>
<div class="input">
<textarea style="width:300px; height:200px"></textarea>
<br>
<button>render</button>
</div>
<div>
<p>output:</p>
<div class="render_container" style = "width:300px; height:200px; border:thin solid silver" >
<div class="flowchart"></div>
</div>
</div>
Thanks for the answer above. I would like to add a react wrapper to the answer scope for whoever using react:
import React, {Component} from "react";
import mermaid from "mermaid";
export default class Mermaid extends Component {
constructor(props){
super(props)
this.state={
chart: this.props.chart || ""
}
mermaid.initialize({
mermaid : {
startOnLoad: false,
}
})
this.mermaidRef = React.createRef()
}
mermaidUpdate(){
var cb = function (svgGraph) {
this.mermaidRef.current.innerHTML = svgGraph
};
//console.log("this.state.chart", this.state.chart)
mermaid.mermaidAPI.render('id0', this.state.chart, cb.bind(this));
}
componentDidMount(){
this.mermaidUpdate()
}
componentDidUpdate(prevProps, prevState) {
//console.log("Mermiad prevProps.chart", prevProps.chart)
if (this.props.chart !== prevProps.chart) {
this.setState({chart:this.props.chart},()=>{
this.mermaidUpdate()
})
}
}
render() {
var outObj = (
<div
ref={this.mermaidRef}
className="mermaid"
>
{this.state.chart}
</div>
)
return outObj
}
}

Create HTML Element with ES6

For an application i want to create Object-Based components in ES6.
On the normal way, you can create Elements as follow:
var element = document.createElement('YourElement');
element.innerHTML = 'Content';
document.querySelector('body').appendChild(element);
How i can create these in ES6 like:
export default class Container extends HTMLDivElement {
constructor() {
super();
this.innerHTML = 'Content';
}
}
With these example?
var container = new Container();
document.querySelector('body').appendChild(container);
My idea is, to create an -only JavaScript- UI Framework, without using "native" HTML snippets...
<div class='body'>
</div>
<script>
class Container extends HTMLElement {
constructor() {
super();
console.log( 'Constructed' )
}
connectedCallback() {
console.log('Callback');
this.innerHTML = "Content";
}
}
customElements.define('my-contain', Container);
let container = new Container();
document.querySelector('.body').appendChild(container);
</script>
You need to register your Component with the CustomElementRegistry below your Class definition and utilize the connectedCallback().
export default class Container extends HTMLDivElement {
constructor() {
super();
this.innerHTML = 'Content'; // Does Nothing
}
connectedCallback() { // Fires when attached
console.log('Callback');
this.innerHTML = "Content";
}
}
customElements.define('my-contain', Container, { extends: "div" });
LIFECYCLE HOOKS OF CUSTOM COMPONENTS
More info on CustomElementRegistry here: MDN CustomElementRegistry
More info on implementation of such here: MDN Using Custom Elements

Categories