unexpected token in case of conditional rendering - javascript

I am getting this unexpected token error in conditional rendering .However it looks fine to me but couldn't figure out what is going wrong .
{isAdd===true?
countries.map(item=>{
return(
<MenuItem key={item.iso2} value={item.iso2}>{item.name}</MenuItem>
);
}))
:
return (
<MenuItem key={101} value={101}>{'Country1'}</MenuItem>
);
}

Simply add return on the outside of the component (Assuming this is at the top of the render() function):
return isAdd===true ?
countries.map(item=> (
<MenuItem key={item.iso2} value={item.iso2}>{item.name}</MenuItem>
))
:
<MenuItem key={101} value={101}>{'Country1'}</MenuItem>;
If it's nested in the component, simply just include { brackets to treat it like a variable:
render() {
return (
<div>
{isAdd===true ?
countries.map(item=> (
<MenuItem key={item.iso2} value={item.iso2}>{item.name}</MenuItem>
))
:
<MenuItem key={101} value={101}>{'Country1'}</MenuItem>
}
</div>
);
}

There is an issue with your return statement.
Try this...
var returnItem;
{isAdd===true?
countries.map(item => {
returnItem = <MenuItem key={item.iso2} value={item.iso2}>{item.name}</MenuItem>;
})
:
returnItem =<MenuItem key={101} value={101}>{'Country1'}</MenuItem>;
}
return returnItem;

Related

Simplify javascript expression

i have this function in javascript:
export const commonRenderer = (option, useFormatter, hasSubLabel) => {
if (useFormatter && hasSubLabel) {
return (
<React.Fragment>
<FormattedMessage id={option.label} /><br /><FormattedMessage id={option.subLabel} />
</React.Fragment>
);
}
if (!useFormatter && hasSubLabel) {
return (
<React.Fragment>
{option.label}<br />{option.subLabel}
</React.Fragment>
);
}
if (useFormatter && !hasSubLabel) {
return (
<FormattedMessage id={option.label} />
);
}
return option.label;
};
and somehow i want to simplify this seems it looks really odd to me but im afraid of losing some cases. Any help?
Not sure if it's simpler or not, but you may try something like this:
export const commonRenderer = (option, useFormatter, hasSubLabel) => {
const Element = useFormatter ? FormattedMessage : React.Fragment;
const attr = useFormatter ? 'id' : 'children';
return (
<React.Fragment>
<Element {...{ [attr]: option.label }} />
{hasSubLabel && (
<React.Fragment>
<br />
<Element {...{ [attr]: option.subLabel }} />
</React.Fragment>
)}
</React.Fragment>
);
};

Ternary statement not accepted in JSX (Unexpected token "?")

