Highlighting a substring in a string - reactjs

I'm trying to highlight a matched substring in a searchable array of strings. I'm pretty close I think, just that last bit is not working.
I display an array of strings. When I type in an input the substrings in the array are supposed to get highlighted (using <mark></mark>) when matched with the input. The matching works ok but instead of highlighted text I get [object Object] instead.
So this is the part of code in question (it sits in Jsx inside a .map() method:
<div>
{item.matched.length > 0
? item.name.replace(new RegExp(inputText, 'gi'), (match) => (
<mark>{match}</mark>
))
: item.name}
</div>
The item is an element of the array that I'm mapping and has two properties: name & matched. matched is either empty or contains the typed search pattern if part or all of name matches it.
And this is what I'm getting when typing into text box:
So clearly the search and match work correctly and look what I get: [object Object] instead of highlighted search pattern.
I've tried to return a template string, like that backquote<mark>${match}</mark>backquote, but that results in displaying <mark>a</mark> in my example.
So I'm at loss here and any constructive feedback will be greatly appreciated.

we should render at in html
<div dangerouslySetInnerHTML={{ __html: (item.matched.length > 0
? item.name.replace(new RegExp(inputText, 'gi'), (match) => {
return `<span>${match}</span>`
})
: item.name) }}>

Related

Cannot display the data from a JSON file in React

I'm trying to display the data from my local JSON file in React. Here is how I see the data from the console: JSON data in the console. The structure is Data -> Classes -> Class[0-730] -> Term (or any other).
So if I try to print the Term of Class[0] in the console, I would do
console.log(Data.Classes.Class[0].Term)
and get the desired result. However, when I try to display the same data in the website, I get the following error:
Cannot read property '0' of undefined
Here is how my code looks like:
return Data.Classes ? (
<ul>
{Object.keys(Data.Classes).map((item, idx) => {
return item ? (
<li key={idx}>
<h3>{item.Class[idx] ? item.Class[idx] : "Doesn't exist"}</h3>
</li>
) : null;
})}
</ul>
): null;
};
I assume there is something going wrong after mapping that makes item.Class[idx] undefined, but I am not sure why. Is there something I am missing?
idx is the index of the item, so it doesn't make sense to use the index of the parent item lower in the depth.
Since you're called the map on Object.keys(Data.Classes), you're mapping the keys from a list of strings, so it will look like this: ["key1", "key2"..].
As I see it, you likely want this:
{Data.Classes.Class.map((item, idx) => {
return (
<li key={idx}>
<h3>{item.Term} - {item.Dept} - {item.Course} - {item.Section}</h3>
</li>
);
})}
I'm not sure why you have ternary operators. Specific keys might be null, but Map will only go to items on the list, so item will never be null. It might be empty (like {} or '') but not null.

Cannot read property 'includes' of undefined when trying to aply a filter based on a user's input

Im trying to aplly tis simple filter ased on a query of a list that with each input the list will narrow the possibilities
HTML:
<mat-form-field>
<mat-label>Search for users</mat-label>
<input #query type="text" matInput placeholder="search" (keyup)="filter(query.value)">
</mat-form-field>
<div *ngIf="filteredUsers">
And the function:
filter(query){
this.filteredUsers= query?
this.users.filter(user=>user.username.includes(query)):
this.users;
}
<ul *ngFor="let u of filteredUsers">
<li>
{{u.username}}
</li>
</ul>
</div>
The error I get as I input a character id that filter is undefined, but since both arrays fileterdUsers and Users are populated, I can't understand why this error is beig thrown...Any ideas?
EDIT: the ngOninit:
ngOnInit(): void {
this.dataService.getUsers()
.pipe(first())
.subscribe(users=>{
this.filteredUsers=this.users=users;
console.log(users, this.filteredUsers) -> i get the data
})
}
Edit 2 :
EDIT
filter(query){
console.log(this.users)
this.filteredUsers= query?
this.users.filter(user=>user.username.includes(query)):
this.users;
console.log(this.users)
}
Like this I don't see any logs...
EDIT 3: snapshot
Ok, maybe I have an idea of whats going on. The first elements of my ngFor are empty as you can see in the picture. Is this the reason for Angular's complaint? (your last fix didn't solve the issue as well)
If console.log doesnt log your array, it means its empty at the time filter(query) is being called. And I just noticed the way you are assigning the array isnt really what you want since arrays work by reference.
ngOnInit(): void {
this.dataService.getUsers()
.pipe(first())
.subscribe(users=>{
this.filteredUsers=users;
this.users=users; //just to be sure
console.log(users, this.filteredUsers) -> i get the data
})
}
filter returns an array so I guess you want to assign that to the filteredUser. I removed the code that made no sense.
filter(query){
console.log(this.users)
this.filteredUsers = query ? this.users.filter(user=> user.username && user.username.includes(query)): this.users
console.log(this.filteredUsers)
}
Whith the help and envolvment of #ukn I found the solution: the first elements of the array - seen on pic - , in this case users, were empty, so the solution was deleting those elements. The filter function is now working properly, giving me the names as I input a single char. The list gets updated trying to match the chars I input.

