英文:
How to bind a delete method to a rendered web component
问题
我有困难弄清楚如何绑定我的handleDelete方法。
我结构化的方式是,用户点击加号按钮,然后数据对象被存储在窗口对象上的一个数组中。然后调用SelectedProducts组件上的渲染,它呈现一个卡片,其中有我试图绑定handleDelete方法的按钮。
如果运行代码,你可以看到我目前的进展。
也许这不是正确的方法,只是尝试不添加库来做。
仍在努力弄清楚我需要哪些生命周期方法或自定义事件?
class SelectedProducts extends HTMLElement {
constructor() {
super();
this.mockData = [
{ id: 1, name: 'name-1', qty: 1 },
{ id: 2, name: 'name-2', qty: 1 },
{ id: 2, name: 'name-1', qty: 2 },
];
}
handleDelete(e) {
e.preventDefault();
console.log('called handleDelete');
}
connectedCallback() {
this.querySelector('button').addEventListener('click', this.handleDelete.bind(this));
}
attributeChangedCallback(attrName, oldValue, newValue) {
console.log('attributeChange called');
this.handleDelete(e);
}
static get observedAttributes() {
return ['data-id'];
}
disconnectedCallback() {
console.log('disconnectedCallback ran');
}
render() {
this.mockData.forEach((item, index) => {
this.innerHTML += `
<div style="display:flex; align-items: center; background-color:white; padding:15px; ">
<button data-id="${item.id}" class="delete-btn">
Delete me
</button>
</div>
`;
});
}
handleDelete(e) {
e.preventDefault();
alert('Called Handle delete');
}
}
customElements.define('selected-products', SelectedProducts);
class ProductCard extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML =
`<style>
::slotted(div){
color: #4B5563;
font-weight: 900;
text-align: center;
font-size: 20px;
}
</style>
` +
` <div style="background: white; margin-right: 15px;">
<slot name="button"></slot>
<slot name="img"></slot>
</div>
`;
}
}
customElements.define('product-card', ProductCard);
class SelectBtn extends HTMLElement {
constructor() {
super();
// This is called with render below
this.itemsPicked = document.querySelector('selected-products');
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<button
aria-label="Select"
type="button"
class="pressed"
data-addbtn="add-btn"
>
+
</button>
`;
this.id = this.getAttribute('id');
this.name = this.getAttribute('name');
this.shadowRoot
.querySelectorAll('button')
.forEach((button) => button.addEventListener('click', this.handleSelect.bind(this)));
}
// Get data from attributes & store object in
// an array on window object
handleSelect(e) {
e.preventDefault();
this.itemsPicked.render();
}
}
customElements.define('select-button', SelectBtn);
<body>
<div style="display: flex; justify-content: center; align-items: center; background: lightblue; padding: 10px">
<product-card>
<div slot="button">
<select-button id="1" name="product name"></select-button>
</div>
<div slot="img">
<div style="height: 100px; width: 100px">Select Button</div>
</div>
</product-card>
<div>
<selected-products></selected-products>
</div>
</div>
<script src="app.js"></script>
<script>
window.selectedItems = {
items: [],
};
</script>
</body>
英文:
I am having trouble figuring out how to bind my handleDelete method.
The way I have it structured is the user clicks the plus button then data objects get stored in an array on the window object. Then render is called on the SelectedProducts component that renders a card that has the button I am trying to bind the handleDelete method to.
If you run the code you can see what I have so far.
Maybe this is not the right approach just trying to do it with out adding a library.
Still trying to wrap my head around which lifecycle methods I need or a custom event?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
class SelectedProducts extends HTMLElement {
constructor() {
super();
this.mockData = [
{ id: 1, name: 'name-1', qty: 1 },
{ id: 2, name: 'name-2', qty: 1 },
{ id: 2, name: 'name-1', qty: 2 },
];
}
handleDelete(e) {
e.preventDefault();
console.log('called handleDelete');
}
connectedCallback() {
this.querySelector('button').addEventListener('click', this.handleDelete.bind(this));
}
attributeChangedCallback(attrName, oldValue, newValue) {
console.log('attributeChange called');
this.handleDelete(e);
}
static get observedAttributes() {
return ['data-id'];
}
disconnectedCallback() {
console.log('disconnectedCallback ran');
}
render() {
this.mockData.forEach((item, index) => {
this.innerHTML += `
<div style="display:flex; align-items: center; background-color:white; padding:15px; ">
<button data-id="${item.id}" class="delete-btn">
Delete me
</button>
</div>
`;
});
}
handleDelete(e) {
e.preventDefault();
alert('Called Handle delete');
}
}
customElements.define('selected-products', SelectedProducts);
class ProductCard extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML =
`<style>
::slotted(div){
color: #4B5563;
font-weight: 900;
text-align: center;
font-size: 20px;
}
</style>
` +
` <div style="background: white; margin-right: 15px;">
<slot name="button"></slot>
<slot name="img"></slot>
</div>
`;
}
}
customElements.define('product-card', ProductCard);
class SelectBtn extends HTMLElement {
constructor() {
super();
// This is called with render below
this.itemsPicked = document.querySelector('selected-products');
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<button
aria-label="Select"
type="button"
class="pressed"
data-addbtn="add-btn"
>
+
</button>
`;
this.id = this.getAttribute('id');
this.name = this.getAttribute('name');
this.shadowRoot
.querySelectorAll('button')
.forEach((button) => button.addEventListener('click', this.handleSelect.bind(this)));
}
// Get data from attributes & store object in
// an array on window object
handleSelect(e) {
e.preventDefault();
this.itemsPicked.render();
}
}
customElements.define('select-button', SelectBtn);
<!-- language: lang-html -->
<body>
<div style="display: flex; justify-content: center; align-items: center; background: lightblue; padding: 10px">
<product-card>
<div slot="button">
<select-button id="1" name="product name"></select-button>
</div>
<div slot="img">
<div style="height: 100px; width: 100px">Select Button</div>
</div>
</product-card>
<div>
<selected-products></selected-products>
</div>
</div>
<script src="app.js"></script>
<script>
window.selectedItems = {
items: [],
};
</script>
</body>
<!-- end snippet -->
答案1
得分: 0
我解决这个问题的方法不是将事件监听器附加到内部HTML本身,而是创建了另一个Web组件(delete-button),并为其添加了事件监听器和处理事件的方法。任何反馈都将非常酷。
class DeleteButton extends HTMLElement {
constructor() {
super();
this.selectedProducts = document.querySelector('selected-products');
this.querySelectorAll('button').forEach((button) => button.addEventListener('click', this.handleDelete.bind(this)));
}
handleDelete(e) {
e.preventDefault();
alert('Delete button Event');
}
}
customElements.define('delete-button', DeleteButton);
class SelectedProducts extends HTMLElement {
constructor() {
super();
this.mockData = [
{ id: 1, name: 'name-1', qty: 1 },
{ id: 2, name: 'name-2', qty: 1 },
{ id: 2, name: 'name-1', qty: 2 },
];
}
render() {
this.mockData.forEach((item, index) => {
this.innerHTML += `
<div style="display:flex; align-items: center; background-color:white; padding:15px;">
<delete-button>
<button data-id="${item.id}" class="delete-btn">
Delete me
</button>
</delete-button>
</div>
`;
});
}
handleDelete(e) {
e.preventDefault();
alert('Called Handle delete');
}
}
customElements.define('selected-products', SelectedProducts);
class ProductCard extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML =
`<style>
::slotted(div){
color: #4B5563;
font-weight: 900;
text-align: center;
font-size: 20px;
}
</style>` +
` <div style="background: white; margin-right: 15px;">
<slot name="button"></slot>
<slot name="img"></slot>
</div>
`;
}
}
customElements.define('product-card', ProductCard);
class SelectBtn extends HTMLElement {
constructor() {
super();
this.itemsPicked = document.querySelector('selected-products');
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<button
aria-label="Select"
type="button"
class="pressed"
data-addbtn="add-btn"
>
+
</button>
`;
this.id = this.getAttribute('id');
this.name = this.getAttribute('name');
this.shadowRoot
.querySelectorAll('button')
.forEach((button) => button.addEventListener('click', this.handleSelect.bind(this)));
}
handleSelect(e) {
e.preventDefault();
this.itemsPicked.render();
}
}
customElements.define('select-button', SelectBtn);
<body>
<div style="display: flex; justify-content: center; align-items: center; background: lightblue; padding: 10px">
<product-card>
<div slot="button">
<select-button id="1" name="product name"></select-button>
</div>
<div slot="img">
<div style="height: 100px; width: 100px">Select Button</div>
</div>
</product-card>
<div>
<selected-products></selected-products>
</div>
</div>
<script src="app.js"></script>
<script>
window.selectedItems = {
items: [],
};
</script>
</body>
英文:
The way I solved this problem was not to attach an event listener to inner html itself. Instead I created another web component (delete-button) with and event listener and a method to handle the event. Any feedback would be super cool.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
class DeleteButton extends HTMLElement {
constructor() {
super();
this.selectedProducts = document.querySelector('selected-products');
this.querySelectorAll('button').forEach((button) => button.addEventListener('click', this.handleDelete.bind(this)));
}
handleDelete(e) {
e.preventDefault();
alert('Delete button Event');
}
}
customElements.define('delete-button', DeleteButton);
class SelectedProducts extends HTMLElement {
constructor() {
super();
this.mockData = [
{ id: 1, name: 'name-1', qty: 1 },
{ id: 2, name: 'name-2', qty: 1 },
{ id: 2, name: 'name-1', qty: 2 },
];
}
render() {
this.mockData.forEach((item, index) => {
this.innerHTML += `
<div style="display:flex; align-items: center; background-color:white; padding:15px; ">
<delete-button>
<button data-id="${item.id}" class="delete-btn">
Delete me
</button>
</delete-button>
</div>
`;
});
}
handleDelete(e) {
e.preventDefault();
alert('Called Handle delete');
}
}
customElements.define('selected-products', SelectedProducts);
class ProductCard extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML =
`<style>
::slotted(div){
color: #4B5563;
font-weight: 900;
text-align: center;
font-size: 20px;
}
</style>
` +
` <div style="background: white; margin-right: 15px;">
<slot name="button"></slot>
<slot name="img"></slot>
</div>
`;
}
}
customElements.define('product-card', ProductCard);
class SelectBtn extends HTMLElement {
constructor() {
super();
// This is called with render below
this.itemsPicked = document.querySelector('selected-products');
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<button
aria-label="Select"
type="button"
class="pressed"
data-addbtn="add-btn"
>
+
</button>
`;
this.id = this.getAttribute('id');
this.name = this.getAttribute('name');
this.shadowRoot
.querySelectorAll('button')
.forEach((button) => button.addEventListener('click', this.handleSelect.bind(this)));
}
// Get data from attributes & store object in
// an array on window object
handleSelect(e) {
e.preventDefault();
this.itemsPicked.render();
}
}
customElements.define('select-button', SelectBtn);
<!-- language: lang-html -->
<body>
<div style="display: flex; justify-content: center; align-items: center; background: lightblue; padding: 10px">
<product-card>
<div slot="button">
<select-button id="1" name="product name"></select-button>
</div>
<div slot="img">
<div style="height: 100px; width: 100px">Select Button</div>
</div>
</product-card>
<div>
<selected-products></selected-products>
</div>
</div>
<script src="app.js"></script>
<script>
window.selectedItems = {
items: [],
};
</script>
</body>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论