I want to show my list with their own styling depending on the text they contain.
function TypeFilter() {
const { filterOpen, TypeList } = useGlobalContext();
return (
<div className={filterOpen ? "ft-filter show-filter" : "ft-filter"}>
<div className="filter-wrapper">
{TypeList.map((type, index) => {
const { name } = type;
return (
<div className="filter-btn" key={index}>
{name}
</div>
);
})}
</div>
</div>
);
}
Here, the text is on the {name}, is there a way for me to achieve that?
You can conditionally add class name to your div. You need to add styles in your css file for that new classnames.
function TypeFilter() {
const { filterOpen, TypeList } = useGlobalContext();
return (
<div className={filterOpen ? "ft-filter show-filter" : "ft-filter"}>
<div className="filter-wrapper">
{TypeList.map((type, index) => {
const { name } = type;
const nameClass = name === 'your-condition' ? 'red' : 'blue';
return (
<div className=`filter-btn ${nameClass}` key={index}>
{name}
</div>
);
})}
</div>
</div>
);
}
If name matches the criteria, assign it the desired class
{TypeList.map((type, index) => {
const { name } = type;
let textClass;
if (name === "banana") textClass = "banana-class";
return (
<div className={`filter-btn ${textClass}`} key={index}>
{name}
</div>
);
})}
Related
I'm creating table of content Gutenberg custom block which reactive reflect h2 text.
Outside of map(), it works. but inside not working.
Please let me know how to modify this code.
thanks.
import { registerBlockType } from "#wordpress/blocks";
import { withSelect, select } from "#wordpress/data";
registerBlockType("theme/toc", {
title: "TOC",
icon: "list-view",
category: "layout",
edit: withSelect((select) => {
return {
blocks: select("core/block-editor").getBlocks(),
};
})(Edit),
save: () => {
return null;
},
});
export function Edit(props) {
const { blocks = [] } = props;
const headings = [];
blocks.forEach((el) => {
if (!(el.name === "core/heading" && el.attributes.level === 2)) {
return;
}
headings.push(el.attributes.content);
});
return (
<div>
<p>{headings[0]}</p> // this line works
<ol>
{headings.map((h2, i) => { // not working
<li key={i}>
<a>{h2}</a>
</li>;
})}
</ol>
</div>
);
}
Simply remove the curly braces so the JSXElemnt can be returned from the map function.
<ol>
{headings.map((h2, i) =>
<li key={i}>
<a>{h2}</a>
</li>;
)}
</ol>
something else to note is it's not advised to use the element index i as the key value. you may want to use a more unique value like id from the element you're looping through.
This is a small app created using react-beautiful-dnd. I want to add individual css element for different key values passed through this div element. However I am unable to access this specific div element for the specific key value in css.
<div key={key} className={"column"}>
<ProjectWrapper className="border">
<hr className="hr"></hr>
<h3 className="title">{data.title}</h3>
</ProjectWrapper>
The entire source code:
import React, {useState} from 'react';
import './App.css';
import {DragDropContext, Droppable, Draggable} from "react-beautiful-dnd";
import _ from "lodash";
import {v4} from "uuid";
const item = {
id: v4(),
name: "Clean the house"
}
const item2 = {
id: v4(),
name: "Wash the car"
}
function App() {
const [text, setText] = useState("")
const [state, setState] = useState({
//creating 3 columns
"todo": {
title: "Todo",
items: [item, item2]//temporary data valuesa
},
"in-progress": {
title: "In Progress",
items: []
},
"done": {
title: "Completed",
items: []
}
})
const handleDragEnd = ({destination, source}) => {
if (!destination) {
return
}
if (destination.index === source.index && destination.droppableId === source.droppableId) {
return
}
// Creating a copy of item before removing it from state
const itemCopy = {...state[source.droppableId].items[source.index]}
setState(prev => {
prev = {...prev}
// Remove from previous items array
prev[source.droppableId].items.splice(source.index, 1)
// Adding to new items array location
prev[destination.droppableId].items.splice(destination.index, 0, itemCopy)
return prev
})
}
const addItem = () => {
setState(prev => {
return {
...prev,
todo: {
title: "Todo",
items: [
{
id: v4(),
name: text
},
...prev.todo.items
]
}
}
})
setText("")
}
//the dragdropcontext is the wrapper for draging elements
//dropable is the certain area inside the column where u can drop items
//dragble are the items in the column to be dragged
//here {_.map(state, (data, key) => {
//the above function is used to return the data and key of all 3 elements mentioned under use state() above
//the key: returns todo,inprogress,and done
//where as the data returns all the values of the variables within each key
return (
<div className="App">
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)}/>
<button onClick={addItem}>Add</button>
</div>
<DragDropContext onDragEnd={handleDragEnd}>
{_.map(state, (data, key) => {
return(
<div key={key} className={"column"}>
<h3>{data.title}</h3>
<Droppable droppableId={key}>
{(provided, snapshot) => {
return(
<div
ref={provided.innerRef}
{...provided.droppableProps}
key = {"Todo"}
className={"droppable-col"}
>
{data.items.map((el, index) => {
return(
<Draggable key={el.id} index={index} draggableId={el.id}>
{(provided, snapshot) => {
console.log(snapshot)
return(
<div
className={`item ${snapshot.isDragging && "dragging"}`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{el.name}
</div>
)
}}
</Draggable>
)
})}
{provided.placeholder}
</div>
)
}}
</Droppable>
</div>
)
})}
</DragDropContext>
</div>
);
}
export default App;
May I suggest using a utility like clsx
It will apply the specific class based on your value like so:
import clsx from 'clsx';
export default function App() {
const key = 'todo'; // or 'in-progress' or 'done'
return (
<div className={clsx('existingClass', key)}>
.
.
.
</div>
);
}
Which renders as <div class="existingClass todo">...</div>. You can configure your CSS classnames for the dynamic values. (in this case, todo)
// https://github.com/lukeed/clsx/blob/master/src/index.js
// MIT © Luke Edwards
function toVal(mix) {
var k, y, str='';
if (typeof mix === 'string' || typeof mix === 'number') {
str += mix;
} else if (typeof mix === 'object') {
if (Array.isArray(mix)) {
for (k=0; k < mix.length; k++) {
if (mix[k]) {
if (y = toVal(mix[k])) {
str && (str += ' ');
str += y;
}
}
}
} else {
for (k in mix) {
if (mix[k]) {
str && (str += ' ');
str += k;
}
}
}
}
return str;
}
function clsx() {
var i=0, tmp, x, str='';
while (i < arguments.length) {
if (tmp = arguments[i++]) {
if (x = toVal(tmp)) {
str && (str += ' ');
str += x
}
}
}
return str;
}
// https://github.com/lukeed/clsx/blob/master/src/index.js
// MIT © Luke Edwards
//-------------------
function App() {
const key = ['todo', 'in-progress', 'done'];
return (
<div className="App">
{key.map((k) => (
<span className={clsx('text', k)}>{k} - </span>
))}
</div>
);
}
ReactDOM.render(<App />, document.getElementById("react"));
.App {
font-family: sans-serif;
text-align: center;
}
.text{
font-size: 16px;
margin: 12px;
}
.todo {
color: orange;
}
.in-progress {
color: magenta;
}
.done {
color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I'm currently building a custom Hero block. I've added a ToggleControl to hide or show content within this block. This does work on the edit section in gutenberg block, it also needs to add a class to the wrapper. This also works on the edit section.
The strange thing is, it does not work on the save section of the block. The code I use to set the class is the one below:
It does work like expected in the edit section
edit: function( props ) {
const { attributes, className } = props;
const wrapperStyle = {
backgroundColor: attributes.backgroundColor,
backgroundImage: attributes.backgroundImage && 'url(' + attributes.backgroundImage + ')',
};
const classes = classnames(
className,
dimRatioToClass( attributes.backgroundOpacity ),
{
'has-background-dim': attributes.backgroundOpacity !== 0,
},
attributes.position,
{ [ `align${ attributes.align }` ]: attributes.align && attributes.fullWidthBackground },
{ [ `has-${ attributes.includeContent ? 'content' : 'no-content' }` ] : attributes.includeContent },
);
return (
<Fragment>
<Inspector { ...props } />
<div style={ wrapperStyle } className={ classes }>
<div className="wrapper-inner">
<div className="wrapper-inner-blocks">
{ attributes.includeContent === true &&
<InnerBlocks />
}
</div>
</div>
</div>
</Fragment>
);
},
But on the save section the style is not applied and the conditional tag is not working. See the code below.
Am I missing something?
save: function( props ) {
const { attributes, className } = props;
const wrapperStyle = {
backgroundColor: attributes.backgroundColor,
backgroundImage: attributes.backgroundImage && 'url(' + attributes.backgroundImage + ')',
};
const classes = classnames(
className,
{ [ `has-${ attributes.includeContent ? 'content' : 'no-content' }` ] : attributes.includeContent },
{ [ `align${ attributes.align }` ]: attributes.align && attributes.fullWidthBackground },
dimRatioToClass( attributes.backgroundOpacity ),
{
'has-background-dim': attributes.backgroundOpacity !== 0,
},
attributes.position,
);
return (
<div style={ wrapperStyle } className={ classes }>
<div className="wrapper-inner">
<div className="wrapper-inner-blocks">
{ attributes.includeContent === true &&
<InnerBlocks.Content />
}
</div>
</div>
</div>
);
}
} );
I can not comment, so, I have to post this an answer instead :/
I'm guessing the attributes.includeContent prop is the ToggleControl is question, yes?
Is it set as a Boolean in the attributes?
What do you get when you console.log it in the save? What about when you console.log its type in save? I'm just wondering if it is ending up as a string which would eval to true.
I have a block that renders titles of all existing posts in the <Modal/>. I retrieve it from the server using <ServerSideRender/> (that returns plain html). I want to be able to choose one of the titles (ideally save it in the postTitle attribute) and display it in the block.
attributes: {
postTitle: {
type: 'string'
}
},
edit(props) {
const { attributes } = props;
const { postTitle } = props.attributes;
const MyModal = withState( {
isOpen: false,
} )
( ( { isOpen, setState } ) => (
<div>
<Button isDefault onClick={ () => setState( { isOpen: true } ) }>Choose</Button>
{ isOpen ?
<Modal onRequestClose={ () => setState( { isOpen: false } ) }>
<ServerSideRender
block="my-blocks/wordpress-title"
attributes={attributes}
/>
</Modal>
: null }
</div>
) );
return ([
<InspectorControls>
<div>
<strong>Choose Wordpress title:</strong>
<MyModal/>
</div>
</InspectorControls>,
]);
},
Is there any sensible way to retrieve data from a server, so it was possible to operate on it within a block?
OS: Windows 10 Pro
apollo-client: 1.9.2
react-redux: 5.0.6
So, I'm attempting to read 'connect' a graphql resultset to redux but am receiving the above mentioned error message. My code is as follows:
import { connect } from 'react-redux';
class PhotoGrid extends React.Component {
render () {
const { data } = this.props;
const isNewPage = this.props.location.pathname.includes('new');
if (data.loading) {
return <p>Loading ...</p>;
}
if (data.error) {
return <p>{data.error.message}</p>;
}
return (
<div>
<div>Total record count: {data._allPostsesMeta.count}</div>
<div className="photo-grid">
{ data.allPostses.map( (post,i) => <Photo {...this.props} key={i} postIndexID={i} post={post} />) }
</div>
{isNewPage && (
<div>
<div onClick={() => this.previousPage()}>
Previous
</div>
<div onClick={() => this.nextPage()}>
Next
</div>
</div>
)}
</div>
);
}
};
const allPostsCommentsQuery = graphql(All_Posts_Comments_Query, {
options: ownProps => {
const page = parseInt(ownProps.match.params.page, 10);
const isNewPage = ownProps.location.pathname.includes('new');
const skip = isNewPage ? (page - 1) * parseInt(PRODUCTS_PER_PAGE) : 0;
const first = isNewPage ? parseInt(PRODUCTS_PER_PAGE) : parseInt(PRODUCTS_PER_PAGE);
const orderBy = isNewPage ? OrderBy : null;
fetchPolicy: 'network-only';
return {
variables: {
__offline__: true,
first,
skip,
orderBy,
},
}
},
});
export default connect(allPostsCommentsQuery)(PhotoGrid)
What am I overlooking here?