React JSX mapping through data where sometimes a data field is missing

im looping through data
This is react.js / jsx
If I am pulling 100 items, none will show because of one being undefined. I just want it to display "0" if it is undefined, and show the size if it is there.
Error: Cannot read property size of undefined.
Example of data,
Item={
color:blue,
size:medium,
}
Item={
color:red
}
I am mapping through the data.
Im essentially doing this :
return items.map((item, i) => {
return( {item.size})
I have also tried {item.size ? "itWorks" : "0"} as a test, and I get the same error.
It is better to use object.hasOwnProperty('property') to check whether your object has a particular property or not . for your case it is:
{item.hasOwnProperty('size') ? "itWorks" : "0"}
The error is:
Error: Cannot read property size of undefined
It means item is undefined,
So you gotta check for item and item.size.
You should do,
return (
items && items.map(function(item, id){
.....}))
So the loop goes through when items array is of some length otherwise it exits

Chaining an element using css containing text and accessing an associated field

I need to access the input field in the below html. The way the page is setup I need to chain using the 'Address Line 1' text and then sending text to the input field. The input field id changes and so doesn't the layout of the fields depending on user preference. I am struggling. If you need some more information feel free to ask I did not want to overload with too much information.
<td class="labelCol requiredInput">
<label for="00N36000000xina"><span class="assistiveText">*</span>Address Line 1</label>
</td>
<td class="dataCol col02">
<div class="requiredInput">
<div class="requiredBlock"></div>
<input id="00N36000000xina" maxlength="255" name="00N36000000xina" size="20" tabindex="4" type="text">
</div>
</td>
I have accessed like this:
element(by.css('div.pbSubsection:nth-child(3) > table:nth-child(1) > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(2) > input'))
However depending on where the user puts the fields it can move around. So what I was hoping was to be able to access the label\ and use that to pinpoint its input field.
I don't know protractor but I cobbled together some code that hopefully will work or be close and I'll give you the thought process and some info and hopefully you can use it to fix my code, if needed, and solve the problem.
Start by finding an element by XPath, "//label[text()='Address Line 1']". This searches for a LABEL tag that contains "Address Line 1". Once you find that element, get the label attribute. From your HTML, this label is the id for the INPUT element you want. Now use the id to find the element and do with it what you want.
id = element(by.xpath("//label[text()='Address Line 1']")).getAttribute("label")
input = element(by.id(id))
input.sendkeys("some text")
Haven't tested this myself, but you could try something like this:
// $ is shorthand for element(by.css())
$('div.assistiveText').getAttribute('for').then(function (val) {
// locate the <input> by the value of the attribute on <label>
element(by.id(val)).sendKeys('abc'); // replace sendKeys with your intended function
});
Or if that first locator on the label isn't specific enough, swap out $('div.assistiveText') for element(by.cssContainingText('Address Line 1'))
I tried it for other attributes (I don't have a for attribute anywhere in my app) and it seemed to work for me.
Try this:
List<WebElement> elementList = driver.findElements(By.cssSelector("tbody > tr"));
for (WebElement element : elementList) {
if(element.findElement(By.cssSelector("td.labelCol > label")).getText().equalsIgnoreCase("Address Line 1")) {
element.findElement(By.cssSelector("input[type='text']")).sendKeys("textToInput");
}
}

Getting text of element without including text of sub-element with jsoup

I'm using jsoup to parse HTML. There are list items that look like this:
<li><span class="chk">X</span>Category Name</li>
I want to get the text of the li NOT including the text of the span. So I want to get "Category Name" without the "X". (If I invoke the text() method on the li element, I get "XCategory Name".) How can I exclude the sub-span?
ownText() method will help you here.
Document document = Jsoup.parse("<ul><li><span class=\"chk\">X</span>Home</li><li><spanclass=\"chk\">X</span>Category Name</li></ul>");
Elements elems = document.select("li");
for(Element elem : elems){
System.out.println(elem.ownText());
}

Resources