I have to create button that will change the style of a text object in React Native App - javascript

I have a button, that change textValue of a text object, but I also have to change object's style
this.state = {
login_title: 'Initial Value',
isButtonPressed: true,
};
this.onPressButton= this.onPressButton.bind(this);
}
onPressButton() {
this.setState({
isButtonPressed : !this.state.isButtonPressed,
login_title : (this.state.isButtonPressed) ? 'Second Value' : 'Intial Value',
})
}
...
<Button onPress= {this.onPressButton}>
<ButtonText>Change Value</ButtonText>
<Text>{this.state.textValue}</Text>

In the <Text> widget you can define the style conditionally:
<Text style={this.state.isButtonPressed ? styles.style1 : styles.style2}>
{this.state.textValue}
</Text>
Of course, this means your style1 and style2 need to be defined.

Related

MUI5 React conditional textfield error color

I want to conditionally change the error color (warning orange and error red). I don't want to use useStyle because it's deprecated in mui5. Here is my code :
import { TextField as MuiTextField } from "#mui/material";
const TextField = styled(MuiTextField)(({ theme, isWarning }) => ({
"& .MuiOutlinedInput-root": {
"&.Mui-error": {
"& fieldset": {
borderColor: isWarning
? theme.palette.warning.main
: theme.palette.error.main,
},
"&:hover fieldset": {
borderColor: isWarning
? theme.palette.warning.main
: theme.palette.error.main,
},
"&.Mui-focused fieldset": {
borderColor: isWarning
? theme.palette.warning.main
: theme.palette.error.main,
},
},
},
}));
Then I use it like this :
<TextField
label="Description"
name="description"
value={this.state.description}
onChange={this.handleChange}
error={Boolean(errors?.description)}
isWarning={this.state.isWarning}
/>
It works but I got this error in the console :
Warning: React does not recognize the isWarning prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase iswarning instead. If you accidentally passed it from a parent component, remove it from the DOM element.
So I tried to use lowercase but I got this error :
Received true for a non-boolean attribute iswarning.
How can I do to remove this log ? Maybe there is another to change the color ?
Instead of using a style, you can change the color of the TextField to get the same effect. Make sure error is set to false or it will override the color to red.
<TextField
...
error={Boolean(errors?.description) && !this.state.isWarning}
color={this.state.isWarning ? "warning" : undefined}
/>
The color property docs can be found here.

React formatting HTML element properties from multiple sources

