MUI Datatables Column Header Not Tidy - reactjs

I was using MUI-Datatables in 2020, and I really satisfied with it so I want to use it again with my upcoming project. Lately, Material UI was upgrading and I think MUI-Datatables have styling issue regarding the placement of column headers.
I am using MUI Datatables with this simple ReactJS code:
import Checkbox from '#mui/material/Checkbox';
import FormControlLabel from '#mui/material/FormControlLabel';
import MUIDataTable from "mui-datatables";
function UserList(props){
const {title} = props;
const columns = [
{
"name": "name",
"label": "Name",
"options": {
"filter": true,
"sort": true,
}
},
{
"name": "username",
"label": "Username",
"options": {
"filter": true,
"sort": true,
}
},
{
"name": "active",
"label": "Active",
"options": {
"customBodyRender": (value) => {
return <FormControlLabel control={<Checkbox checked={value} color="success" />} disabled label="" />;
},
"filter": true,
"sort": false,
}
}
];
const dummyData = [
{
"name": "Administrator",
"username": "admin#gmail.com",
"active": true
},
{
"name": "Jalaluddin AF",
"username": "jalaluddin#gmail.com",
"active": true
},
{
"name": "Alex",
"username": "alexandro#gmail.com",
"active": false
}
];
const options = {
selectableRows: "none",
viewColumns: false
};
return(
<MUIDataTable
columns={columns}
data={dummyData}
options={options}
title={title}
/>
);
}
export default UserList;
Basically, it was just showing a table with Name, Username, and Active/Inactive checkbox. But the thing is, when I start npm, the column header aren't in place with its value.
Anyone could help me?
My environment:
#mui/icons-material: 5.2.0
#mui/material: 5.2.0
#mui/styles: ^5.2.0
mui-datatables: ^4.0.0
react: 17.0.2

I think there is some clash with the libraries. Can you check if you are not using multiple version. You can also override the existing css using inspect element.

Related

How do I iterate, dynamically load my form input elements and then retrieve the input values on Form Submit in React?

