I have some files that load into my react components, which have HTML code.
As it is now, the pure HTML code renders just fine, however there is some 'hidden' code that appears whenever you click certain buttons in other parts of the application or on the text above (think of it like panels that expand when you click on it).
The HTML is hidden just using the good old <div id="someId" style="display:none">.
Anyway I am trying to get the correct panel to expand upon clicking their respective buttons.
So in theory, what I need to do is find the element by id, and switch it's display to block whenever needed, and then switch it back when the parent is clicked again.
Unfortunately I have no idea how to do this and so far have gotten nowhere. As it is now, I have access to the component's ids. What I want to know is how in the world can I access that and get to change whatever is rendering?
Create your function:
function element_do(my_element, what_to_do) {
document.getElementById(my_element).style.display = what_to_do;
}
and latter in code you can append wherever you want through javascript onclick or not depends what do you need:
element_do("someId", "none"); // to hide
element_do("someId", "block"); // to show
or create yourself toggle:
function toggle_element(element_id) {
var element = document.getElementById(element_id);
element.style.display = (element.style.display != 'none' ? 'none' : 'block' );
}
// and you can just call it
<button onClick="toggle_element('some_id')">toggle some element</button>
The react way to do it would be with states. Assuming that you know how to use states I'd do something like this:
class ShowHide extends React.Component {
constructor() {
super();
this.state = {myState: true};
this.onClick = this.onClick.bind(this)
}
onClick() {
this.setState({myState: !this.state.myState}) //set the opposite of true/false
}
render() {
const style = {myState ? "display: none" : "display:block"} //if myState is true/false it will set the style
return (<div>
<button onClick={this.onClick}>Click me to hide/show me </button>
<div id="myDiv" style={style}> Here you will hide/show div on click </div>
</div>)
}
}
Related
I have the below, except currently it's setting the minimize class as default. Toggling works fine, I just would like a unique default class to be show at first before any click has happened. After a click, it would then go between maximize and minimize classes as it does now.
If I could keep the below functionality, and just prevent maximize or minimize classes from being added automatically, this should solve the issue, however anytime I try to remove it breaks.
class ToggleIt extends Component {
constructor(props) {
super(props)
this.state = {
expandedTray: false,
}
this.toggleExpandedTray = this.toggleExpandedTray.bind(this);
}
toggleExpandedTray() {
this.setState({ expandedTray: !this.state.expandedTray, });
}
render() {
return (
<div
className={`something--isi-tray ${this.state.expandedTray ? 'expanded-tray' : 'minimize-tray'}`}
onClick={this.toggleExpandedTray}
>
<div className="something--isi-tray__content">
<h3>{this.props.mainHeadingTitle}</h3>
<div
data-rte-editelement
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(this.props.isiContent)
}}
/>
</div>
</div>
)
}
}
Toggling works fine, I just would like a unique default class to be
show at first before any click has happened.
If I correctly understood you could set null as initial value in state, and then
this.state.expandedTray === null ? "some-class" : this.state.expandedTray ? 'expanded-tray' : 'minimize-tray'
I'm in trouble to create a component like mat-button-toggle-group of material
I create a simple container with an ng-content that wraps buttons and inside it some customized buttons. THe number of components-button can change...
<container-buttons-wrapper>
<component-button>Test 1</component-button>
<component-button>Test 2</component-button>
<component-button>Test 3</component-button>
</container-buttons-wrapper>
component-button has inside only a button tag
<button (click)="setActive()" [ngClass]="active? 'active-class' : 'no-active-class'"><ng-content></button>
I defined a function setActive() that toggle active value
setActive() {
this.active = !this.active
}
But I can't find a solution to control the other buttons into container. I want to reproduce exactly what mat-button-toggle-group. Is possible to define an eventEmitter inside the template html?
Problem: when a button changes its status to "active", container should change the state of the remaining buttons to "inactive".
Solution: Implement two-way communication between buttons and the container:
a button should be able to notify the container that it became active
a container should be able to set the remaining buttons to inactive state (or, a button should be able to know whether it is active or not from the container)
Basically, the container becomes a holder of the shared state for itself and all nested buttons. This state is made available to nested buttons via DI. State can be handled by a separate service, or it can be a part of the container component itself for simplicity (the latter approach is implemented in Material):
const CONTAINER = new InjectionToken<ContainerComponent>();
#Directive({
providers: [{provide: CONTAINER, useExisting: forwardRef(() => ContainerComponent)}]
})
class ContainerComponent {
private selectedButton: ButtonComponent | null = null
toggleButton(button: ButtonComponent) {
if (this.selectedButton = button) {
this.selectedButton = null
} else {
this.selectedButton = button;
}
}
isSelected(button: ButtonComponent): boolean {
return this.selectedButton = button
}
}
#Component({template: `
<button [class.selected]="isSelected()" (click)="onClick()">
<ng-content></ng-content>
</button>
`})
class ButtonComponent {
constructor(#Inject(CONTAINER) private container: ContainerComponent) {}
isSelected() {
return this.container.isSelected(this)
}
onClick() {
this.container.toggleButton(this)
}
}
Update: Pre-selecting a button
How do we set some button as "selected" initially?
Approach 1
One way is doing smth similar to what Material does.
Add "selected" input to a button componentn
In the Container we would read all buttons via ContentChildren
Whenever the input changes, button should update the state in container.
A challenge is that now we have two sources of truth for "selected" flag in a button (button's input and the state coming from the container) - so we need to reconcile them, and the overall code becomes more involved.
Approach 2
Alternatively, let's assume your toggle component has some sort of "value" property. Kind of like html <select> element - each option has value property, and the selected property of the <select> is derived based on that.
In this case, we would have an input in ContainerComponent that allows to set initial value:
class ContainerComponent {
#Input() selected: any
toggleButton(value: any) {
if (this.selected !== value) {
this.selected = value
} else {
this.selected = null
}
}
}
class ButtonComponent {
#Input() value: any
onClick() {
this.container.toggleButton(this.value)
}
}
// usage
<container selected="option-1">
<my-button value="option-1"><my-button>
<my-button value="option-2"><my-button>
</container>
This question already has answers here:
Getting the ID of the element that fired an event
(24 answers)
Closed 10 months ago.
<tooltip message="Click" content="preview"></tooltip>
<tooltip message="Tooltip 1" class="repeat-tooltip" content="Click tooltip 1 preview"></tooltip>
<tooltip trigger="hover" class="repeat-tooltip" message="Hover Tooltip" content="Hover tooltip preview"></tooltip>
New and trying to create a custom tooltip tag and only one tooltip will be active at a time.
<tooltip>
<p class="tooltip-content" control="tooltip">{ message } ref="target"</p>
<div class="tooltip-wrapper" show={show_message} ref="content">
//inner html
</div>
</tooltip>
Trying to use show toggling show_message value to display and hide the tooltips. But show_message is within the context of that particular elements click event. Onclick of a particular tooltip, how can I access other custom tag's context to hide the value of that particular element if that tooltip already open?
this.root.addEventListener('click', (e) => that.toggle_message(e));
this.toggle_message = function(e) {
//here close all other tooltips before opening this one. How can I access the refs of all the open tooltip?
this.show_message = !this.show_message;
this.update();
};
From the specs of Riot.js I could not find anything that will allow you to keep track of all tags of same type so solution that I can think of for this particular scenario is to store collection of tooltips under windows and show/hide them on click of each individual tooltip.
As I do not have all component that you posted, I created bare minimum working example over here.
My demo component look like:
<tooltip>
<p>{ content }</p>
<span riot-style="display: { show_message ? 'inline-block' : 'none' }; background: black; color: white; padding:3px;"> { message } </span>
const self = this;
this.content = opts.content || '';
this.message = opts.message || '';
this.root.addEventListener('click', (e) => self.showTooltip(e));
this.toggle_message = function(show) {
self.show_message = show;
self.update();
};
this.showTooltip = function(e){
const bShow = !self.show_message;
for(var i=0; i<window.tooltips.length; i++){
window.tooltips[i].toggle_message(false);
}
self.toggle_message(bShow);
};
<script>
this.on('mount', function(){
if(!window.tooltips)
window.tooltips = [];
window.tooltips.push(this);
});
</script>
</tooltip>
On mount event it adds it's self to window.tooltips array collection and later when one of the components is clicked, event handler iterates through all registered components and hides them before showing current component.
Update - I found a better solution here using riot events. Add the events to windows and listen to that event on document body click and other trigger elements click, so that you will get the context of all tooltips and close it.
I need to update the CSS, and naturally I used jQuery, but I'm told not to use jQuery with React.
How would I do this properly. I can add more code if needed. I'm simply toggling the bottom border of a div
toggleMarker () {
if (this.state.previous && (this.state.current !== this.state.previous)) {
$('#nav_' + this.state.previous).css("border-bottom", '');
}
if (this.state.previous !== this.state.current) {
$('#nav_' + this.state.current).css("border-bottom", this.color);
}
this.setState({previous: this.state.current});
}
You can manipulate components style inline and you can give conditions according to state variables.
Example
render(){
return(
<div style={{ borderBottom: ((this.state.previous && (this.state.current !== this.state.previous)) ? 'none' : 1) }}>
// ...
</div>
)
}
When it comes to react, there are many ways to style a component including inline styles, define styles in css and import, using styled components and also using some small JS libraries e.g. classnames.
classnames supports any JS expression as class name to your HTML element. You can explore more using above link.
Just a simple example:
import styles from './yourcss.css'
import { classnames } from './classnames/bind'
const cx = classnames.bind(styles)
<div className={cx('divStyle')}>
</div>
I would suggest to have inline CSS with reference from variable in the state. consider this,
//define state
this.state={
toggleState : false}
//have toggler function
togglerFunction(){
var temp = this.state.toggleState
this.setState({
toggleState : !temp})
}
//in render you can have your element like this
render(){
...
//start of your element suppose a div
{this.state.toggleState == false ? <div style=
{{borderBottom:"YourValueForFalseHere"}}></div>:<div style=
{{borderBottom:"YourValueForTrueHere"}}></div>}
//...End of your element
...
}
So basically what I am doing is iterating through an array of data and making some kind of list. What I want to achieve here is on clicking on a particular list item a css class should get attached.
Iteration to make a list
var sports = allSports.sportList.map((sport) => {
return (
<SportItem icon= {sport.colorIcon} text = {sport.name} onClick={this.handleClick()} key= {sport.id}/>
)
})
A single list item
<div className="display-type icon-pad ">
<div className="icons link">
<img className="sport-icon" src={icon}/>
</div>
<p className="text-center">{text}</p>
</div>
I am not able to figure out what to do with handleClick so that If I click on a particular list it gets highlighted.
If you want to highlight the particular list item it's way better to call the handleClick function on the list item itself, and you can add CSS classes more accurately with this approach,
here is my sample code to implement the single list component
var SingleListItem = React.createClass({
getInitialState: function() {
return {
isClicked: false
};
},
handleClick: function() {
this.setState({
isClicked: true
})
},
render: function() {
var isClicked = this.state.isClicked;
var style = {
'background-color': ''
};
if (isClicked) {
style = {
'background-color': '#D3D3D3'
};
}
return (
<li onClick={this.handleClick} style={style}>{this.props.text}</li>
);
}
});
Keep a separate state variable for every item that can be selected and use classnames library to conditionally manipulate classes as facebook recommends.
Edit: ok, you've mentioned that only 1 element can be selected at a time,it means that we only need to store which one of them was selected (I'm going to use the selected item's id). And also I've noticed a typo in your code, you need to link the function when you declare a component, not call it
<SportItem onClick={this.handleClick} ...
(notice how handleClick no longer contains ()).
And now we're going to pass the element's id along with the event to the handleClick handler using partial application - bind method:
<SportItem onClick={this.handleClick.bind(this,sport.id} ...
And as I said we want to store the selected item's id in the state, so the handleClick could look like:
handleClick(id,event){
this.setState({selectedItemId: id})
...
}
Now we need to pass the selectedItemId to SportItem instances so they're aware of the current selection: <SportItem selectedItemId={selectedItemId} ....Also, don't forget to attach the onClick={this.handleClick} callback to where it needs to be, invoking which is going to trigger the change of the state in the parent:
<div onClick={this.props.onClick} className={classNames('foo', { myClass: this.props.selectedItemId == this.props.key}); // => the div will always have 'foo' class but 'myClass' will be added only if this is the element that's currently selected}>
</div>