I am creating an application with a requirement for 2 search bars. One to search by name and another to search by tag. The search should also work when the user puts both name and tag in the searchbars.
The data from the api is in the format
{
"students" : [
{
"city": "city",
"company" : "company",
"email" : "email",
"firstName" : "firstName",
"grades" : ["12", "54"],
"id" : "1",
"lastName" : "lastName",
"pic" : "url",
"skill" : "skill"
},
],
}
My application is running on https://temp-application.netlify.app/
Currently the application does search with name as it is supposed to be.
But as soon as I attach search by tag functionality with it. Everything breaks down.
This is how I implemented searching by both name and tag.
useEffect(() => {
let filteredResults = results.filter((result) => {
const name = result.firstName + " " + result.lastName;
const isName = name
.toLowerCase()
.includes(searchName.toLowerCase());
const tags =
result.tag !== undefined ? result.tag.toString() : false;
const isTag =
typeof tags === "string"
? tags.toLowerCase().includes(searchTag.toLowerCase())
: false;
return isName && isTag;
});
setStudents(filteredResults);
}, [searchName, searchTag]);
Notice that 'tag' array is not present in the object returned by the API
The link you gave is not working.
For Tags, you are searching in the "tag" string in the Student(result) object but there is no key named tag in the given data.
Even if you have the tag key, you are probably not getting the result because you are doing a "&&" instead of "||"
I solved it. The problem was that I was trying to do the search in one-go. But instead I needed to make a if-else chain to achieve the result.
Here is the final function
let filteredResults = results.filter((result) => {
const name = result.firstName + " " + result.lastName;
const tags =
result.tag !== undefined ? result.tag.toString() : false;
if (searchName !== "" && searchTag === "") {
return name.toLowerCase().includes(searchName.toLowerCase());
} else if (searchName === "" && searchTag !== "") {
return typeof tags === "string"
? tags.toLowerCase().includes(searchTag.toLowerCase())
: false;
} else if (searchName !== "" && searchTag !== "") {
const isName = name
.toLowerCase()
.includes(searchName.toLowerCase());
const isTag =
typeof tags === "string"
? tags.toLowerCase().includes(searchTag.toLowerCase())
: false;
return isName && isTag;
} else if (searchName === "" && searchTag === "") {
return true;
}
return false;
});
setStudents(filteredResults);
}, [searchName, searchTag]);
Related
I'm missing something if someone can please explain it to me. I'm trying to re-write existing code into the ternary operator way.
I'm getting the following console error :
Uncaught SyntaxError: Unexpected token }
which I understand there's a condition not properly formatted which I can't seem to find. So I'm not sure what I'm missing or if I maybe misunderstand something in the filter function? Isn't the ? item.verified === true not suppose to automatically return the objects that's true?
var engagement = "social";
var audience = [{ 'verified': true, 'name': 'Steve'},
{ 'verified': false, 'name': 'Phil'},
{ 'verified': true, 'name': 'Jason'}];
let data = [];
data = audience.filter((item) => {
(engagement === "social")
? item.verified === true
: (engagement === 'social-crm')
? item.verified === false
: (engagement === 'all')
? item
})
The syntax that I understand:
data = audience.filter((item) => {
if (this.engagement === 'social-crm') {
return item.verified === true;
} else if (this.engagement === 'social') {
return item.verified === false;
} else if (this.engagement === 'all') {
return item;
}
});
Here's the fiddle I've been trying to play around with:
https://jsfiddle.net/phfilly/ya73e325/7/
Yup. Your syntax isn't right. To understand why your code isn't working, it would help if you were to re-write your if-else statements a bit.
if (this.engagement === 'social-crm') {
return item.verified === true;
} else if (this.engagement === 'social') {
return item.verified === false;
} else if (this.engagement === 'all') {
return item;
}
To this:
if(this.engagement === 'social-crm') { return item.verified === true; }
else {
if(this.engagement === 'social') {item.verified === false; }
else {
if(this.engagement === 'all') {return item;}
}
}
Now, ternary operators follow a similar nested fashion.
cond1 ? val1 : ( val2 )
Where val2 => cond2 ? val3 : (val4)
Where val4 => cond3 ? val5 : val6
So, now you can rewrite your expression like this:
this.engagement === 'social-crm' ? item.verified === true :
(this.engagement === 'social' ? item.verified === false :
(this.engagement === 'all' ? item : null))
The parenthesis matters here, because it closely mimics the nested if-elses from above.
Also note that for the inner most expression, a return value in the else must be specified. I've set it to null but you can return what you want. Do note this is the actual reason your code was failing. Apologies if the answer was long but I wanted to help you understand nested ternary operators.
A ternary operator looks like this:
something = (condition) ? a_value : a_different_value;
You forgot : a_different_value on the last case.
A nested ternary operator looks like this:
something = condition ? nested_condition ? value_if_both_conditions_are_true
: value_if_nested_condition_is_false : value_if_condition_is_false;
This works even without parentheses, but as others have mentioned, it can be hard to read. Especially when multiple conditions are checked, by use of && or || in the condition parts of this example.
Try this
You have to have a Condition for the Ternary operator as pointed by #Quentin
data = audience.filter((item) => { (engagement === "social") ?
item.verified === true : (engagement === 'social-crm') ?
item.verified === false : (engagement === 'all')?
item : null})
Deep nesting can write in a simpler way like this for ternary if-else
let userName = 'Amoos'
let isStudent = false
let age = 7
userName
? console.log(`User name: ${userName} 😊`)
: console.log('Unknow user');
isStudent ? console.log("Yes, is student 👨🎓")
: console.log('No, not a student 👨🎓');
(age<18) ? console.log("Younger 👶")
: console.log("Elder 😁")
I am currently using React and wish to retrieve data from my RealTime Database and save it in the variable: 'information' using the setInformation function from useState but when I run it, it still says that 'information' is null. I am sure I initialized Firebase correctly as when I write to the database it does show up, and the path in which I reference is also correct. I am not sure what I am doing wrong can someone help me please.
My Code:
function retrieveData() {
const curUser = firebase.auth().currentUser
const curUserUID = curUser.uid
const curDatabase = firebase.database()
const [information, setInformation] = useState(null)
console.log(curUserUID)
curDatabase.ref('user/' + curUserUID).once('value').then(snapshot => {
console.log(snapshot.val())
setInformation(snapshot.val().information))
})
return(
<div>
<h1>{information.age}</h1>
</div>
)
console.log Outputs:
HSfF9HwtK2QaYfUp4bHlhedGuKD2
{age : "23", weight : "90", height : "180"}
My Database Structure:
{
"users" : {
"HSfF9HwtK2QaYfUp4bHlhedGuKD2" : {
"information" : {
"age" : "23",
"weight" : "90",
"height" : "180"
}
},
"vXcWmZfLKwXbwUfdEudFrM1X0np1" : {
"information" : {
"age" : "29",
"weight" : "87",
"height" : "178"
}
}
}
}
i want to use ternary operator instead of if else conditions in react.
What i am trying to do?
I have an array of object type named 'list_info' which has type, recipient_idand recipient_email attributes.
Now i have a method named "get_text" which returns text whose value is string "to you" or the recipient email.
If the list_info type is "type_1" and props.current_user_id === list_info.recipient_id then it should
return nothing.
If the list_info type is "type_1" and props.current_user_id !== list_info.recipient_id then it should
return the list_info.recipient_email.
Now when the list_info type is anything other than "type_1" and and props.current_user_id ===
list_info.recipient_id then it should
return string "to you".
If the list_info type is anything other than "type_1" and props.current_user_id !==
list_info.recipient_id then it should return the list_info.recipient_email.
So to accomplish the above conditions i have the "get_text" method as below,
get_text = () => {
const list_info = this.props.list_info;
let text;
if (this.props.list_info.type === 'type_1') {
if (this.props.current_user_id === list_info.recipient_id) {
text = '';
} else {
text = list_info.recipient_email;
}
} else {
text = this.props.current_user_id === list_info.recipient_id
? 'you'
: list_info.recipient_email;
}
return <strong key={list_info.type}>{text}</strong>;
};
The above code works. But i think it could be made even more simple to read using ternary operator. could someone help me fix this. thanks.
Generally writing nested ternary operators will make the code unreadable. You can refactor your code as below, if you have more and more conditions/logic coming in, you can probably start using switch statement.
get_text = () => {
const { list_info, current_user_id } = this.props;
const meTextByType = list_info.type === 'type_1' ? "" : "you";
let text = current_user_id === list_info.recipient_id ?
meTextByType :
list_info.recipient_email;
return <strong key={list_info.type}>{text}</strong>;
};
get_text = () => {
const { list_info, current_user_id } = this.props;
const { type, recipient_id, recipient_email } = list_info;
const meTextByType = type === 'type_1' ? "" : "you";
let text = current_user_id === recipient_id ? meTextByType :brecipient_email;
return <strong key={type}>{text}</strong>;
};
How about local functions that describe exactly what each condition is, and by the looks of you only ever return 2 values, either 'to you' or the recipient_email prop.
getText = () => {
const isToYou = () => listInfoType !== 'type_1' && recipientId === userId
return isToYou() ? 'To You' : recipientEmail
}
I want to create a function that can be general as possible but It doesn't work now.
I have two case :
Check if the state of a state is not empty or true and if my item is equal to him, I want to reset him by calling resetState() and set to false and empty string
Check if the state of a state is not empty and if my item is equal to him, I want to reset him by calling resetState()and the empty string
My problem is : I try to replace stateItem.checkedA by something like stateItem.item to avoid repetitions but doesn't work for me, is it possible in react to do that ?
This is what I have :
const [stateBoolean, setStateBoolean] = React.useState({
checkedA: false,
checkedB: false
});
const [stateItem, setStateItem] = React.useState({
checkedA: "",
checkedB: "toto",
checkedC: "onlyHere not in Boolean"
});
const check = (listState) => {
listState.map(item => {
(stateBoolean.checkedA === true || stateItem.checkedA !== "") &&
item === "checkedA"
? (resetChange("checkedA", "stateItem"),
resetChange("checkedA", "stateBoolean"))
: null;
(stateBoolean.checkedB === true || stateItem.checkedB !== "") &&
item === "checkedB"
? (resetChange("checkedB", "stateItem"), resetChange("checkedB", "stateBoolean"))
: null;
stateItem.checkedC !== "" && item === "checkedC"
? resetChange("checkedC", "stateItem")
: null;
});
};
What I expected, but not working:
const checkWanted = (listState) => {
listState.map(item => {
(stateBoolean.item === true || stateItem.item !== "") &&
(item === "checkedB" || item === "checkedA")
? (resetChange(item, "stateItem"), resetChange(item, "stateBoolean"))
: null;
stateItem.checkedEOther !== "" && item === "checkedEOther"
? resetChange(item, "stateItem")
: null;
});
};
Any idea?
Use stateBoolean[item] instead, you can access properties of an object like an array
The function map return a new Array mdn description
If you want to iterate on a array and do something you should use forEach or a for loop.
I have an array of events and I have a search() function (below) that filters through it. Currently it only filters for name or date. Within my payload I have an array of tags, and I'm trying to figure out how to include it in the filtering of this. My current work-around is buttons that re-run the /event endpoint with search params which I don't like.
search(array: any[], query: string, excludeProps?: string|string[], dateFormat?: string) {
if (!query || !this._objArrayCheck(array)) {
return array;
}
const lQuery = query.toLowerCase();
const isoDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/; // ISO UTC
const dateF = dateFormat ? dateFormat : 'medium';
const filteredArray = array.filter(item => {
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (!excludeProps || excludeProps.indexOf(key) === -1) {
const thisVal = item[key];
if (
// Value is a string and NOT a UTC date
typeof thisVal === 'string' &&
!thisVal.match(isoDateRegex) &&
thisVal.toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
// Value is a Date object or UTC string
(thisVal instanceof Date || thisVal.toString().match(isoDateRegex)) &&
// https://angular.io/api/common/DatePipe
// Matching date format string passed in as param (or default to 'medium')
this.datePipe.transform(thisVal, dateF).toLowerCase().indexOf(lQuery) !== -1
) {
return true;
}
}
}
}
});
return filteredArray;
}
I tried adding an addition else after the date finder and leverage a for() loop on item.tags but it seems typescript doesn't really let you do a traditional for loop.
What is the actual method of handling this within Ang/Typescript?
Update
search(array: any[], query: string, excludeProps?: string|string[], dateFormat?: string) {
if (!query || !this._objArrayCheck(array)) {
return array;
}
const lQuery = query.toLowerCase();
const isoDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/; // ISO UTC
const dateF = dateFormat ? dateFormat : 'medium';
const filteredArray = array.filter(item => {
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (!excludeProps || excludeProps.indexOf(key) === -1) {
const thisVal = item[key];
if (
// Value is a string and NOT a UTC date
typeof thisVal === 'string' &&
!thisVal.match(isoDateRegex) &&
thisVal.toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
// Value is a Date object or UTC string
(thisVal instanceof Date || thisVal.toString().match(isoDateRegex)) &&
// https://angular.io/api/common/DatePipe
// Matching date format string passed in as param (or default to 'medium')
this.datePipe.transform(thisVal, dateF).toLowerCase().indexOf(lQuery) !== -1
) {
return true;
} else if (
typeof thisVal === 'string'
) {
for (var i=0; i < item.tags.length; i++) {
if (thisVal === item.tags[i]){
return true;
}
}
}
}
}
}
});
return filteredArray;
}
I was thinking something similar to this but it doesn't seem to be returning anything.
sample Payload
// collection: events
{
"_id" : ObjectId("59dda4b702ac8332bcb90921"),
"title" : "Gantt Chart Example222dsda",
"location" : "Home",
"startDatetime" : ISODate("2018-01-01T12:30:00.000-05:00"),
"endDatetime" : ISODate("2018-01-02T12:30:00.000-05:00"),
"description" : "dsad",
"viewPublic" : true,
"tags" : [
"Gaming",
"Social",
"home",
"misc"
],
"__v" : NumberInt("0")
}
My function should be able to match 'gantt' to the title and still show the row. It should also be able to match 'gaming', 'social' 'home' etc and pull this same record due to the tags. It should be able to pull from the start or end date time.