split function to highlight search term in React - javascript

I have some data that Im mapping through and trying to highlight the search term entered into a field. I have this little section where I pass the string value (which I verified console logs correctly) into my splitResult function. It is supposed to split that string into pieces, index them, and return the string with highlighted parts... how do I return the pieces?? Example: (the item.title should show and is not) If there is not enough code to understand this sandbox might help..
search app
//split the search term
const splitResult = (result) => {
result.split(new RegExp(`(${searchTerm})`, `gi`)).map((piece, index) => {
return <span
key={index}
style={{
background: piece.toLowerCase() === searchTerm.toLocaleLowerCase() ?
"YELLOW" : "TRANSPARENT",
}}
>
{piece} //<--is this right?//
</span>
});
};
//some of the rendering
<div key={item.index}>
<div>{splitResult(item.title)}</div>
{item.content.map((i, index) => {
return <div key={index}>{i.text}</div>;
})}
<div className={styles.searchLink}
onClick={() => {
context.setCurrentSlide(item.index);}}
>Go To This Slide {item.index}
</div>
</div>

Related

How do I get rid of commas showing in my text area? [duplicate]

This question already has answers here:
Removing commas from javascript array
(3 answers)
Closed 1 year ago.
I'm coding a little program to generate a list of groceries, the items are in the screen and when you click on the "+" button, that item goes into the text area and so on. The problem is that after the first item, they all start with a comma for some reason. I know this must be something very basic but I just can't seem to find the issue.
An image of the program running, with the issue.
I have two components besides the main App component, GroceryItem and GroceryItems.
GroceryItem:
export const GroceryItem = (props) => {
return (
<div className="grocery" >
<button
type="button"
id={props.name}
value={props.name}
onClick={() => props.clickHandler(props.name)}
>+</button>
<label htmlFor={props.name}>{props.name}</label>
</div>
)
}
GroceryItems:
export const GroceryItems = () => {
const [items, setItems] = useState([]);
const clickHandler = (v) => {
setItems(prevState => [...prevState, `${v}\n`]);
console.log(typeof v)
}
return (
<>
<div className="groceryContainer" >
{listaMercado.map((el, i) => (
<GroceryItem clickHandler={clickHandler} key={i} name={el} />
))}
</div>
<textarea style={{margin: "30px", width: "300px",height: "300px"}} value={items} readOnly />
</>
)
}
I'm omitting the list because it's just unnecessary.
As Pointy pointed out (nice), you've converted your array to a string so currently you are just displaying the contents of the array as a long string.
To format it without the commas you can use a regular expression to remove all instances of "," when passing your items into the textarea value:
<textarea style={{margin: "30px", width: "300px", height: "300px"}} value={items.replace (/,/g, "")} readOnly />
If you're not familar with regex theres also this solution too:
items.split(",").join("")

in react when I remove a dynamic input, the input does not show the right value on the browser

