Passing Objects in Native Web Components

I'm trying to learn Native Web Components and would love some help with this problem I'm facing. I'm trying to pass a simple object literal from the dispatch-data to the recieve-data component by listening to the event. However so some reason I can't get the recieve data to listen to the event using the this.addEventListener, but I can using the window object. so my question is... is there a way to pass an object from the parent to the child without using the window object? look forward to hearing solutions so I can get a good nights sleep! 🤣
16 Replies
Benji598
Benji598•8mo ago
Jochem
Jochem•8mo ago
you would have to call dispatchEvent on a reference to the child I'm not too familiar with the custom element API, you may be able to do a this.querySelector to get a reference to the child, then dispatchEvent on that basically, this.addEventListener will listen only to events fired on that specific element. So firing the event on the parent doesn't trigger the listener on the child, just like this.addEventListener('click') doesn't listen to events fired on the parent
Benji598
Benji598•8mo ago
Thank you for your speedy response... according to custom events the custom event is person-data and thats what the child listens for in the receive js so not quite sure what the crack is with it... I have even stuck it in ChatGPT and it says it should work but it doesn't haha! the only other way is to use this.parentNode.addEventListener so then it listens directly to the parent but I'm not sure if this is good practice?
Jochem
Jochem•8mo ago
the child listens to person-data events on itself though, and the event is firing on the parent effectively, you're clicking on a button on the right hand side of your screen and wondering why the click handler for a different button isn't firing (also, this is a nitpick and not related to the issue at hand probably, but that's something that will look sloppy on a portfolio or similar thing... it's Receive, not Recieve)
Benji598
Benji598•8mo ago
I know... its confused me to... listening on itself... but apparently its correct.... apparently you should be able to pass an object between the two components. hahah! its ok I already noticed, it not for a portfolio I already have a job as a FE dev... but I just want to keep expanding my knowledge.. and exposing myself to new tech.
Jochem
Jochem•8mo ago
ah 🙂 that's always a good idea! yeah, so, the event system in Javascript takes a bit of getting used to. Events fire on elements, that then bubble up to their parents (unless there's something stopping them). Window is the parent of everything, so eventually the event makes its way there, no matter where it's been fired
Benji598
Benji598•8mo ago
yeah exactly.... according to what I have read if the receive component is fired first and completes, before the dispatch event fires it should in "theory" catch the event..... if we change it to window.addEventListener the object gets passed... I was just trying to keep the components contained
Jochem
Jochem•8mo ago
have you tried this?
// Dispatch the event after the component is connected
this.querySelector('recieve-data').dispatchEvent(sendData);
// Dispatch the event after the component is connected
this.querySelector('recieve-data').dispatchEvent(sendData);
no idea if querySelector is available there, but that might work
Benji598
Benji598•8mo ago
hey i'm open to anything at this point, lets give it a go.... well you won't believe it! it works!!!!! nice one
Jochem
Jochem•8mo ago
cool!
Benji598
Benji598•8mo ago
how do you send code blocks on discord btw? I'll send the code
Javascript
const dispatch = document.createElement('template');

dispatch.innerHTML = `

`;

class Dispatch extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(dispatch.content.cloneNode(true));

document.createElement('dispatched-data').append('body');
}

connectedCallback() {
this.dispatchData();
}

dispatchData() {
console.log('disptached');
const person = {
name: 'Ben',
lastName: 'Hewart',
number: '+4412345678910',
};

const sendData = new CustomEvent('person-data', {
detail: person,
bubbles: true,
composed: true,
});

// Dispatch the event after the component is connected
const recieveComponent = this.querySelector('recieve-data');
if (recieveComponent) {
recieveComponent.dispatchEvent(sendData);
}
}
}

customElements.define('dispatch-data', Dispatch);
Javascript
const dispatch = document.createElement('template');

dispatch.innerHTML = `

`;

class Dispatch extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(dispatch.content.cloneNode(true));

document.createElement('dispatched-data').append('body');
}

connectedCallback() {
this.dispatchData();
}

dispatchData() {
console.log('disptached');
const person = {
name: 'Ben',
lastName: 'Hewart',
number: '+4412345678910',
};

const sendData = new CustomEvent('person-data', {
detail: person,
bubbles: true,
composed: true,
});

// Dispatch the event after the component is connected
const recieveComponent = this.querySelector('recieve-data');
if (recieveComponent) {
recieveComponent.dispatchEvent(sendData);
}
}
}

customElements.define('dispatch-data', Dispatch);
Jochem
Jochem•8mo ago
you add the abbreviation for the language just after the three ticks, so ```js would highlight as javascript
MarkBoots
MarkBoots•8mo ago
i was wondering, can't you extend the child component Class to the parent? then the child has access to it's parents methods and props (this would be the case with normal Classes)
Benji598
Benji598•8mo ago
You have to extend the HTMLElement in order to create the native web component e.g <dispatch-data> All custom elements need to have a - in then in order to order so they don't class with the reserved element name But your right you normal extend the parent class
MarkBoots
MarkBoots•8mo ago
okay, i thought you could just leave it as the way it was, only changing the class Recieve extends Dispatch {} and that by inheritence it will also extend the HTMLElement
Benji598
Benji598•8mo ago
Hmn.... That's interesting.... I never even thought of that..... Wonder if it will be worth giving a go Ok so I was wrong in the custom events.... I had misread that a custom event is what a normal event does and bubbles up so e.g. if a user clicked a button and you wanted the parent to catch that event and then do something with it..... to pass an object between components you would have to do this.....
const dispatch = document.createElement('template');

dispatch.innerHTML = `

`;

class Dispatch extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(dispatch.content.cloneNode(true));
}

connectedCallback() {
this.passDataToObject();
}

passDataToObject() {
const dataToPass = {
name: 'Ben',
lastName: 'Hewart',
message: 'Hello Parent Dispatch',
};

const child = this.querySelector('recieve-data');
if (child) {
child.receiveData(dataToPass);
}
}
}

customElements.define('dispatch-data', Dispatch);
const dispatch = document.createElement('template');

dispatch.innerHTML = `

`;

class Dispatch extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(dispatch.content.cloneNode(true));
}

connectedCallback() {
this.passDataToObject();
}

passDataToObject() {
const dataToPass = {
name: 'Ben',
lastName: 'Hewart',
message: 'Hello Parent Dispatch',
};

const child = this.querySelector('recieve-data');
if (child) {
child.receiveData(dataToPass);
}
}
}

customElements.define('dispatch-data', Dispatch);
const recieve = document.createElement('template');

recieve.innerHTML = `

`;

class Recieve extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(recieve.content.cloneNode(true));
}

// connectedCallback() {}

receiveData(obj) {
console.log('Received data:', obj.name);
}
}

customElements.define('recieve-data', Recieve);
const recieve = document.createElement('template');

recieve.innerHTML = `

`;

class Recieve extends HTMLElement {
constructor() {
super();

this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(recieve.content.cloneNode(true));
}

// connectedCallback() {}

receiveData(obj) {
console.log('Received data:', obj.name);
}
}

customElements.define('recieve-data', Recieve);