using a ternary statement to render different JSX depending on shouldRenderPlanA property (which resolves true or false). Issue however is that an error appears at the shouldRenderPlanA ternary check with the following:
"Unexpected token ?, expected the token :"
Can anyone explain where I might be going wrong? TIA
return (
<>
{options.map(option)}
<StyledRow>
{variousOptions.map((opt) => (
{shouldRenderPlanA ? (
<StyledLabelOptionOne
variousProps={variousProps}
/>
) : (
<StyledLabelOptionTwo
variousProps={variousProps}
/>
)}
))}
</StyledRow>
</>
);
My suspicion is that it's something to do with the check happening inside the map?
You cannot use nested braces {} in JSX, remove the inner ones and it will work:
return (
<>
{options.map(option)}
<StyledRow>
{variousOptions.map((opt) => shouldRenderPlanA ? (
<StyledLabelOptionOne
variousProps={variousProps}
/>
) : (
<StyledLabelOptionTwo
variousProps={variousProps}
/>
))}
</StyledRow>
</>
);
Here's the problem.
(
{shouldRenderPlanA ? (
You can't expect to return an object, instead
(shouldRenderPlanA ?
Or try to write something simple at the beginning , ex. flag?1:0 to get it working before plugging other things :)
You have an error because you didn't return a value inside the map
Maybe this can help you
return (
<>
{options.map(option)}
<StyledRow>
{variousOptions.map((opt) => {
return shouldRenderPlanA ? (
<StyledLabelOptionOne
variousProps={variousProps}
/>
) : (
<StyledLabelOptionTwo
variousProps={variousProps}
/>
}
))}
</StyledRow>
</>
);
You muset remove the parentheses, and return the element

React nested rendering

I have an object containing several arrays like:
const Items = {
Deserts: [{name:cookies}, {name:chocolate}],
Fruits: [{name:apple}, {name:orange}]
...
}
I want to render it as:
<title>Deserts</title>
Cookies
Chocolate
<title>Fruits</title>
Apple
Orange
So first I render the type:
return <Grid>
{Object.keys(Items).map(type => {
return <Box key={type}>
{type} // <== this would be the title, Fruits or whatever
{this.createCard(Items[type])}
</Box>
})}
</Grid>
Then I want to add the content of each type:
createCard = (items) => {
return <Box>
{items.forEach(item => {
return <div>{item.name}</div>
})}
</Box>
}
Content is not returned, it works fine if instead of a forEach loop I just add some predefined content.
The forEach method only iterates over all items but does not return anything. Instead, what you want to use is a map.
Also, make sure you wrap your return value when it extends more than one line:
createCard = (items) => {
return (<Box>
{items.map(item => {
return <div>{item.name}</div>
})}
</Box>);
}
If you don't do that it works as if a semicolon was introduced after the first line. So, in reality, your current code is equivalent to:
createCard = (items) => {
return <Box>;
// The code below will never be executed!
{items.forEach(item => {
return <div>{item.name}</div>
})}
</Box>
}
When returning an element you need to wrap it in parentheses, ( ) and I generally use map instead of forEach.
const createCard = items => {
return (
<Box>
{items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)
}
I believe you can also nix the curly braces if the function doesn't need any logic.
const createCard = items => (
<Box>
{items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)
-- Edit --
Now that I'm reading back over your question a much cleaner way to approach this would be to declare the component function outside of your class like
class Grid extends react.Component {
render(){
return (
<Box>
<CreateCard props={ item }/>
</Box
)
}
}
const CreateCard = props => (
<Box>
{props.items.map(item => {
return ( <div>{item.name}</div> )
})}
</Box>
)

How to properly print values from a nested loop in a react render() method?

As you can see in my code example below which is part of a render() block in a react component, I am trying to render the value of the variable "folder" in the outer loop. Unfortunately, the code section
<div>{folder}</div>
seems to be ignored. Can anyone help me in finding the right syntax that outputs the current folder value from the outer loop?
{
folders.map((folder,_index1) => {
<div>{folder}</div>
return (
items.map((item, index) => {
return (
<div>
{(folder === item.folder) ?
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{ ...provided.draggableProps }
{ ...provided.dragHandleProps }
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}>
<div>
{item.content}
</div>
</div>
)}
</Draggable>
: null
}
</div>
)})
)})
}
Following Zydnar's comment above:
This is what it should look like:
{
folders.map((folder,_index1) => {
return (
<> // or <React.Fragment> with the corresponding closing tag
<div>{folder}</div> // this has to be part of what is returned
items.map((item, index) => {
return (
<div>
{(folder === item.folder) ?
...
</>
)})
)})
}

React + MaterialUi handling actions in IconMenu and ListItem

I'm learning react and I try to create simple TODO based on material-ui, I have problem with handling IconMenu menu actions, menu is displayed in listItem element. At this moment I have no idea how trigger deleteItem function with item name as a parameter when delete action is clicked in menu.
const iconButtonElement = (
<IconButton touch={true} tooltip="More" tooltipPosition="bottom-left">
<MoreVertIcon color="black"/>
</IconButton>
);
const rightIconMenu = (
<IconMenu iconButtonElement={iconButtonElement}>
<MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
<MenuItem value="delete" leftIcon={<Delete />}>Delete</MenuItem>
</IconMenu>
);
class TodoElements extends Component {
deleteItem(nameProp)
{
this.props.delete(nameProp);
}
render() {
var listItemRender = function(item) {
return <ListItem key={item.name} primaryText={item.name} style={listItemStyle} rightIconButton={rightIconMenu}/>
};
listItemRender = listItemRender.bind(this);
return (
<List>
{this.props.items.map(listItemRender)}
</List>
)
}
}
As far as I can see, you should be able to add an onChange handler to your IconMenu. So your rightIconMenu can look like this:
const RightIconMenu = ({onChange}) => (
<IconMenu iconButtonElement={iconButtonElement} onChange={onChange}>
<MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
<MenuItem value="delete" leftIcon={<Delete />}>Delete</MenuItem>
</IconMenu>
);
Then you can use it in your TodoElements like this:
class TodoElements extends Component {
constructor(props){
super(props);
this.state = {
items: props.items
};
}
createChangeHandler = (nameProp) => {
return (event, value) => {
if(value==="delete"){
this.deleteItem(nameProp);
}
};
}
deleteItem = (nameProp) =>
{
this.setState({
items: this.state.items.filter((item) => {
return item.name !== nameProp);
})
});
}
render() {
return (
<List>
{this.state.items.map((item) => {
<ListItem key={item.name} primaryText={item.name} style={listItemStyle}
rightIconButton={<RightIconMenu onChange={this.createChangeHandler(item.name)} />}/>
})}
</List>
)
}
}
Alternative
As an alternative solution you could bind an onClick handler to your delete MenuItem instead. I would probably implement it like this:
const RightIconMenu = ({onDelete}) => (
<IconMenu iconButtonElement={iconButtonElement}>
<MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
<MenuItem value="delete" leftIcon={<Delete />} onClick={onDelete}>Delete</MenuItem>
</IconMenu>
);
And then replace the appropriate functions in the TodoElements:
createChangeHandler = (nameProp) => {
return (event, value) => {
this.deleteItem(nameProp);
};
}
render() {
return (
<List>
{this.state.items.map((item) => {
<ListItem key={item.name} primaryText={item.name} style={listItemStyle}
rightIconButton={<RightIconMenu onDelete={this.createDeleteHandler(item.name)} />}/>
})}
</List>
)
}
As for handling the state of your list of items, you should probably take a look at global state management such as Redux.
I think that a nicer approach would be using the onTouchTap every MenuItem has, So the onChange function won't have a switch or many if statements.
I'm actually using it when I iterate over all menu items,
To me it looks like this:
_.map(menuItems, (currItem, index) => {
return (<MenuItem primaryText={currItem.primaryText}
rightIcon={currItem.rightIcon}
leftIcon={currItem.leftIcon}
key={`menu-item-${index}`}
value={currItem.value}}
onTouchTap={currItem.onTouchTap}/>)
})

Categories

Resources