I'm new in React and i'm learning to use it with hooks.
I tried to put dynamics inputs which works so far but I have a display problem.
If I delete the last input, no problem but if I delete others inputs than the last one then the correct values does not show on the browser.
For example I add 2 inputs.
first one titled "one" and second titled "two".
If I delete "one", the remain input on screen shows "one" or it should show "two".
However, in the array where I collect the inputs infos, there is the correct remaining input.
(see screenshot).
How can I do to show the correct title in the input on the browser ?
const [titleSelected, setTitleSelected] = useState(true);
const [questionType, setQuestionType] = useState([]);
const [questionsTitle, setQuestionsTitle] = useState([]);
{questionType ? (
questionType.map((questions, index) => {
return (
<div key={index} className="questions">
<div className={questions === "texte" ? "orange" : "red"}>
<span>{questions === "texte" ? "1" : "2"}</span>
<img src={Minus} alt="" />
<img
src={questions === "texte" ? FileWhite : StarWhite}
alt=""
/>
</div>
<input
type="text"
placeholder="Ecrivez votre question"
onChange={(event) => {
let tab = [...questionsTitle];
// si index de l'objet existe on update index de l'objet par index sinon on push le nouvel objet
let tabIndex = tab.findIndex(
(element) => element.index === index
);
if (tabIndex !== -1) {
tab[tabIndex].type = questionType[index];
tab[tabIndex].title = event.target.value;
} else {
tab.push({
index: index,
type: questionType[index],
title: event.target.value,
});
}
setQuestionsTitle(tab);
}}
></input>
<div>
<img src={ChevronUp} alt="move up" />
<img src={ChevronDown} alt="move down" />
<img
src={SmallTrash}
alt="delete question"
onClick={() => {
let tab = [...questionType];
tab.splice(index, 1);
setQuestionType(tab);
let tabTitle = [...questionsTitle];
tabTitle.splice(index, 1);
setQuestionsTitle(tabTitle);
}}
/>
</div>
</div>
);
})
) : (
<div></div>
)}
<div className="questionType">
<div
className="addText"
onClick={() => {
let tab = [...questionType];
tab.push("texte");
setQuestionType(tab);
}}
>
<img src={File} alt="" />
<p>Ajouter une question "Texte"</p>
</div>
<div
className="addNote"
onClick={() => {
let tab = [...questionType];
tab.push("note");
setQuestionType(tab);
}}
>
<img src={Star} alt="" />
<p>Ajouter une question "Note"</p>
</div>
</div>
screenshot
Issues
You are mutating the array you are mapping so don't use the array index as the react key. If you remove the ith element all the elements shift up, but the keys remain unchanged and react bails on rerendering.
Lists & Keys
questionType.map((questions, index) => (
<div key={index} className="questions">
...
</div>
)
The array index as a React key doesn't "stick" to the element object it "identifies".
You've also some state object mutation occurring.
tab[tabIndex].type = questionType[index];
tab[tabIndex].title = event.target.value;
This is masked by the shallow copy let tab = [...questionsTitle];.
Solution
Select a react key that is unique among siblings and related to the elements, like an id.
Since you enclose the index when adding new elements to the array I think you can resolve the key issue by simply using the saved index.
questionType.map((questions, index) => (
<div key={questionsTitle[index].index} className="questions">
...
</div>
)
This may be a little confusing so I suggest changing the property to id.
questionType.map((questions, index) => (
<div key={questionsTitle[index].id} className="questions">
...
<input
...
onChange={event => {
...
tab.push({
id: index,
type: questionType[index],
title: event.target.value,
});
...
}}
/>
...
</div>
)
A further suggestion is to avoid using the array index at all. The following code can quickly get out of sync when the array index being mapped doesn't align to the saved index in the element.
let tabIndex = tab.findIndex(element => element.index === index);
Generate id's for your elements and use that to determine if elements should be updated or appended. When updating make sure to shallow copy the array and then also shallow copy the element object being updated.

How to separate items from array?

I'm making weather app for 7 days and I need to create abillity for users to open some of days to see more information about weather of current day. So, it means that every item choosen by user has to contain unique id (i don't know could I use in this situation index instead of id) to show information only about some of day. So before this I had some code:
const DailyWeatherData = ({dailyData, isLoading}) => {
const getWeatherStatistic = (value0,value1) => {
if(dailyData && Array.isArray(dailyData.daily)){
return (
<div className="col-lg-3 box-daily-weather">
<NavLink to={'/WeatherDayStat'}>
{setDay([value1])}
<div className="temp-day">{Math.ceil(dailyData.daily[value0].temp.day)}°C</div>
<div className="feels-like">Feels like: {Math.ceil(dailyData.daily[value0].feels_like.day)}°C</div>
<div className="daily-weather-condition">Conditions: {dailyData.daily[value0].weather.map(e => e.main)}</div>
</NavLink>
</div>
)
}else {
return isLoading === true ? <Preloader /> : null
}
}
const setDay = (param) => {
return checkCod ? null : setCurrentDate(new Date(),param)
}
return (
<div>
<div className="daily-weather-container">
{checkCod ? null : <div className="daily-title">Daily Weather</div>}
<div className='row scrolling-wrapper justify-content-center'>
{getWeatherStatistic(1,1)}
{getWeatherStatistic(2,2)}
{getWeatherStatistic(3,3)}
{getWeatherStatistic(4,4)}
{getWeatherStatistic(5,5)}
{getWeatherStatistic(6,6)}
</div>
</div>
</div>
)
}
export default DailyWeatherData
In function getWeatherStatistic you can see 2 arguments, value0 - doesn't matter here, value1 - using to show only 1st-6 object, because array which i have got from ajax request contains more days(10) but I need to show only 6 of them. And most importantly, each of them is separate. Logically I'd use map, but It shows all items, so I can use slice but it also shows 6 items in 1 column.
The next problem, this array has not contain parameter like ID, that's why I can't add to NavLink id. If there were ID, I would make something like that dailyData.daily.map(p => <NavLink to={'/WeatherDayStat' + p.id}>)
Also, just in case, add the state code (daily - array which I need):
So I have 2 questions:
How to show only 6 days from array?
How to add unique ID to every Item from array?
Making something like this:
//making new array with data I need
let sliceDailyData = dailyData.daily ? dailyData.daily.slice(1,7) : null
//using map with new array
{sliceDailyData ? sliceDailyData.map((i) => <div key={i.dt} className="col-lg-3 box-daily-weather">
{getCurrentDate(new Date())}
<NavLink to={'/WeatherDayStat'}>
<div className="temp-day">{Math.ceil(i.temp.day)}°C</div>
<div className="feels-like">Feels like: {Math.ceil(i.feels_like.day)} °C</div>
<div className="daily-weather-condition">Conditions: {i.weather.map(i => i.main)} </div>
</NavLink>
</div>
): null}
Speaking about ID, I have created variable which generte id and push it to array.
You can store your dailyData.daily array in an object and then retrieve it with key, you can use something simple but SEO friendly like obj['day'+(dailyData.daily.indexOf(d)+1)]
obj{}
dailyData.daily.forEach(d=>array.indexOf(d)<=5?obj[String(Math.random())]=d:null)

React - Split on string not having any effect

I am trying to split a given text at each \n in order to put them on individual lines.
The problem is, in React, I am using the following code:
const details = property.details !== undefined
? property.details.split("\n").map((item, i) => {
return <p key={i}>{item}</p>;
})
: "";
but there is no splitting made whatsoever. The returned array is simply the whole string. I tried the same string in the console of the browser and it works there.
Also, the typeof property.details is string.
What am I missing?
My render function for this component is:
render() {
const property = this.state.property;
const details =
property.details !== undefined
? property.details.split(/\r?\n/).map((item, i) => {
return <p key={i}>{item}</p>;
})
: "";
return (
<Fragment>
{this.state.isLoading ? (
<div className="sweet-loading" style={{ marginTop: "120px" }}>
<BarLoader
sizeUnit={"px"}
css={override}
size={200}
color={"#123abc"}
loading={this.state.isLoading}
/>
</div>
) : (
<div className="container p-4" style={{ marginTop: "4rem" }}>
<div className="row align-items-center">
<div className="row display-inline p-3">
<h3>{property.title}</h3>
<h5 className="fontw-300">{property.zone}</h5>
<h1 className="mt-5 price-font-presentation">
{property.sale_type} -{" "}
<strong>{property.price.toLocaleString()} EUR</strong>
</h1>
</div>
<Carousel>
{property.images.map(image => (
<img key={image.id} src={image.image} />
))}
</Carousel>
<div className="row p-3">
<h3 className="border-bottom">Detalii</h3>
{details}
</div>
</div>
</div>
)}
</Fragment>
);
}
Maybe I should mention that the information is taken with a django_rest api. Maybe there is a problem with returning \n in a string from there.
It might happen because client OS uses different symbols for new lines. Try this, it's multi-platform:
const details = property.details !== undefined
? property.details.split(/\r?\n/)
: [];
EDIT:
typeof property.details is string because it's string. calling split on property.details returns array, but string remains to be string.
From your updated code sample I can see that you are basically rendering details, which results in array transforming to string back again but without line seperators.
Maybe you have to map it to paragraphs for example:
<h3 className="border-bottom">Detalii</h3>
{details.map(detail => <p>{detail}</p>)}
Also, try white-space: pre; css property as alternative
Have you tried this version:
const details = property.details !== undefined
? property.details.split('\r\n').map((item, i) =>
<p key={i}>{item}</p>;
)
: '';
(It's the extra \r)

How to add a <br> tag in reactjs between two strings?

I am using react. I want to add a line break <br> between strings
'No results' and 'Please try another search term.'.
I have tried 'No results.<br>Please try another search term.'
but it does not work, I need to add the <br> in the html.
Any ideas how to solve it?
render() {
let data = this.props.data;
let isLoading = this.props.isLoading;
let isDataEmpty = Object.entries(data).length === 0;
let movieList = isLoading ? <Loader /> : isDataEmpty ? 'No results. Please try another search term.' :
Object.entries(data).map((movie, index) => <MovieTile key={index} {...movie[1]} />);
return (
<div className='movieList'>{movieList}</div>
);
}
You should use JSX instead of string:
<div>No results.<br />Please try another search term.</div>
Because each jsx should have 1 wrapper I added a <div> wrapper for the string.
Here it is in your code:
render() {
let data = this.props.data;
let isLoading = this.props.isLoading;
let isDataEmpty = Object.entries(data).length === 0;
let movieList = isLoading ? <Loader /> : isDataEmpty ? <div>No results.<br />Please try another search term.</div> :
Object.entries(data).map((movie, index) => <MovieTile key={index} {...movie[1]} />);
return (
<div className='movieList'>{movieList}</div>
);
}
You can use CSS white-space to solve the problem.
React Component
render() {
message = `No results. \n Please try another search term.`;
return (
<div className='new-line'>{message}</div>
);
}
CSS
.new-line {
white-space: pre-line;
}
OUTPUT
No results.
Please try another search term.
break text to line:
render() {
...
<div>
{this.props.data.split('\n').map( (it, i) => <div key={'x'+i}>{it}</div> )}
</div>
...
Some HTML elements such as <img> and <input> use only one tag. Such tags that belong to a single-tag element aren't an opening tag nor a closing tag. Those are self-closing tags.
In JSX, one has to include the slash. So, remove <br> and try <br />
Here is how I got around this. Let message be the prop/variable that has the string containing line breaks to be displayed in HTML as follows:
message = 'No results.<br>Please try another search term.';
<div>
{message}
</div>
To make this work, we need to use \n instead of break tag <br> and set the following css on the wrapper element of this message as follows:
message = 'No results.\nPlease try another search term.';
<div className="msg-wrapper">
{message}
</div>
CSS:
.msg-wrapper {
white-space: pre-wrap;
}
OUTPUT:
No results.
Please try another search term.
If you don't want put the string inside a <div> you could use <> to do it.
Like this:
var text = <>This is a text in the first line;<br />this is a text in a second line</>;
Just split text by /n, I do this in this way:
<div>
{text.split('\n').map((item, i) => <p key={i}>{item}</p>)}
</div>
Try with span
return (
<div className='movieList'><span>{movieList}</span></div>
);
If you are like in my situation and you don't want to add css, you can do that :
render () {
...
return (
...
<Typography component="p">
...
{(contact.lastname)?<div>Hello {contact.firstname} {contact.lastname}</div>:''}
...
</Typography>
...
);
}
using ` worked for me however i am not sure if it is the exact solution to the problem :
import React from 'react';
import ReactDOM from 'react-dom';
let element = (
<div>
<h1> Hello world</h1>
This is just a sentence <br></br>
But This line should not be in the same previous line. <br></br>
The above content proves its working. <br></br>
npm v6.14.6 | react : {React.version}
</div>
);
ReactDOM.render(element,document.getElementById("html-element-id"))
You can add a span tag and add block as a class.
Pomodoro Technique Timer <span className="block">with Bla</span>
The simplest thing which I did is by creating a component.
const EmptySpace = ({ spaceCount = 0 }) => {
return (
<>
{Array.from({ length: spaceCount }, (item, index) => {
return <br key={index} />;
})}
</>
);
};
export default EmptySpace;
<EmptySpace spaceCount={1} />
In your case you could do something like this:
const msg = (
<p>
No results <EmptySpace spaceCount={2} />
Please try another search term.
</p>
);

Categories

Resources