'How to change child components own public property - Lit Elements?
I am trying to implement active button using lit-elements. On click of a button css class should get attached to that particular element. On next button click css has to be removed from previous button and get added to new button. I have implemented this using single custom element and it is working fine. But I tried to implement this using parent-child custom elements.
my-app - parent component my-button - child component
Issue: active class is not getting removed from 1st button on next button click. Please refer output image attached.
I am trying to change my-button's public property on its own click.
this.clicked = ! this.clicked;
Is there any way to make this below code work by changing child component's public property inside its own class?
<!doctype html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
body {
margin: 0;
height: 100vh;
text-align: center;
margin-top: 50px;
font-family: Arial;
}
</style>
</head>
<body>
<my-app></my-app>
</body>
<script type="module">
import {LitElement, html, css} from 'https://unpkg.com/lit-element/lit-element.js?module';
class MyButton extends LitElement {
static properties = {
clicked: {},
label: {},
};
static styles = css`
/* Style the buttons */
button {
border: none;
outline: none;
padding: 10px 16px;
background-color: #f1f1f1;
cursor: pointer;
font-size: 18px;
}
/* Style the active class, and buttons on mouse-over */
.active, button:hover {
background-color: #666;
color: white;
}
`;
constructor() {
super();
this.label = 0;
}
render() {
console.log("C Render " + this.clicked);
return html`
<button
class=${ this.clicked ? 'active' : '' }
@click=${ this.setClicked }
>
${this.label}
</button>
`;
}
setClicked(e) {
const event = new Event('ask-parent-reset', {bubbles: true, composed: true});
this.dispatchEvent(event);
this.clicked = ! this.clicked;
}
}
customElements.define('my-button', MyButton);
const fBoolRrand = () => Math.random() < 0.5;
class MyApp extends LitElement {
static properties = {
pclicked: {
hasChanged(newVal, oldVal) {
return true;
}
},
};
constructor() {
super();
this.pclicked = [ false, false, false, false ];
}
render() {
console.log("P Render " + this.pclicked);
return html`
<div>
${
this.pclicked.map( (_,i) => {
return html `
<my-button
.label=${i+1}
.clicked=${this.pclicked[i]}
@ask-parent-reset=${this.resetClicked}
>
</my-button>
`
})
}
</div>
`;
}
resetClicked(e) {
this.pclicked = [ false, false, false, false ];
//this.requestUpdate();
//this.pclicked = [ true, true, true, true ];
//this.pclicked = [ fBoolRrand(), fBoolRrand(), fBoolRrand(), fBoolRrand() ];
//this.pclicked = this.pclicked.map( x => x ? false : false );
//console.log(e.target.clicked);
//const recvElem = e.srcElement;
//recvElem.clicked = !recvElem.clicked;
}
}
customElements.define('my-app', MyApp);
</script>
output: output image
Solution 1:[1]
Is there any way to make this below code work by changing child component's public property inside its own class?
I'm not 100% sure I understood your question correctly but I think it is possible. I think your attempt came very close to working so I suggest a small change which will produce a working solution.
- You can include a 'detail' property in events so I changed the 'ask-parent-reset' event to include data on which button has been pressed:
Before:
const event = new Event('ask-parent-reset', {bubbles: true, composed: true});
After:
const event = new CustomEvent('ask-parent-reset', {bubbles: true, composed: true, detail: {button: this.label}});
- Use the new event to set the
pclickedparent property so that it reflects the requested change.
Before:
resetClicked(e) {
this.pclicked = [ false, false, false, false ];
}
After:
resetClicked(e) {
const buttonIndex = e.detail.button - 1
const oldState = this.pclicked[buttonIndex]
this.pclicked = [ false, false, false, false ];
this.pclicked[buttonIndex] = !oldState
}
Hopefully that helped!
Stackblitz link to my suggested code: https://stackblitz.com/edit/web-platform-6pfvzh?file=index.html
Full HTML source:
<!doctype html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
body {
margin: 0;
height: 100vh;
text-align: center;
margin-top: 50px;
font-family: Arial;
}
</style>
</head>
<body>
<my-app></my-app>
</body>
<script type="module">
import {LitElement, html, css} from 'https://unpkg.com/lit-element/lit-element.js?module';
class MyButton extends LitElement {
static properties = {
clicked: {},
label: {},
};
static styles = css`
/* Style the buttons */
button {
border: none;
outline: none;
padding: 10px 16px;
background-color: #f1f1f1;
cursor: pointer;
font-size: 18px;
}
/* Style the active class, and buttons on mouse-over */
.active, button:hover {
background-color: #666;
color: white;
}
`;
constructor() {
super();
this.label = 0;
}
render() {
console.log("C Render " + this.clicked);
return html`
<button
class=${ this.clicked ? 'active' : '' }
@click=${ this.setClicked }
>
${this.label}
</button>
`;
}
setClicked(e) {
const event = new CustomEvent('ask-parent-reset', {bubbles: true, composed: true, detail: {button: this.label}});
this.dispatchEvent(event);
this.clicked = ! this.clicked;
}
}
customElements.define('my-button', MyButton);
const fBoolRrand = () => Math.random() < 0.5;
class MyApp extends LitElement {
static properties = {
pclicked: {
hasChanged(newVal, oldVal) {
return true;
}
},
};
constructor() {
super();
this.pclicked = [ false, false, false, false ];
}
render() {
console.log("P Render " + this.pclicked);
return html`
<div>
${
this.pclicked.map( (_,i) => {
return html `
<my-button
.label=${i+1}
.clicked=${this.pclicked[i]}
@ask-parent-reset=${this.resetClicked}
>
</my-button>
`
})
}
</div>
`;
}
resetClicked(e) {
this.pclicked = [ false, false, false, false ];
this.pclicked[e.detail.button - 1] = true
//this.requestUpdate();
//this.pclicked = [ true, true, true, true ];
//this.pclicked = [ fBoolRrand(), fBoolRrand(), fBoolRrand(), fBoolRrand() ];
//this.pclicked = this.pclicked.map( x => x ? false : false );
//console.log(e.target.clicked);
//const recvElem = e.srcElement;
//recvElem.clicked = !recvElem.clicked;
}
}
customElements.define('my-app', MyApp);
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | adamjhawley |