I am iterating over state that holds the data for cards like
cards: [
{ id: 1, name: "p1", value: "Prize 1", imageSrc: "/path/to/image", bgColor: { background: "#FF6384", border: "4px solid #FF6384" }, isVisible: "" },
in my iteration, I am using a ternary to determine one of the classes like
<div className={`prize-card ${this.state.flipped === card ? "flipped" : ""} `} onClick={() => this.clickHandler(card)}>
I see how I can use the ternary to determine a second class on top of standard "prize-card", but how would I add even a third class based on the bgColor state? In a standard HTML element, I can just:
<div className={card.bgColor}>
But I can't figure out the syntax on how to add the {card.bgColor} to the rest of the className below... the bgColor below is wrapped in asterisks to show what I cannot add without errors.
<div className={ **{card.bgColor}**`prize-card ${this.state.flipped === card ? "flipped" : ""} `} onClick={() => this.clickHandler(card)}>
Any help is appreciated. Thank you in advance.

react native - change prop state depending on number of buttons selected

I am using a nightlight button library: react-native-selectmultiple-button
In this library there is a prop selected
Description: Type:Boolean. Default is false. The selected prop determines whether the button is selected and highlighted
Is there a way I can change the state of "selected" prop, depending on number of buttons selected?
For example, if I select more than 5 buttons, I want other buttons to be unselectable.
constructor(props) {
super(props)
this.state = {
numberOfbuttonsSelected:0
}
}
{
if(this.state.numberOfbuttonsSelected <5){
<SelectMulipleButton
selected={true}/>}
else{<SelectMulipleButton
selected={false}/>
}
}
The code above won't work any comments or advise would be really appreciated :)
This is the new code:
<View style={{ flexWrap: 'wrap', flexDirection: 'row',backgroundColor:'gray',paddingTop:10,paddingLeft:6,paddingRight:0,borderColor:'white', borderWidth:1}}>
{
multipleData.map(
(interest) =>
<SelectMultipleButton
key={interest}
buttonViewStyle={{
borderRadius: 0,
height: 40,
width: 110,
}}
textStyle={{
fontSize: 15,
}}
highLightStyle={{
borderColor: 'white',
backgroundColor: 'transparent',
textColor: 'white',
borderTintColor: 'white',
backgroundTintColor: '#6AAAC6',
textTintColor: 'white',
}}
multiple={true}
value={interest}
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)} />
)
}
</View>
</ScrollView>
Sorry for the delay in replying. Please see my example component below. I have included explanations in comments inline in the code. Please reach out if you need further help.
export class YourComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
numberOfbuttonsSelected: 0,
multipleSelectedData: []
};
}
//This method is what you mainly need
trackSelection = value => {
if (!this.state.multipleSelectedData.includes(value)) { //This checks if the value already exists in the checked buttons list
if (this.state.numberOfbuttonsSelected < 5) { //Here we check if the number of selected buttons has exceeded the specified number
this.state.multipleSelectedData.push(value);
this.setState({
numberOfbuttonsSelected: this.state.numberOfbuttonsSelected + 1
});
} //else do nothing. Effectively, we are disabling the click on the button.
} else { //we are simply toggling the selection here
this.state.multipleSelectedData.splice(
this.state.multipleSelectedData.indexOf(value), 1
);
this.setState({
numberOfbuttonsSelected: this.state.numberOfbuttonsSelected - 1
});
}
};
render() {
return (
//Customize your render function. I just included one button as an example.
<View>
<SelectMultipleButton
multiple={true}
value={interest} //"interest" is just an example value. Change it according to your requirements for each button.
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)} //valueTap is supposed to be the "value" prop's value for each
//button according to the lib's documentation, but if you're not comfortable using valueTap, you can
//simply pass "interest" (or your own custom value for the particular button) into the trackSelection() method
/>
</View>
);
}
}
EDIT
I went through the code in the lib and the onPress function in the SelectMultipleButton component is why your multiple selection still works:
<TouchableWithoutFeedback
onPress={() => {
if (this.props.multiple) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
} else {
if (!this.state.selected) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
}
}
}>
I know it's not a good idea to modify library files, but in this case, instead of using the whole lib, you can copy over this file to your project (don't remove the author credit at the top of this file) and add a prop selectable to it and modify the onPress thus:
<TouchableWithoutFeedback
onPress={() => {
if (this.props.multiple) {
if(this.props.selectable) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
} else {
if (!this.state.selected) {
this.setState({ selected: !this.state.selected })
this.props.singleTap(this.props.value)
}
}
}
}>
Pass the prop thus:
<SelectMultipleButton
multiple={true}
value={interest}
selectable={this.state.multipleSelectedData.includes(interest) || this.state.numberOfbuttonsSelected < 5}
selected={this.state.multipleSelectedData.includes(interest)}
singleTap={valueTap => this.trackSelection(valueTap)}
/>
This should solve your problem.

React - changing the background of a single span class not working

