Reputation: 1023
EDIT: This is a Web Component exported from Angular using Angular Elements and is not traditional Angular
I am experimenting with Angular Elements and have created an NgFor component that loads the JSON file below.
[
{
"id":1,
"name": "star 1",
"image":"https://picsum.photos/id/1059/400/400",
"text":"Text about star 1"
},
{
"id":2,
"name": "star 2",
"image":"https://picsum.photos/id/1060/400/400",
"text":"Text about star 2"
},
{
"id":3,
"name": "star 3",
"image":"https://picsum.photos/id/1061/400/400",
"text":"Text about star 3"
},
{
"id":4,
"name": "star 4",
"image":"https://picsum.photos/id/1062/400/400",
"text":"Text about star 4"
},
{
"id":5,
"name": "star 5",
"image":"https://picsum.photos/id/1063/400/400",
"text":"Text about star 5"
},
{
"id":6,
"name": "star 6",
"image":"https://picsum.photos/id/1064/400/400",
"text":"Text about star 6"
},
{
"id":7,
"name": "star 7",
"image":"https://picsum.photos/id/1065/400/400",
"text":"Text about star 7"
},
{
"id":8,
"name": "star 8",
"image":"https://picsum.photos/id/1066/400/400",
"text":"Text about star 8"
},
{
"id":9,
"name": "star 9",
"image":"https://picsum.photos/id/1067/400/400",
"text":"Text about star 9"
},
{
"id":10,
"name": "star 10",
"image":"https://picsum.photos/id/1068/400/400",
"text":"Text about star 10"
}
]
This renders a list in the browser
Star1
Star2
Star3
.
.
etc
There is an onClick function on these elements which emits the object through the @Output property.
I then have an eventListener in a script tag in the HTML that listens for this emit and updates the src property in an img tag with the relevant image.
My question is; I would like to create another WebComponent that has this eventListener built into it so I can just add this second component to the HTML and then they will communicate with each other without me having to write an eventListener directly in the script tag. My current Code.
<name-list />
<img-comp />
<img></img> //not needed if <img-comp> can receive the emitted data
<script src="elementCommunicationWithDom.js"></script>
<script>
init();
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'data.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
}
function init() {
loadJSON(function (response) {
var obj = JSON.parse(response);
console.log(obj);
let element = document.querySelector('name-list');
element.names = obj; //set the html property names created in @input in Angular to the object
});
}
let element = document.querySelector('name-list');
let img = document.querySelector('img');
// I want to do the below directly within the <img-comp> component
element.addEventListener("onSelectItem", (event) => { //gets the output of @Output which is onSelectItem
img.src = event.detail.image;
console.log(event.detail.image)
})
</script>
Back in my Angular Component for <img-comp>
I have the following
Template
<img [src]="imgsrc" />
Component
@Component({
selector: 'app-img-comp',
templateUrl: './img-comp.component.html',
styleUrls: ['./img-comp.component.css']
})
export class ImgCompComponent implements OnInit {
@Input() imgsrc: string;
//This below is incorrect and is what I need I think to make this work
@HostListener('onSelectItem', ['$event'])
OnStarClicked(event) {
this.imgsrc = event.detail.image;
console.log(event.detail.image);
}
How do I get the @Hostlistener property to correctly add the equivalent eventListener that is in the html script tag?
https://stackblitz.com/edit/angular-ej7fnv
Upvotes: 1
Views: 1907
Reputation: 6432
I’m not sure what the sturcure of your comonnets look like but you have to keep in mind:
EventEmitters !== DOM events
Unlike DOM events Angular custom events do not bubble. What it means you can only listen to component's event at the parent level.
What you can is to create native DOM events as following:
constructor(private el: ElementRef) { }
onClick(star) {
this.el.nativeElement
.dispatchEvent(new CustomEvent('onSelectItem', {
detail: star,
bubbles: true
}));
}
I Hope it helpful.
Upvotes: 1