How to toggle class to a div element in reactjs? - javascript

i am new to reactjs and i am unable to toggle the class for div element on click event.
What i want to implement is below,
I have a div element created dynamically like below,
constructor(props) {
super(props);
this.element = document.createElement('div');
this.element.className = 'div_class';
}
I add and remove the div element on component mount and unmount as below,
componentDidMount() {
notifications_root.appendChild(this.element);
ReactDOM.render(<SvgSome onClick={this.handle_dialog_close} width="36"
style={{position:'absolute',cursor: 'pointer', right: '250px', top:
'105px'}} />, this.element);
}
componentWillUnmount() {
this.element.classList.remove('hidden');
root.removeChild(this.element);
}
handle_dialog_close = () => {
this.element.classList.add('hidden');
};
Also i add and remove class 'hidden' to div element on clicking the svg element.
However it does hide the div element on clicking svg element but doesnt show up the div element again...I guess the div element class is set to hidden it doesnt showup. Can somebody help me know where the problem is. Below is the css code. Thanks.
.div_class {
width:800px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.3);
margin-top: 100px;
margin-right: auto;
margin-bottom: 0px;
margin-left: auto;
&.hidden {
display: none;
}
}

One thing you could is create an variable (or array if you want more classes) and then add then conditionally.
Render(){
Const divClasses =[‘My-Div’, ‘Container’]
Return(
<div className=
{/*condition*\ && divClasses>
//content
</div>
)
}
So the class(es) will be the added based on a condition. Additionally you could add a handler to control the condition.

React is a declarative library. You don't need to create and remove DOM elements with it. You just declare them with jsx inside the render method.
Check out some react tutorials to learn how to work with react.
You are looking for some solution like this:
<div className=`div_class ${this.state.hidden ? 'hidden' : ''}`>
<svg onClick={() => this.setState({hidden: !this.state.hidden})}></svg>
</div>

What about using core javascript instead?
There is no point to use a library if it makes stuff harder!
function toggleClass(id,classA,classB){
if (document.getElementById(id).classList[0] === classA){
document.getElementById(id).classList = classB
}
else {
document.getElementById(id).classList = classA
}
}
.hidden {display:none}
.show {display:block}
#elem1 {background: blue; width:200px;height:200px;font-size:10rem;text-align:center}
<button onclick="toggleClass('elem1','show','hidden')">Hide/Show</button>
<div id="elem1" class="show">☀</div>

Related

Add class if image has the class

I have some images which are way too big when I make the menu they're containing in smaller, that's why I made a second class where I changed the width and height.
I tried to add and remove the class with javascript like this:
if ($('img').hasClass('lorem')) {
$('img').removeClass('lorem')
$('img').addClass('smalllorem')
} else {
$('img').addClass('lorem')
$('img').removeClass('smalllorem')
}
Now this works perfectly fine, but this will add the classes to my other images on the website as well, how can I specify to only give the class "smalllorem" to the elements which have the class lorem? Because the other images don't have the class "lorem" they will still get the class "smalllorem" added on.
-> I don't get why images without the class "lorem" get into the code? I mean I ask if the image has class .. Why does it include the other image elements?
I would look for a CSS solution before moving on to a JavaScript one. But answering the question asked...
I don't get why images without the class "lorem" getting into the code ? I mean I ask if img has class
Because $("img") selects all images, but $("img").hasClass("lorem") only looks at the first image to see if it has the class. Then in each branch of your if/else, you're applying changes to all images ($("img").addClass("lorem");). jQuery's API is asymmetric in this regard: methods that tell you something about the element only look at the first element in the jQuery collection, but methods that change something apply to all elements in the collection.
If I understand you correctly, you want to:
Remove lorem from images that have it, adding smalllorem instead
and
Remove smalllorem from images that have it, adding lorem instead
Basically, you want to toggle both classes. There's a toggleClass method for that.
$("img.lorem, img.smalllorem").toggleClass("lorem smalllorem");
That selects all img elements that have either class, and toggles the classes on them.
Live Example:
setTimeout(() => {
$("img.lorem, img.smalllorem").toggleClass("lorem smalllorem");
}, 800);
.lorem {
border: 2px solid black;
}
.smalllorem {
border: 2px solid yellow;
}
<div>lorem (black border) => smalllorem (yellow border):</div>
<img class="lorem" src="https://via.placeholder.com/50.png/09f/fff">
<img class="lorem" src="https://via.placeholder.com/50.png/09f/fff">
<img class="lorem" src="https://via.placeholder.com/50.png/09f/fff">
<div>smalllorem (yellow border) => lorem (black border):</div>
<img class="smalllorem" src="https://via.placeholder.com/50.png/09f/fff">
<img class="smalllorem" src="https://via.placeholder.com/50.png/09f/fff">
<img class="smalllorem" src="https://via.placeholder.com/50.png/09f/fff">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Instead of adding a new class to the image you could just make it responsive :
.img {
width: 100%; //define width
max-width: 250px; //restrict the size (can use min-width aswell)
height: auto; //auto adjust depending on the width
}
var count = 0;
function resize(){
var menue = document.getElementById("container");
count++;
if(count % 2)
{
menue.style.width = "50%";
menue.style.height = "50px";
}
else
{
menue.style.width = "100%";
menue.style.height = "100px";
}
}
#container{
border: 1px solid black;
width: 100%;
height: 100px;
transition: 330ms;
}
#home{
width: 15%;
height: auto;
min-width:10px;
}
menue
<div id="container">
<img src="https://cdn-icons-png.flaticon.com/512/25/25694.png" id="home">
</div>
<br>
<input type="button" value="resize menue" onclick="resize()">

How to change a div border color when clicked?

Working on a react/typescript project, I have a div and want to replace the border color and width of a div when it's clicked:
<div
className="showroom-card "
onClick={() => setSelection({ showroom: 'Westchester' })}
>
I know it should be simple but I'm pretty new to this.
in javascript you can make but please describe more
div.style.border="1px solid #000";
With pure html/js it would be look like that:
.showroom-card {
width: 500px;
height: 300px;
background-color: yellow;
border: 2px solid red;
}
.selected {
border: 2px solid black;
}
<div
id="card1"
class="showroom-card"
onClick="(function(divId) {
targetDiv = document.querySelector(`#${divId}`)
targetDiv.classList.toggle('selected')
})('card1');return false;"
></div>
But in react you must use state of component to manipulate div's style. For example, you would use divToggled variable in state of your component to render border and manipulate its color. The handler function, named handleDivClick change state and component will be rerendered:
class YourComponent extends React.Component {
...
handleDivClick = () => {
this.setState(divToggled: !this.state.divToggled)
}
...
render() {
return (
<div
onClick={this.handleDivClick}
className={`showroom-card ${this.state.divToggled ? 'selected' : ''}`}
/>
)
}
}

Clear inline style after reset

How do I remove the inline style which is added by JavaScript?
For example: if people click the button, the marginTop of div#test will be 30px, but what if I want to remove the inline style instead of resetting it to another value like 0?
I do not want to add a class to that element and remove it because it's not suitable in my use case.
const elm = document.querySelector('#test')
function change() {
elm.style.marginTop = '30px';
}
#test {
width: 150px;
height: 60px;
background-color: blue;
}
<div id="test"></div>
<button onclick="change()">Change</button>
either set as empty string
elm.style.marginTop = '';
or to remove the complete attribute use
removeAttribute
elem.removeAttribute('style');

Cannot get element with the "display: none" property applied to it using getElementById()

I'm running into an issue where the getElementById() function is unable to get a particular element on the page that has the display: none property applied to it, even though it's visible in the DOM (I can see that the div and its id exists on the final rendered page).
Is there a way around this?
Here's the code:
togglePanel() {
const panelId = this.accordionItem.querySelector("#collapsible-panel");
this.shouldShowAccordion = !this.shouldShowAccordion;
if (this.shouldShowAccordion) {
panelId.classList.remove("collapsed");
}
else {
panelId.classList.add("collapsed");
}
}
"collapsible-panel" is the ID of the div which has display: none applied to it.
setTimeout(() => {
document.querySelector("div[id='collapsiblepanel']").style.display = 'block';
}, 2000)
#collapsiblepanel {
width: 200px;
height: 100px;
background-color: red;
display: none;
}
Following is ana example where I am selecting a div which has the value of display as none. After 2 seconds I am setting up it's display to block.
<div id="collapsiblepanel">
</div>

Webcomponents is re-initializing every time while working with Vue js

I have created a webcomponent for a generic input boxes that i needed across multiple projects.
the design functionality remains same only i have to use switch themes on each projects.so i have decided to go on with webcomponents.One of the projects is based on Vue Js.In Vue js the DOM content is re-rendered while each update for enabling reactivity. That re-rendering of vue template is reinitializing my custom webcomponent which will result in loosing all my configurations i have assigned to the component using setters.
I know the below solutions. but i wanted to use a setter method.
pass data as Attributes
Event based passing of configurations.
Using Vue-directives.
using v-show instead of v-if
-- Above three solutions doesn't really match with what i am trying to create.
I have created a sample project in jsfiddle to display my issue.
Each time i an unchecking and checking the checkbox new instances of my component is creating. which causes loosing the theme i have selected. (please check he active boxes count)
For this particular example i want blue theme to be displayed. but it keep changing to red
JSFiddle direct Link
class InputBox extends HTMLElement {
constructor() {
super();
window.activeBoxes ? window.activeBoxes++ : window.activeBoxes = 1;
var shadow = this.attachShadow({
mode: 'open'
});
var template = `
<style>
.blue#iElem {
background: #00f !important;
color: #fff !important;
}
.green#iElem {
background: #0f0 !important;
color: #f00 !important;
}
#iElem {
background: #f00;
padding: 13px;
border-radius: 10px;
color: yellow;
border: 0;
outline: 0;
box-shadow: 0px 0px 14px -3px #000;
}
</style>
<input id="iElem" autocomplete="off" autocorrect="off" spellcheck="false" type="text" />
`;
shadow.innerHTML = template;
this._theme = 'red';
this.changeTheme = function(){
this.shadowRoot.querySelector('#iElem').className = '';
this.shadowRoot.querySelector('#iElem').classList.add(this._theme);
}
}
connectedCallback() {
this.changeTheme();
}
set theme(val){
this._theme = val;
this.changeTheme();
}
}
window.customElements.define('search-bar', InputBox);
<!DOCTYPE html>
<html>
<head>
<title>Wrapper Component</title>
<script src="https://unpkg.com/vue"></script>
<style>
html,
body {
font: 13px/18px sans-serif;
}
select {
min-width: 300px;
}
search-bar {
top: 100px;
position: absolute;
left: 300px;
}
input {
min-width: 20px;
padding: 25px;
top: 100px;
position: absolute;
}
</style>
</head>
<body>
<div id="el"></div>
<!-- using string template here to work around HTML <option> placement restriction -->
<script type="text/x-template" id="demo-template">
<div>
<div class='parent' contentEditable='true' v-if='visible'>
<search-bar ref='iBox'></search-bar>
</div>
<input type='checkbox' v-model='visible'>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select>
<slot></slot>
</select>
</script>
<script>
var vm = new Vue({
el: "#el",
template: "#demo-template",
data: {
visible: true,
},
mounted(){
let self = this
setTimeout(()=>{
self.$refs.iBox.theme = 'blue';
} , 0)
}
});
</script>
</body>
</html>
<div class='parent' contentEditable='true' v-if='visible'>
<search-bar ref='iBox'></search-bar>
</div>
<input type='checkbox' v-model='visible'>
Vue's v-if will add/remove the whole DIV from the DOM
So <search-bar> is also added/removed on every checkbox click
If you want a state for <search-bar> you have to save it someplace outside the <search-bar> component:
JavaScript variable
localStorage
.getRootnode().host
CSS Properties I would go with this one, as they trickle into shadowDOM
...
...
Or change your checkbox code to not use v-if but hide the <div> with any CSS:
display: none
visibility: hidden
opacity: 0
move to off screen location
height: 0
...
and/or...
Managing multiple screen elements with Stylesheets
You can easily toggle styling using <style> elements:
<style id="SearchBox" onload="this.disabled=true">
... lots of CSS
... even more CSS
... and more CSS
</style>
The onload event makes sure the <style> is not applied on page load.
activate all CSS styles:
(this.shadowRoot || document).getElementById("SearchBox").disabled = false
remove all CSS styles:
(this.shadowRoot || document).getElementById("SearchBox").disabled = true
You do need CSS Properties for this to work in combo with shadowDOM Elements.
I prefer native over Frameworks. <style v-if='visible'/> will work.. by brutally removing/adding the stylesheet.

Categories