I want to create a Web Component. I use a ShadowDom and after generating a list I want to add a click Event to each element of the list. But I wonder how to access the list.
Neither the document nor the template shows me the items after a querySelect.
My question: How can I access the generated list within the webcomponent?
JavaScript
x
117
117
1
const news =
2
{
3
uk: [{
4
id: 1,
5
title: "News 1 UK",
6
body: "lorem ipsum"
7
},
8
{
9
id: 2,
10
title: "News 2 UK",
11
body: "lorem ipsum"
12
},
13
{
14
id: 3,
15
title: "News 3 UK",
16
body: "lorem ipsum"
17
},
18
{
19
id: 4,
20
title: "News 4 UK",
21
body: "lorem ipsum"
22
},
23
],
24
de: [
25
{
26
id: 1,
27
title: "News 1 DE",
28
body: "lorem ipsum"
29
},
30
{
31
id: 2,
32
title: "News 2 DE",
33
body: "lorem ipsum"
34
},
35
{
36
id: 3,
37
title: "News 3 DE",
38
body: "lorem ipsum"
39
},
40
{
41
id: 4,
42
title: "News 4 DE",
43
body: "lorem ipsum"
44
},
45
]
46
};
47
48
class MyNews {
49
50
#limit = 10;
51
#region = 'uk';
52
news = [];
53
54
constructor(conf = {}) {
55
this.#limit = conf.limit ?? this.#limit;
56
this.#region = conf.region ?? this.#region;
57
this.news = news[this.#region]
58
}
59
60
61
showNews() {
62
const items = this.news.slice(0,this.#limit);
63
return items.map((n,i) => {
64
return `<p>${i+1}. ${n.title}</p>`;
65
}).join('');
66
}
67
68
getNewsData() {
69
return this.news;
70
}
71
}
72
73
74
class NewsTicker extends HTMLElement {
75
76
constructor() {
77
super();
78
this.name = 'World News';
79
this.limit = 10;
80
this.region = "uk"
81
}
82
83
static get observedAttributes() {
84
return ['name', 'url', 'limit', 'region'];
85
}
86
87
attributeChangedCallback(property, oldValue, newValue) {
88
89
if (oldValue === newValue) return;
90
this[ property ] = newValue;
91
92
}
93
94
async connectedCallback() {
95
const options = {
96
url: this.url,
97
limit: this.limit,
98
region: this.region
99
};
100
const myNews = new MyNews(options);
101
102
const
103
shadow = this.attachShadow({ mode: 'closed' }),
104
template = document.getElementById('news-template').content.cloneNode(1),
105
contextTitle = `Context ${ this.name } !`;
106
107
template.querySelector('.news-context-title').textContent = contextTitle;
108
template.querySelector('.news-list').innerHTML = myNews.showNews();
109
shadow.append( template );
110
111
const list = document.querySelector('.news-list');
112
console.log("try to get list inner the template tag:", list)
113
}
114
115
}
116
117
customElements.define( 'news-ticker', NewsTicker );
JavaScript
1
39
39
1
<news-ticker
2
name="News DE"
3
region="de"
4
limit="2">
5
</news-ticker>
6
<template id="news-template">
7
<style>
8
h2 {
9
text-align: center;
10
font-weight: normal;
11
padding: 0.5em;
12
margin: 1px 0;
13
background-color: black;
14
color: white;
15
border: 1px solid #666;
16
font-weight: bold;
17
}
18
19
.news-list > p {
20
font-weight: normal;
21
border: 1px solid #787878;
22
padding: 0.3em;
23
border-radius: 5px;
24
margin: 0.2em;
25
text-transform: capitalize;
26
text-align: left;
27
}
28
29
.news-list p:hover {
30
cursor: pointer;
31
background-color: #ffffd0;
32
}
33
</style>
34
35
<h2 class="news-context-title"></h2>
36
<div class="news-list"></div>
37
</template>
38
39
<h1></h1>
Advertisement
Answer
You dont have access to the template over document. The template tag is a shadow DOM. You can make avaible for access the shadow DOM if you change the mode parameter to true: this.attachShadow({ mode: 'open' })
. Then you can use this.shadowRoot.querySel...
. Otherwise you can access directly over your shadow object (shadow = this.attachShadow({ mode: 'closed' })
) with shadow.querySelector()
.
JavaScript
1
123
123
1
const news =
2
{
3
uk: [{
4
id: 1,
5
title: "News 1 UK",
6
body: "lorem ipsum"
7
},
8
{
9
id: 2,
10
title: "News 2 UK",
11
body: "lorem ipsum"
12
},
13
{
14
id: 3,
15
title: "News 3 UK",
16
body: "lorem ipsum"
17
},
18
{
19
id: 4,
20
title: "News 4 UK",
21
body: "lorem ipsum"
22
},
23
],
24
de: [
25
{
26
id: 1,
27
title: "News 1 DE",
28
body: "lorem ipsum"
29
},
30
{
31
id: 2,
32
title: "News 2 DE",
33
body: "lorem ipsum"
34
},
35
{
36
id: 3,
37
title: "News 3 DE",
38
body: "lorem ipsum"
39
},
40
{
41
id: 4,
42
title: "News 4 DE",
43
body: "lorem ipsum"
44
},
45
]
46
};
47
48
class MyNews {
49
50
#limit = 10;
51
#region = 'uk';
52
news = [];
53
54
constructor(conf = {}) {
55
this.#limit = conf.limit ?? this.#limit;
56
this.#region = conf.region ?? this.#region;
57
this.news = news[this.#region]
58
}
59
60
61
showNews() {
62
const items = this.news.slice(0,this.#limit);
63
return items.map((n,i) => {
64
return `<p>${i+1}. ${n.title}</p>`;
65
}).join('');
66
}
67
68
getNewsData() {
69
return this.news;
70
}
71
}
72
73
74
class NewsTicker extends HTMLElement {
75
76
constructor() {
77
super();
78
this.name = 'World News';
79
this.limit = 10;
80
this.region = "uk"
81
}
82
83
static get observedAttributes() {
84
return ['name', 'url', 'limit', 'region'];
85
}
86
87
attributeChangedCallback(property, oldValue, newValue) {
88
89
if (oldValue === newValue) return;
90
this[ property ] = newValue;
91
92
}
93
94
async connectedCallback() {
95
const options = {
96
url: this.url,
97
limit: this.limit,
98
region: this.region
99
};
100
const myNews = new MyNews(options);
101
102
const
103
shadow = this.attachShadow({ mode: 'open' }), // change mode to open then you have access over the shadowRoot
104
template = document.getElementById('news-template').content.cloneNode(1),
105
contextTitle = `Context ${ this.name } !`;
106
107
template.querySelector('.news-context-title').textContent = contextTitle;
108
template.querySelector('.news-list').innerHTML = myNews.showNews();
109
shadow.append( template );
110
111
const list = document.querySelector('.news-list');
112
const list_1 = shadow.querySelector('.news-list');
113
const list_2 = this.shadowRoot.querySelector('.news-list');
114
115
console.log("document.querySelector('.news-list') :", list_1)
116
console.log("shadow.querySelector('.news-list') :", list_2);
117
console.log("this.shadowRoot.querySelector('.news-list') :", list_3);
118
119
}
120
121
}
122
123
customElements.define( 'news-ticker', NewsTicker );
JavaScript
1
37
37
1
<news-ticker
2
name="News DE"
3
region="de"
4
limit="2">
5
</news-ticker>
6
<template id="news-template">
7
<style>
8
h2 {
9
text-align: center;
10
font-weight: normal;
11
padding: 0.5em;
12
margin: 1px 0;
13
background-color: black;
14
color: white;
15
border: 1px solid #666;
16
font-weight: bold;
17
}
18
19
.news-list > p {
20
font-weight: normal;
21
border: 1px solid #787878;
22
padding: 0.3em;
23
border-radius: 5px;
24
margin: 0.2em;
25
text-transform: capitalize;
26
text-align: left;
27
}
28
29
.news-list p:hover {
30
cursor: pointer;
31
background-color: #ffffd0;
32
}
33
</style>
34
35
<h2 class="news-context-title"></h2>
36
<div class="news-list"></div>
37
</template>