I am creating a sample dynamic form and I want to load my input elements based on a JSON which contains different input elements like "textbox", "text-area", "dropdown", "radio-input" and so on..
I have a JSON file created to get this as shown below:
[
{
"id": "1",
"type": "textbox",
"text": "",
"required": true,
"label": "lbl"
},
{
"id": "2",
"type": "textbox",
"text": "",
"required": true,
"label": "Specification Name"
},
{
"id": "3",
"type": "dropdown",
"text": "",
"required": true,
"label": "Specification Reviewed",
"options":["a","2"]
},
{
"id": "4",
"type": "dropdown",
"text": "",
"required": true,
"label": "Action Required",
"options":["1","2","3"]
},
{
"id": "5",
"type": "textbox",
"text": "",
"required": true,
"label": "lbl"
}
]
I have an App base component which calls another component called "Input" which has my layout and I retrieve the elements through that component. I am able to pull the text box and dropdown here but I am not able to iterate through the dropdown select. I'm not sure how to do it.
Here's my App Base solution: Here I use the map concept to fetch the data from the JSON local file and assign it to inputvalues which I then use in the return within the form tag.
I'm able to list all my input elements dynamically
But I'm not able to get the dropdown values from my JSON file
function App() {
const [inputObject, setInputObject] = React.useState(inputData)
const inputvalues = inputObject.map( input => {
return (
<Input
key={input.id}
input={input}
/>
)
})
const handleSubmit = (event) => {
event.preventDefault();
}
return (
<div className="App">
<header className="App-header">
<form>
<div>
{inputvalues}
</div>
<input type="submit" value="submit" onClick={handleSubmit} />
</form>
</header>
</div>
);
}
export default App;
And, here's my input.js component file: This basically lays out the input elements and I fetch the data using Props but I am unable to fetch the dropdown selection values because I would need to somehow iterate within each of those dropdown elements.
export default function Input(props) {
const [state, setState] = React.useState({
textBoxValue: ""
})
function handleChange(evt) {
setState({ [props.input.id] : evt.target.value });
}
if (props.onChange) {
props.onChange(state);
}
return (
<div>
<label>{props.input.type}: </label>
{props.input.type === "textbox" && <input name={props.input.type} placeholder={props.input.type} id={props.input.id} value={state.firstName} onChange={handleChange}/>}
{props.input.type === "dropdown" && <select name={props.input.type} id={props.input.id}>
<option value={props.input.options}></option></select>
}</div>)}
Please help me or guide me because I'm still learning React.
In addition to this, how would i later get all the input values upon FORM SUBMIT ? For this I tried adding a handleChange event to see if data comes through but it does not work.
Thank you so much in advance!
You may find Yup and Formik useful.
With Yup, you can include types to fields as well as things such as if the field is required.
The example linked should get you in the right direction.
Edit - (after OP comment)
So without using any external library, you could do something like this:
// Get a hook function
const {useState} = React;
const INPUTS = [
{
"id": "1",
"type": "textbox",
"value": "",
"required": true,
"label": "lbl"
},
{
"id": "2",
"type": "textbox",
"value": "",
"required": true,
"label": "Specification Name"
},
{
"id": "3",
"type": "dropdown",
"value": "",
"required": true,
"label": "Specification Reviewed",
"options":["a","2"]
},
{
"id": "4",
"type": "dropdown",
"value": "",
"required": true,
"label": "Action Required",
"options":["1","2","3"]
},
{
"id": "5",
"type": "textbox",
"value": "",
"required": true,
"label": "lbl"
}
];
const convertArrayToObject = (array, key, targetKey) => {
const initialValue = {};
return array.reduce((obj, item) => {
return {
...obj,
[item[key]]: item[targetKey],
};
}, initialValue);
};
const Form = () => {
const [formState, setFormState] = useState(
convertArrayToObject(INPUTS, "id", "value")
);
const handleChanges = (keyName) => (e) => {
const newValue = e.target.value
setFormState(prev => ({
...prev,
[keyName]: newValue
}));
}
console.log(formState);
return (
<form>
{INPUTS.map((input, inputIndex) => (
<div key={inputIndex}>
<label htmlFor={input.id}>{input.label}</label>
{input.type === "dropdown" && input.options ? (
<select onChange={handleChanges(input.id)}>
{input.options.map((option, optionIndex) => (
<option
key={optionIndex}
value={option}>{option}
</option>
))}
</select>
) : (
<input
id={input.id}
name={input.id}
required={input.required}
type={input.type}
onChange={handleChanges(input.id)}
value={formState.value}
/>
)}
</div>
))}
</form>
);
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<Form />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
A little reasoning behind some of the code written:
React wants a key prop to be passed when mapping over objects (hence I've added it for each wrapper div and option element.
I've mapped over the INPUTS object to build the initial state, and then created an onChange handler that is curried, that way it is generic enough to be used everywhere
I'm just console.loging the formState to demonstrate the changes as you update the form.
Beyond
Consider adding Auto Complete if applicable or worthwhile
You will of course need some kind of some kind of submit button if you plan to submit the data to an API.
<button type="submit">Submit</button
But I will leave that as an exercise for you...
Hope this helps!

Gutenberg blocks - print attributes query (react.js)

I'd like to display a button in my plugin that creates a custom Wordpress block. I have a problem, I cannot display an attribute from the query array:
block.json:
"hero_button_1": {
"type": "array",
"source": "query",
"selector": "a",
"query": {
"url": {
"type": "string",
"source": "attribute",
"selector": "a",
"attribute": "href"
},
"title": {
"type": "string",
"source": "attribute",
"selector": "a",
"attribute": "title"
},
"text": {
"type": "array",
"source": "children",
"selector": "a"
}
}
}
edit.js
const buttonHeroURL = ( newURL ) => {
setAttributes( {
hero_button_1: {
url: newURL
}
} )
}
<RichText
{...blockProps}
tagName="a"
onChange={buttonHeroURL}
allowedFormats={['core/bold', 'core/italic']}
value={attributes.hero_button_1.url}
placeholder={__('Adress url button')}
/>
save.js
<RichText.Content
{ ...blockProps }
tagName="a"
className={"mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto
md:mt-5 md:text-xl lg:mx-0"}
value={ attributes.hero_button_1.url }
/>
I need to create custom buttons in which it will be possible to specify the url and the button name on the backend side of Wordpress.
Thank you for your help :)
Add this to your code (i am assuming you have the base construct working):
<RichText
{...blockProps}
tagName="a"
onChange={(value) => {
setAttributes({hero_button_1: value})
}}
allowedFormats={['core/bold', 'core/italic']}
value={hero_button_1}
placeholder={__('Adress url button')}
/>
This will set the value on the hero_button_1 directly. If you want it inside as an object, you'll have to deal with creating a JSON String.
For this to work you'll also have to get your attributes and the setAttributes in your edit function:
https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/
Similar to this example of mine:
https://stackoverflow.com/a/73544454/7262739

Creating a map function inside a map in React

I have a JSON array like below. I want to generate dynamic components using the array. I have an array inside the array and need to generate a checkbox dynamically inside a card.
export const DemoProductSpec =
{
"productSpecCharacteristic": [
{
"configurable": false,
"name": "testing",
"productSpecCharacteristicValue": [
{
"value": 2000
},
{
"value": 2002
},
{
"value": 2003
}
],
},
{
"configurable": false,
"name": "testing2",
"productSpecCharacteristicValue": [
{
"value": 20003
},
{
"value": 200233
},
{
"value": 200333
},
{
"value": 20034
}
],
},
]
}
My react code is as below. but this code is not working. first map function is working. but the second map is not working.
{DemoProductSpec.productSpecCharacteristic.map((Characteristic) => (
<Card
title={Characteristic.name}
bordered={true}
size="small"
extra={
<Radio.Group onChange={onChange} value={value}>
<Radio value={1}>Deafult</Radio>
<Radio value={2}>Overriden</Radio>
</Radio.Group>
}
>
{" "}
<span>Values: </span>
{Characteristic.productSpecCharacteristicValue.map((Values) => (<Checkbox>{Values.value}</Checkbox>))}
</Card>
))
}

Filter an array of objects to render items according to checkboxes selected in React using hooks

What am I missing here?? I'm stuck trying to filter an array of objects conditionally in React. I have everything set up and working as I believe it should, but I think I'm just mixing a few things up in my inexperience.
Ultimately I want to have all my objects rendered at start, but then filter according to checkboxes selected. For some reason the conditional statement for what to render is not working at all, and while I'm able to get my checkboxes state stored and changed with each click, I am not able to get it to filter.
Here is my code for the component(StoneDisplay.js) This renders the list of checkboxes for filtering the list of stones to display, as well as the container that displays the list of stones. It contains instances of State for my checkboxes, along with the conditional rendering code for which stones to display. To state the obvious, without the conditional code, all items render fine.
import React, { /* useEffect, */ useState } from 'react'
import StoneFilter from '../StoneFilter/StoneFilter'
import Stone from '../Stone/Stone'
import './StoneDisplay.css'
const StoneDisplay = ({ stones }) => {
const [checkedType, setCheckedType] = useState({})
const [checkedColor, setCheckedColor] = useState({})
//const [stonesToShow, setStonesToShow] = useState(stones) // for useEffect
console.log('stones in StoneDisplay: ', stones)
//console.log('stonesToShow in Display: ', stonesToShow) // for useEffect
console.log('checkedType in StoneDisplay: ', checkedType)
console.log('checkedColor in StoneDisplay: ', checkedColor)
///// This is code I am trying to filter stones conditionally without instance of state. /////
const stonesToShow = (checkedType === {} && checkedColor === {}) // (checkedType.length === 0 && checkedColor.length === 0) tried this too, but had difficulty with length and current setup..
? stones
: stones.filter(item => item.type === checkedType && item.color === checkedColor) // need to figure what is wrond with this filter
//stones.filter((item) => true) // Use this filter to 'override' filter to show rendering functions work.
console.log('checkedType.length: ', checkedType.length) // attempt to try and use .length for initial statement for conditional
console.log('checkedColor.length: ', checkedColor.length)// i.e. (checkedType.length === 0 && checkedColor.length === 0) ? ..
///// This code I'm trying to filter stones using state/useEffect that has been recommended. /////
// useEffect(() => {
// setStonesToShow(currentStones => {
// console.log('currentStones in useEffect: ', currentStones)
// return currentStones.filter((item) => true); // Use this filter to 'override' filter to show rendering functions work.
// //return currentStones.filter(item => item.type === checkedType && item.color === checkedColor) // Need to fix this
// })
// }, [checkedType, checkedColor])
return (
<section className="stone">
<StoneFilter
checkedType={checkedType}
setCheckedType={setCheckedType}
checkedColor={checkedColor}
setCheckedColor={setCheckedColor}
/>
<div className="stone__carousel">
{stonesToShow.map((stone) =>
<Stone
key={stone.id}
stone={stone}
/>
)}
</div>
</section>
)
}
export default StoneDisplay
Here is the component containing my checkboxes. I keep coming back here as I believe my problems could be from how I'm handling/saving the state. I am unable to determine how/why though..
import React from 'react'
import StoneFilterListItem from '../StoneFilterListItem/StoneFilterListItem'
import checkboxesType from './checkboxesType'
import checkboxesColor from './checkboxesColor'
import './StoneFilter.css'
const StoneFilter = ({ checkedType, setCheckedType, checkedColor, setCheckedColor }) => {
const handleTypeChange = event => {
setCheckedType({
...checkedType,
[event.target.value]: event.target.checked
})
}
const handleColorChange = event => {
setCheckedColor({
...checkedColor,
[event.target.value]: event.target.checked
})
}
return (
<div className="stone__nav">
<h2 className="stone__nav-head">Type</h2>
<div className="stone__nav-list">
{checkboxesType.map(item => (
<label className="stone__nav-var" key={item.key}>
{item.value}
<StoneFilterListItem
id={item.id}
value={item.value}
checked={checkedType[item.value]}
onChange={handleTypeChange}
/>
<span className="checkmark"></span>
</label>
))}
</div>
<h2 className="stone__nav-head">Couleur</h2>
<div className="stone__nav-list">
{checkboxesColor.map(item => (
<label className="stone__nav-var" key={item.key}>
{item.value}
<StoneFilterListItem
id={item.id}
value={item.value}
checked={checkedColor[item.value]}
onChange={handleColorChange}
/>
<span className="checkmark"></span>
</label>
))}
</div>
</div>
)
}
export default StoneFilter
Here is my component for each checkbox list item:
import React from 'react'
const StoneFilterListItem = ({ type = "checkbox", id, value, checked = false, onChange }) => {
console.log('StoneFilterListItem: ', id, value, checked)
return (
<input type={type} id={id} value={value} checked={checked} onChange={onChange} />
)
}
export default StoneFilterListItem
Here is the checkboxesType.js used for filtering type, chcekboxesColor,js is similar so don't believe I need to post that too.
const checkboxesType = [
{
id: "Marbre",
key: "checkbox1",
label: "marbre",
value: "Marbre"
},
{
id: "Granit",
key: "checkbox2",
label: "granit",
value: "Granit"
},
{
id: "Onyx",
key: "checkbox3",
label: "onyx",
value: "Onyx"
},
{
id: "Travertin",
key: "checkbox4",
label: "travertin",
value: "Travertin"
},
{
id: "Quartz",
key: "checkbox5",
label: "quartz",
value: "Quartz"
},
{
id: "Terrazzo",
key: "checkbox6",
label: "terrazzo",
value: "Terrazzo"
}
]
export default checkboxesType
Adding App.js just incase too:
import React, { useState, useEffect } from 'react'
import Header from '../Header/Header'
import NavBar from '../NavBar/NavBar'
import About from '../About/About'
import StoneDisplay from '../StoneDisplay/StoneDisplay'
import Contact from '../Contact/Contact'
/* import stoneService from '../../services/stones' */
import axios from 'axios'
import './App.css'
const App = () => {
const [stones, setStones] = useState([])
useEffect(() => {
console.log('effect');
axios
.get('http://localhost:3001/stones')
.then(response => {
console.log('promise fulfilled')
setStones(response.data)
})
}, [])
console.log('render', stones.length, 'stones')
return (
<div className="appContainer">
<Header />
<NavBar />
<About />
<StoneDisplay stones={stones} />
<Contact />
</div>
)
}
export default App
Here is stones array. Currently using json server for development:
{
"stones": [
{
"id": 1,
"important": true,
"name": "Bianco Sivec",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/BiancoSivec1.jpg"
},
{
"id": 2,
"important": true,
"name": "Imperial White",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/ImperialWhite1.jpg"
},
{
"id": 3,
"important": true,
"name": "Fantasy White",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/FantasyWhite1.jpg"
},
{
"id": 4,
"important": true,
"name": "Infinito",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Infinito1.jpg"
},
{
"id": 5,
"important": true,
"name": "Fantasy Gold",
"type": "Marbre",
"color": "Beige",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/FatasyGold1.jpg"
},
{
"id": 6,
"important": true,
"name": "Labareda",
"type": "Quartz",
"color": "Multi",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Labareda1.jpg"
},
{
"id": 7,
"important": true,
"name": "Honey Blue",
"type": "Granit",
"color": "Bleu",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/HoneyBlue1.jpg"
},
{
"id": 8,
"important": true,
"name": "Black Taurus",
"type": "Granit",
"color": "Noir",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/BlackTaurus1.jpg"
},
{
"id": 9,
"important": true,
"name": "Lavender",
"type": "Onyx",
"color": "Bleu",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Lavender1.jpg"
},
{
"id": 10,
"important": true,
"name": "Mercury Black",
"type": "Travertin",
"color": "Noir",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/MercuryBlack1.jpg"
},
{
"id": 11,
"important": true,
"name": "Mount Ranier",
"type": "Quartz",
"color": "Beige",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/MountRanier1.jpg"
},
{
"id": 12,
"important": true,
"name": "Red Multicolor",
"type": "Travertin",
"color": "Rouge",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/RedMulticolor1.jpg"
}
]
}
Any help or guidance towards what I'm doing wrong here would be greatly appreciated.
Here is a code sandbox with the relevant components:
https://codesandbox.io/s/cool-keldysh-627yx?file=/src/StoneDisplay.js
I have followed the answer presented below and created an instance of state for stonesToShow(still here, just commented out). I keep hitting road blocks so went back to what I had before to try and sort out filter and then will refactor into the suggested implementation.
Without looking at your detailed implementation, I think you're missing the obvious here: Your stonesToShow array will never react to changes made after the initial render. That's because you defined it as a "normal" variable in the component const stonesToShow = ... and not as a "React" state const [stonesToShow, setStonesToShow] = useState(...)
Here is a very basic example that modifies values in an array, once with useState and once with a "normal" variable in the component:
https://codesandbox.io/s/floral-hooks-nsnvt?file=/src/App.tsx
When you click on the "Modify array" button, you can see that React does not rerender based on changes to the "normal variable".
You need useState/useEffect for that.
So for your example:
const StoneDisplay = ({ stones }) => {
const [stoneType, setStoneType] = useState({})
const [stoneColor, setStoneColor] = useState({})
const [stonesToShow, setStonesToShow] = useState(stones) // initialized from props
useEffect(() => {
setStonesToShow(currentStones => {
return currentStones.filter(item => item.type === stoneType.checked && stoneColor.checked)
})
}, [stoneType.checked, stoneColor.checked]) // re-filter the array when one of these changes
...
Using the useEffect to set the state will actually trigger a rerender.

React react-icons-kit and get Icons dynamically

How to get Icons dynamically in React using extension React Icon kit? I try to find out the way to add a icon dynamically in a MAP-loop as I get them from array "sociallinks"
here is the part of the code
....
import { Icon } from 'react-icons-kit'
import {facebook} from 'react-icons-kit/feather/facebook';
import {instagram} from 'react-icons-kit/feather/instagram';
import {twitter} from 'react-icons-kit/feather/twitter';
....
// dynamic array from redux store
"sociallinks": [
{
"_id": 1,
"type": "facebook",
"linkname": "Facebook",
"link": "https://www.facebook.com/zzzzz/"
},
{
"_id": 2,
"type": "instagram",
"linkname": "Instagram",
"link": "https://www.instagram.com/yyy/"
},
{
"_id": 3,
"type": "twitter",
"linkname": "Twitter",
"link": "https://twitter.com/xxx"
},
{
"_id": 4,
"type": "youtube",
"linkname": "Youtube",
"link": "https://www.youtube.com/user/youtube"
}
]
// problem is here how to markup icon = {xxxxx} from map item.type? item.link and item.linkname works fine.. but not item.type :(((
<ul>
{this.props.data.socialLinks.map((item,i) => (
<li key = {i}> <a href = {item.link}><Icon size={18} icon={item.type} />{item.linkname}</a></li>
))
}
</ul>

Resources