im trying to make a nested side menu using nexJS and materialsUI dinamically based on an API response that would look like this:
const Response1 = [
{
id: 1,
name: "Logistics",
icon: "warehouse",
url: "/",
children: [
{
id: 2,
name: "Express",
icon: "precision_manufacturing",
url: "/",
children: [
{
id: 3,
name: "request",
icon: "list_alt",
url: "/Logistica/Express-Cedis",
children: [],
},
],
},
{
id: 5,
name: "Dashboards",
icon: "bar_chart",
url: "/Logistica/Dashboard",
children: [],
},
],
}
]
I was able to iterate the object and get all the items and display them, the only problem is that the ones that are childs should be visible only when clicking the parent, and i only have them all in a list statically, i did this with a code like this:
const mapStructure = (nodes: any) => {
if (nodes) {
return nodes.map((node) => (
<>
<ListItemButton onClick={handleClick}>
<ListItemIcon>
<Icon>{node.icon}</Icon>
</ListItemIcon>
<ListItemText primary={node.name} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
{mapStructure(node.children)}
</>
));
}
};
the idea is that the parent objects display just as the code above, but the children elements display in a collapse like the one below:
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItemButton sx={{ pl: 4 }}>
<ListItemIcon>
<Icon>{node.icon}</Icon>
</ListItemIcon>
<ListItemText primary={node.name} />
</ListItemButton>
</List>
</Collapse>
i tried something like "if node has a child, render like the first example, and when it doesn´t have childs render like the second examle" but i can´t manage to write it correctly
Related
I am using scrollToIndex and scrollToRow but is not working on adding a new message, Also I tried with use ref but was not able to make it work, feel free to suggest. In your text, I would be more than happy to receive.
I want to scroll to the last message when we add a new message.
useEffect(() => {
parentRef.current!?.lastElementChild?.scrollIntoView()
}, [messagesList])
const rowRenderer = useCallback(
({index, isScrolling, key, parent, style, scrollToRow}) => {
const chat = messagesList[index]
console.log(
'cell renderer index : ',
index,
' list length : ',
messagesList.length
)
return (
<CellMeasurer
cache={cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
className='List'
scrollToRow={messagesList.length - 1}
autoHeight={true}
autoWidth={true}
// ref={parentRef}
recomputeRowHeights={index}
recomputeRowWidths={index}
resetMeasurementForRow={index}
resetMeasurementForColumn={index}
resetMeasurements={true}
style={{wordWrap: 'break-word', whiteSpace: 'normal', flexWrap: 'wrap'}}>
{({measure, registerChild}: any) => (
<div style={style}>
<Message
key={chat?.id}
ref={registerChild}
data={chat}
/>
</div>
)}
</CellMeasurer>
)
},
[messagesList, cache]
)
const getMessages = useMemo(() => {
console.log('getting messages....')
return (
<List
scrollToAlignment={'end'}
height={700}
width={wrapperRef.current ? wrapperRef.current?.clientWidth : 100}
style={{width: '100%', border: '2px solid grey'}} // important to maintain the width
itemSize={10}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowCount={messagesList.length}
rowRenderer={rowRenderer}
// scrollToIndex={messagesList.length}
// ref={parentRef}
scrollToRow={messagesList.length - 1}
// scrollToIndex
/>
)
}, [messagesList, wrapperRef.current])
scrollToIndex={messagesList.length - 1} works fine here and this solved my issue
I have a card to display an order and inside the card on cancellation sweetalert2 popup opens asking for cancellation reason. This is working just fine on orders screen.
<Grid item md={8} sm={12}>
orders.map((order) => <SupplierOrderBlock data={order} />)
</Grid>
And on Cancellation these swal fire. First one to ask the user to enter reason and if user doesnt enter a reason the second sweetalert to prompt user to enter a reason in order to cancel.
const cancelOrder = (orderID, status) => {
Swal.fire({
title: "Are You Sure You Want to Cancel Order",
text: "Please Enter the reason for the cancellation of order",
input: "text",
showCancelButton: true,
confirmButtonColor: "#1c8fec",
cancelButtonColor: "#fa013b",
customClass: 'swal-wide'
}).then((result) => {
if (result.value == '') {
swal({
title: "You can not cancel without giving a reason",
showCancelButton: true,
confirmButtonColor: "#1c8fec",
cancelButtonColor: "#fa013b",
buttons: {
Confirm: { text: "Okay", className: "okayButton" },
},
});
}
else if (result.isConfirmed) { //cancel order}
This is working just fine.
Now when i try to use this same component on my dashboard inside a Material UI modal it doesnt let me enter text.
<Modal
open={modal}
onClose={handleClose}
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
style={{ width: "60%", zIndex: 1, marginLeft: '-10%' }}
>
<Box style={{ marginLeft: "50%", marginTop: "25vh", width: "100%", position: 'absolute' }}>
<SupplierOrderBlock data={supplierorder} />
</Box>
</Modal>
If i remove Z-index property from Modal then swal goes behind the modal
But on closing the modal it lets us enter reason
I have a dropdown from Fluent UI and want to change the CSS of the dropdown options.
I can add classes though className to the dropdown, but I can't reach the dropdown options through adding CSS here because the dropdown options exist on a layout on the same level as <div id="root">. Is there a way I can set the CSS only to apply to this dropdown (preferably from the dropdown component)?
My code is as following:
const styles = mergeStyleSets({
main: {
selectors: {
"& .ms-Dropdown-title": {
color: "red"
},
"& .ms-Dropdown-optionText": {
color: "blue" //does not work
}
}
}
});
const Test = () => {
const options = [
{ key: "A", text: "I am an option" },
{ key: "B", text: "Do not choose me" },
{ key: "C", text: "Here is a third option" }
];
return (
<div style={{ width: "300px" }}>
<Dropdown
placeholder="Select an option"
label="Choose something"
options={options}
className={styles.main}
/>
</div>
);
};
Codesandbox:
https://codesandbox.io/s/bold-moon-u0ol2?file=/src/App.js
Just use the styles property:
<Dropdown
placeholder="Select an option"
label="Choose something"
options={options}
styles={{
title: { color: 'red' },
dropdownOptionText: { color: 'blue' }
}}
/>
It gives fine grained control over the single elements of a dropdown that can be styled and, in an editor like VSCode, autocompletion suggests all styleable elements.
Updated Codesandbox: https://codesandbox.io/s/elegant-noyce-ddjek?file=/src/App.js
If you want to use a conditional styling for each dropdown option based on the disabled property, you can do the following:
export const optionsWithCustomStyling: any = (
options: IDropdownOption[]
) =>
options.map((x) => ({
key: x.key,
text: x.text,
styles: {
optionText: {
color: `${x.disabled ? '#FF0000' : '#000000'}`,
},
}
})
)
Following is my code for implementing LeftNav with Toolbar. I am using Material-UI package for meteor. LeftNav does not show up at all. When similar configuration used with AppBar it works fine. Need some help to fix the problem.
var {Toolbar, ToolbarGroup, , ToolbarTitle, FontIcon,FlatButton,ToolbarSeparator,IconButton,LeftNav,FlatButton} = MUI;
let {SvgIcons} = MUI.Libs;
let LeftIcon = <SvgIcons.NavigationExpandMore />
let LeftIcon = <SvgIcons.NavigationExpandMore />
var menuItems = [
{ route: 'get-started', text: 'Get Started' },
{ route: 'customization', text: 'Customization' },
{ route: 'components', text: 'Components' },
{ type: MenuItem.Types.SUBHEADER, text: 'Resources' },
{
type: MenuItem.Types.LINK,
payload: 'https://github.com/callemall/material-ui',
text: 'GitHub'
},
{
text: 'Disabled',
disabled: true
},
{
type: MenuItem.Types.LINK,
payload: 'https://www.google.com',
text: 'Disabled Link',
disabled: true
}
];
injectTapEventPlugin();
Header = React.createClass({
_toggle(e){
e.preventDefault()
this.refs.leftNav.toggle()
},
render(){
return(
<div>
<LeftNav ref="leftNav" docked={false} menuItems={menuItems onLeftIconButtonTouchTap={this._toggle}} />
<Toolbar>
<ToolbarGroup key={0} float="left">
<ToolbarTitle text="React" />
</ToolbarGroup>
<ToolbarGroup key={1} float="right">
<FontIcon className="muidocs-icon-custom-sort" />
<FlatButton label="Questions" linkButton={true} href="/login" secondary={true}/>}
<ToolbarSeparator/>
{Meteor.userId() ? <FlatButton label="Logout" onClick={Meteor.logout}/> : <FlatButton label="Login" linkButton={true} href="/login" primary={true}/>}
</ToolbarGroup>
</Toolbar>
</div>
)
}
});
I'm just looking at this now too. It maybe that these are deprecated items?
https://github.com/callemall/material-ui/issues/2491
however, this is using 0.14 - not sure which version you're on
update: I have a working example and code here:
https://github.com/dcsan/react-hot/blob/master/app/client/layouts/MainLayout.jsx#L25-L53
demo
http://react-hot.meteor.com
hope that helps!
I am creating a treeview styled object using KnockoutJS and need to be able to have x number of children folders and items. Has anyone done a recurring array on screen, I usually use foreach and I can put one child within another but I can't figure out how to change the template to make them recurring, is it even possible? To clarify I can get the items into knockout fine it's simply getting them displayed on screen.
Looked everywhere on the internet but can only find nested templates rather than recurring ones. Can anyone help?
Let me demonstrate how you can achieve this using a template.
Let suppose you have the following viewmodel:
var comments = [{
id: 1,
comment: 'How can i use knockoutjs?',
childrenLength: 3,
children: [{
id: 2,
comment: 'Please search before asking',
childrenLength: 0,
children: []
}, {
id: 3,
comment: 'Please read the documentation',
childrenLength: 0,
children: []
}, {
id: 4,
comment: 'You can see the blog posts on this',
childrenLength: 2,
children: [{
id: 5,
comment: 'Please search before asking',
childrenLength: 0,
children: []
}, {
id: 6,
comment: 'Please search before asking',
childrenLength: 0,
children: []
}]
}]
}, {
id: 7,
comment: 'You question is not sufficient to be asked here?',
childrenLength: 3,
children: [{
id: 8,
comment: 'Please seach before asking',
childrenLength: 0,
children: []
}, {
id: 9,
comment: 'Please read the documentation',
childrenLength: 0,
children: []
}, {
id: 10,
comment: 'You can see the blog posts on this',
childrenLength: 0,
children: []
}]
}]
var vm = function(){
var self = this
self.comments = ko.observableArray(comments)
}
$('document').ready(function () {
ko.applyBindings(new vm())
})
You can see here is multilevel branching. Now you can achieve this with recursion.
<div class="body" data-bind="foreach: comments">
<div data-bind="template: { name: 'childTemplate', data: $data }"></div>
</div>
<script type="text/html" id="childTemplate">
<span data-bind="text:comment"></span>
<!-- ko if: $data.childrenLength > 0 -->
<!-- ko foreach: children -->
<div data-bind="template: { name: 'childTemplate', data: $data }" style="padding-left:35px;"></div>
<!-- /ko -->
<!-- /ko -->
</script>
Fiddle Demo