I am new to React so my apologies if the question, or the thing I am trying to achieve is just weird (and please do tell if there is a better / more logic way to do this).
I am using the List Fabric React component in my React application, which is based on the ListGridExample component which is found here:
https://developer.microsoft.com/en-us/fabric#/components/list
I have set it up but I can't seem to accomplish the following:
When a span class (which is actually an item) in the List component is clicked, I want to change it's background color, to do this I have followed the instructions in the following post:
https://forum.freecodecamp.org/t/react-js-i-need-a-button-color-to-change-onclick-but-cannot-determine-how-to-properly-set-and-change-state-for-that-component/45168
This is a fairly simple example but this changes all my grid cells / span classes to the color blue instead of only the clicked one. Is there a way I can make just the clicked span class change it's background?
The Initial state:
The state after clicking one span class (which is wrong):
Implementation code (ommitted some unecesary code):
class UrenBoekenGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
bgColor: 'red'
}
}
render() {
return (
<FocusZone>
<List
items={[
{
key: '#test1',
name: 'test1',
},
{
name: 'test2',
key: '#test2',
},
{
name: 'test3',
key: '#test3',
},
{
name: 'test4',
key: '#test4',
},
..... up to 32 items
]}
onRenderCell={this._onRenderCell}
/>
</FocusZone>
);
}
changeColor(item){
this.setState({bgColor: 'blue'});
console.log('clicked item == ' + item.name)
}
_onRenderCell = (item, index) => {
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={true}
style={{
width: 100 / this._columnCount + '%',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
<div className="ms-ListGridExample-sizer">
<div className="msListGridExample-padder">
{/* The span class with the click event: */}
<span className="ms-ListGridExample-label" onClick={this.changeColor.bind(this, item)} style={{backgroundColor:this.state.bgColor}}>{`item ${index}`}</span>
<span className="urenboeken-bottom"></span>
</div>
</div>
</div>
);
};
}
I now have attached the click event to the span class itself but I would think it is way more logic to have the click event on the item(s) (array) itself, however I could not find a way to achieve this either.
----UPDATE----
#peetya answer seems the way to go since #Mario Santini answer just updates a single cell, if another cell is clicked then the previous one returns back to normal and loses it's color.
So what I did is adding the items array to the state and adding the bgColor property to them:
this.state = {
items: [
{
key: '#test1',
name: 'test1',
bgColor: 'blue',
},
{
name: 'test2',
key: '#test2',
bgColor: 'blue',
},
{
name: 'test3',
key: '#test3',
bgColor: 'blue',
},
{
name: 'test4',
key: '#test4',
bgColor: 'blue',
},
],
}
Now in my List rendering I have set the items to the state items array and added the onClick event in the _onRenderCell function:
render() {
return (
<FocusZone>
<List
items={this.state.items}
getItemCountForPage={this._getItemCountForPage}
getPageHeight={this._getPageHeight}
renderedWindowsAhead={4}
onRenderCell={this._onRenderCell}
/>
</FocusZone>
);
}
_onRenderCell = (item, index) => {
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={true}
style={{
width: 100 / this._columnCount + '%',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
<div className="ms-ListGridExample-sizer">
<div className="msListGridExample-padder">
<span className="ms-ListGridExample-label"
onClick={this.onClick(item.name)}
style={{backgroundColor: item.bgColor}}
>
{`item ${index}`}
</span>
<span className="urenboeken-bottom"></span>
</div>
</div>
</div>
);
};
The problem is that I can't add the onClick event in the _onRenderCell function as this will give the following error:
I want to keep the Fabric List component as it also has functions for rendering / adjusting to screen size, removing the list component entirely and just replacing it with what #peetya suggested works:
render() {
<div>
{this.state.items.map(item => (
<div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
{item.name}
</div>
))}
</div>
}
But this will also remove the List component functionality with it's responsive functions.
So my last idea was to just replace the items of the List with the entire onClick div and removing the _onRenderCell function itself, but this makes the page blank (can't see the cells at all anymore..):
render() {
return (
<FocusZone>
<List
items={this.state.items.map(item => (
<div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
{item.name}
</div>
))}
getItemCountForPage={this._getItemCountForPage}
getPageHeight={this._getPageHeight}
renderedWindowsAhead={4}
// onRenderCell={this._onRenderCell}
/>
</FocusZone>
);
}
I thought that perhaps the css ms-classes / div's should be in there as well because these have the height/width properties but adding them (exactly as in the _onRenderCell function) does not make any difference, the page is still blank.
The problem is that you are storing the background color in the state of the Grid and assign this state to every element of the grid, so if you update the state, it will affect every element. The best would be if you create a separate component for the Grid elements and store their own state inside there or if you want to use only one state then store the items array inside the state and add a new bgColor attribute for them so if you want to change the background color only for one item, you need to call the setEstate for the specific object of the items array.
Here is a small example (I did not tested it):
class UrenBoekenGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{
key: '#test1',
name: 'test1',
bgColor: 'blue',
},
],
};
}
onClick(name) {
this.setState(prevState => ({
items: prevState.items.map(item => {
if (item.name === name) {
item.bgColor = 'red';
}
return item;
})
}))
}
render() {
<div>
{this.state.items.map(item => (
<div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
{item.name}
</div>
))}
</div>
}
}
Actually you are changing the color of all the span elements, as you set for each span the style to the state variable bgColor.
Insteas, you should save the clicked item, and decide the color based on that:
this.state = {
bgColor: 'red',
clickedColor: 'blue
}
In the constructor.
Then in the click handler:
changeColor(item){
this.setState({selected: item.name});
console.log('clicked item == ' + item.name)
}
So in the renderer (I just put the relevant part):
<span ... style={{backgroundColor: (item.name === this.state.selected ? this.state.clickedColor : this.state.bgColor)}}>{`item ${index}`}</span>

Uncaught TypeError: Cannot read property 'icon' of null

i have a form for editing the tab. When a edit icon is clicked to edit that tab a form in dialog box appears where the input box has current data in it. But when i hit save without touching the icon field i get an error of Uncaught TypeError: Cannot read property 'icon' of null. If i did not touch the name field and only touch on icon field and hit save button then the tab gets edited. How can i make icon field work too like name field is working ? I mean if i want to only edit name, i can edit the name from name field and save without touching icon field which will save the tab name with edited name and current icon.
How can it be possible?
class EditForm extends Component {
render() {
const { tab } = this.props;
console.log('tab object is', this.props.tab);
const listOfIcon = _.map(this.props.fetchIcon.icons, (singleIcon) => ({
text: singleIcon.name,
id: singleIcon.id,
value: <MenuItem primaryText={singleIcon.name} />
}));
return (
<div>
<form
onSubmit={(e) => {
console.log('auto', e.target.auto);
e.preventDefault();
this.props.editTab(
tab.id,
e.target.text.value,
this.state.icon
);
this.props.closeTabIcon();
}
}
>
<div className="tab-name">
<TextField
hintText={tab.name}
name="text"
defaultValue={tab.name}
hintStyle={{ display: 'none' }}
floatingLabelStyle={{ color: '#1ab394' }}
floatingLabelFocusStyle={{ color: '#1db4c2' }}
underlineStyle={{ borderColor: '#1ab394' }}
/>
</div>
<div className="icon">
<AutoComplete
floatingLabelText={tab.icon}
name="auto"
filter={AutoComplete.noFilter}
openOnFocus
dataSource={listOfIcon}
textFieldStyle={{ borderColor: '#1ab394' }}
className="autocomplete"
onNewRequest={(e) => { this.setState({ icon: e.id }); }}
/>
</div>
<button className="btn">Save</button>
</form>
</div>
);
}
}
const mapStateToProps = state => {
console.log(state);
return {
fetchIcon: state.fetchIcon,
tabs: state.tabs.tabs.map(tab => {
const icons = state.fetchIcon.icons.find(icon => Number(icon.id) === tab.icon);
return {
...tab,
icon: icons && icons.name
};
})
};
};
function mapDispatchToProps(dispatch) {
return bindActionCreators({
editTab,
closeTabIcon
}, dispatch);
}
The state of a componnet is intitated with the null. YOu can set the intital value of state in constrocutor of the class
class EditForm extends Component {
constructor(props) {
super(props)
this.state ={}
}
render() {
const { tab } = this.props;
console.log('tab object is', this.props.tab);
const listOfIcon = _.map(this.props.fetchIcon.icons, (singleIcon) => ({
text: singleIcon.name,
id: singleIcon.id,
value: <MenuItem primaryText={singleIcon.name} />
}));..........
initialize 'input box' with empty value from code behind.

Categories

Resources