React—add a click listener to dangerouslySetInnerHTML sub-element
up vote
0
down vote
favorite
I have this html text:
"<span id='capo' class='capo' data-capo=3>Capo 3</span>"
This is part of a larger html that is inserted via dangerouslySetInnerHTML
And I have a listener like this:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
However this only works for one click—after that the listener doesn't exist. I'm guessing because React has replaced the component (since I change the state in this.changeKey
), and therefore the listener no longer exists.
How do I reliably set a listener for React components?
reactjs
add a comment |
up vote
0
down vote
favorite
I have this html text:
"<span id='capo' class='capo' data-capo=3>Capo 3</span>"
This is part of a larger html that is inserted via dangerouslySetInnerHTML
And I have a listener like this:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
However this only works for one click—after that the listener doesn't exist. I'm guessing because React has replaced the component (since I change the state in this.changeKey
), and therefore the listener no longer exists.
How do I reliably set a listener for React components?
reactjs
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I have this html text:
"<span id='capo' class='capo' data-capo=3>Capo 3</span>"
This is part of a larger html that is inserted via dangerouslySetInnerHTML
And I have a listener like this:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
However this only works for one click—after that the listener doesn't exist. I'm guessing because React has replaced the component (since I change the state in this.changeKey
), and therefore the listener no longer exists.
How do I reliably set a listener for React components?
reactjs
I have this html text:
"<span id='capo' class='capo' data-capo=3>Capo 3</span>"
This is part of a larger html that is inserted via dangerouslySetInnerHTML
And I have a listener like this:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
However this only works for one click—after that the listener doesn't exist. I'm guessing because React has replaced the component (since I change the state in this.changeKey
), and therefore the listener no longer exists.
How do I reliably set a listener for React components?
reactjs
reactjs
asked Nov 11 at 7:41
Mirror318
4,84922941
4,84922941
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
In this case you can make use of event bubbling!
Just add your event listener to the upper element (the one with dangerouslySetInnerHTML
will be fine) listen for clicks and make sure that e.target.id
is equal to the desired element ID.
Check out the example below (it uses dangerouslySetInnerHTML
just to show how event bubbling works and how to use it with React, you shouldn't write component like this in the real life):
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
add a comment |
up vote
0
down vote
Whenever there is a state change, React removes the html and replaces it.
This code will only execute when the component is first loaded, not when state changes and html elements (and their listeners) are wiped:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
But this code will run every time the component is rerendered (so whenever a new html element is made, a new listener is attached to it):
componentDidUpdate() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
In this case you can make use of event bubbling!
Just add your event listener to the upper element (the one with dangerouslySetInnerHTML
will be fine) listen for clicks and make sure that e.target.id
is equal to the desired element ID.
Check out the example below (it uses dangerouslySetInnerHTML
just to show how event bubbling works and how to use it with React, you shouldn't write component like this in the real life):
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
add a comment |
up vote
1
down vote
In this case you can make use of event bubbling!
Just add your event listener to the upper element (the one with dangerouslySetInnerHTML
will be fine) listen for clicks and make sure that e.target.id
is equal to the desired element ID.
Check out the example below (it uses dangerouslySetInnerHTML
just to show how event bubbling works and how to use it with React, you shouldn't write component like this in the real life):
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
add a comment |
up vote
1
down vote
up vote
1
down vote
In this case you can make use of event bubbling!
Just add your event listener to the upper element (the one with dangerouslySetInnerHTML
will be fine) listen for clicks and make sure that e.target.id
is equal to the desired element ID.
Check out the example below (it uses dangerouslySetInnerHTML
just to show how event bubbling works and how to use it with React, you shouldn't write component like this in the real life):
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
In this case you can make use of event bubbling!
Just add your event listener to the upper element (the one with dangerouslySetInnerHTML
will be fine) listen for clicks and make sure that e.target.id
is equal to the desired element ID.
Check out the example below (it uses dangerouslySetInnerHTML
just to show how event bubbling works and how to use it with React, you shouldn't write component like this in the real life):
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
class Element extends React.Component {
state = {
loadTime: 0,
lastUpdate: 0
};
lastUpdateTimer = null;
componentDidMount() {
this.resetTimer();
this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
this.dynamicContentElement.addEventListener("click", this.handleClick)
}
componentWillUnmount() {
clearInterval(this.lastUpdateTimer);
this.dynamicContentElement.removeEventListener(this.handleClick)
}
resetTimer() {
const now = Date.now();
this.setState({
loadTime: now,
lastUpdate: now
});
}
setLastUpdate = () => {
this.setState({
lastUpdate: Date.now()
});
}
getDynamicContent() {
const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
return {
__html: `<p>
You are here: <strong>${time}</strong> seconods.
<br>
<button id="btn">Click to reset counter</button>
</p>`
};
}
handleClick = (e) => {
if (e.target.id === "btn") {
this.resetTimer();
}
}
render() {
return (
<div>
Dynamic content below:
<div
ref={el => this.dynamicContentElement = el}
dangerouslySetInnerHTML={this.getDynamicContent()}
/>
</div>
);
}
}
ReactDOM.render(
<Element />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
answered Nov 11 at 10:32
slawekkolodziej
52438
52438
add a comment |
add a comment |
up vote
0
down vote
Whenever there is a state change, React removes the html and replaces it.
This code will only execute when the component is first loaded, not when state changes and html elements (and their listeners) are wiped:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
But this code will run every time the component is rerendered (so whenever a new html element is made, a new listener is attached to it):
componentDidUpdate() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
add a comment |
up vote
0
down vote
Whenever there is a state change, React removes the html and replaces it.
This code will only execute when the component is first loaded, not when state changes and html elements (and their listeners) are wiped:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
But this code will run every time the component is rerendered (so whenever a new html element is made, a new listener is attached to it):
componentDidUpdate() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
add a comment |
up vote
0
down vote
up vote
0
down vote
Whenever there is a state change, React removes the html and replaces it.
This code will only execute when the component is first loaded, not when state changes and html elements (and their listeners) are wiped:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
But this code will run every time the component is rerendered (so whenever a new html element is made, a new listener is attached to it):
componentDidUpdate() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
Whenever there is a state change, React removes the html and replaces it.
This code will only execute when the component is first loaded, not when state changes and html elements (and their listeners) are wiped:
componentDidMount() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
But this code will run every time the component is rerendered (so whenever a new html element is made, a new listener is attached to it):
componentDidUpdate() {
document.getElementById('capo').addEventListener('click', this.changeKey);
}
answered Nov 12 at 6:08
Mirror318
4,84922941
4,84922941
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53246760%2freact-add-a-click-listener-to-dangerouslysetinnerhtml-sub-element%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown