Skip to content

Commit d93289a

Browse files
committed
Add exercise 7 to lesson 1
1 parent 1ac544f commit d93289a

3 files changed

Lines changed: 127 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<html>
2+
<head>
3+
<link rel="stylesheet" type="text/css" href="../css/semantic.min.css" />
4+
<link rel="stylesheet" type="text/css" href="../css/store_with_header.css" />
5+
</head>
6+
<body>
7+
<div id="content">
8+
<section class="header">
9+
<h1 class="title">Welcome to Fresh Products Store!</h1>
10+
11+
<div class="ui menu">
12+
<div class="item">
13+
Filtered by tags: <span class="tags"></span>
14+
</div>
15+
<div class="right item">
16+
<search-box value="" />
17+
</div>
18+
</div>
19+
</section>
20+
21+
<div class="ui items"></div>
22+
</div>
23+
24+
<script src="search_box.js"></script>
25+
<script src="../data/products.js"></script>
26+
<script src="../sample_003/create_elements.js"></script>
27+
<script src="filter_and_search.js"></script>
28+
</body>
29+
</html>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const tagsToFilterBy = [];
2+
let textToSearch = '';
3+
4+
const searchBoxElement = document.querySelector('search-box');
5+
searchBoxElement.addEventListener('changed', (e) => {
6+
textToSearch = e.detail.text;
7+
applyFilters();
8+
});
9+
10+
function addTagFilter() {
11+
Array.from(document.querySelectorAll('.extra .label'))
12+
.forEach(tagEl => {
13+
tagEl.addEventListener('click', () => {
14+
if (!tagsToFilterBy.includes(tagEl.innerHTML)) {
15+
tagsToFilterBy.push(tagEl.innerHTML);
16+
applyFilters();
17+
}
18+
});
19+
});
20+
}
21+
22+
function applyFilters() {
23+
createListForProducts(filterByText(filterByTags(products)));
24+
addTagFilter();
25+
updateTagFilterList();
26+
}
27+
28+
function createTagFilterLabel(tag) {
29+
const el = document.createElement('span');
30+
el.className = 'ui label orange';
31+
el.innerText = tag;
32+
33+
el.addEventListener('click', () => {
34+
const index = tagsToFilterBy.indexOf(tag);
35+
tagsToFilterBy.splice(index, 1);
36+
applyFilters();
37+
});
38+
return el;
39+
}
40+
41+
function filterByTags(products) {
42+
let filtered = products;
43+
tagsToFilterBy.forEach((t) => filtered = filtered.filter(p => p.tags.includes(t)));
44+
return filtered;
45+
}
46+
47+
function filterByText(products) {
48+
const txt = (textToSearch || '').toLowerCase();
49+
return products.filter((p) => {
50+
return p.name.toLowerCase().includes(txt)
51+
|| p.description.toLowerCase().includes(txt);
52+
});
53+
}
54+
55+
function updateTagFilterList() {
56+
const tagHolder = document.querySelector('.item span.tags');
57+
58+
if (tagsToFilterBy.length == 0) {
59+
tagHolder.innerHTML = 'No filters';
60+
} else {
61+
tagHolder.innerHTML = '';
62+
tagsToFilterBy.sort();
63+
tagsToFilterBy.map(createTagFilterLabel)
64+
.forEach((tEl) => tagHolder.appendChild(tEl));
65+
}
66+
}
67+
68+
applyFilters();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class SearchBox extends HTMLElement {
2+
constructor() {
3+
super();
4+
this.attachShadow({ mode: 'open' });
5+
this.render();
6+
this.shadowRoot.querySelector('input').addEventListener('keyup', (e) => {
7+
this.triggerTextChanged(e.target.value);
8+
});
9+
}
10+
11+
render() {
12+
this.shadowRoot.innerHTML = `
13+
<link rel="stylesheet" type="text/css" href="../css/semantic.min.css" />
14+
<div class="ui icon input">
15+
<input type="text" placeholder="Search..." />
16+
<i class="search icon"></i>
17+
</div>
18+
`;
19+
}
20+
21+
triggerTextChanged(text) {
22+
const event = new CustomEvent('changed', {
23+
bubbles: true,
24+
detail: { text },
25+
});
26+
this.dispatchEvent(event);
27+
}
28+
}
29+
30+
customElements.define('search-box', SearchBox);

0 commit comments

Comments
 (0)