I am getting the "address" value from the backend. However, the incoming value is all uppercase. I just want the first letters to be uppercase. I achieved this. But I get an error when "address" value does not come.
const upperCaseFirstLetter = (string) =>
`${string.slice(0, 1).toUpperCase()}${string.slice(1)}`;
const lowerCaseAllWordsExceptFirstLetters = (string) =>
string.replaceAll(/\S*/g, (word) => `${word.slice(0, 1)}${word.slice(1).toLowerCase()}`
);
let address = '';
address = upperCaseFirstLetter(lowerCaseAllWordsExceptFirstLetters(props.policy.assets.address));
html
<div className="policycard__subinfo">
{props.policy.assets.address ? (t('policy.policy-cards.address') + address) : null}
</div>
The error in the console is as follows; Cannot read properties of undefined (reading 'replaceAll').
There is probably a better way, but any time I run into an error like that I like to just give it a default value:
const lowerCaseAllWordsExceptFirstLetters = (string) => {
return (string || '').replaceAll(/\S*/g, (word) => `${word.slice(0, 1)}${word.slice(1).toLowerCase()}`
}
so that if string is undefined, it instead is treated as an empty string and you avoid the error.
Related
Here are the relevant sections of my code:
HTML (excerpt)
<label for="name">File delimiter (optional, max 1 character):</label>
<input type="text" id="delimiter" name="delimiter" required
minlength="0" maxlength="1" size="1"><br>
JS (excerpt)
async function getRelease(idFiltered) {
return fetch(`https://api.***.com/releases/${idFiltered}`, {
headers: {
'User-Agent': '***/0.1',
'Authorization': `*** key=${KEY}, secret=${SECRET}`,
},
}).then(response => response.json())
.then(data => {
if (data.message === 'Release not found.') {
return { error: `Release with ID ${idFiltered} does not exist` };
} else {
const { country = 'Unknown', genres = [], styles = [], year = 'Unknown' } = data;
const artists = data.artists?.map?.(artist => artist.name);
const barcode = data.identifiers.filter(id => id.type === 'Barcode').map(barcode => barcode.value);
const catno = data.labels.map(catno => catno.catno);
const descriptions = data.formats.map(descriptions => descriptions.descriptions);
const format = data.formats.map(format => format.name);
const labels = data.labels.map(label => label.name);
const qty = data.formats.map(format => format.qty);
const tracklist = data.tracklist.map(track => track.title);
const formattedLabels = labels.map(label => label.name);
const delimiter = document.getElementById("delimiter").value ?? "|";
const formattedBarcode = barcode.join(delimiter);
const formattedCatNo = catno.join(delimiter);
const formattedGenres = genres.join(delimiter);
const formattedStyles = styles.join(delimiter);
const formattedTracklist = tracklist.join(delimiter);
const preformattedDescriptions = descriptions.toString()
.replace('"', '""').replace(/,/g, ', ');
const formattedDescriptions = '"' + preformattedDescriptions + '"';
console.log(data);
return [idFiltered,
artists,
format,
qty,
formattedDescriptions,
formattedLabels,
formattedCatNo,
country,
year,
formattedGenres,
formattedStyles,
formattedBarcode,
formattedTracklist
];
}
});
}
When I manually input the delimiter | in the text box on my HTML page, I get the correct output back, for instance...
5,Datacide,CD,1,"Album, Limited Edition",,,RI 026|RI026,Germany,1995,Electronic,Abstract|Ambient|Downtempo,,Flashback Signal|Flowerhead|Deep Chair|So Much Light|Sixties Out Of Tune
but when I don't do that, it is missing!
5,Datacide,CD,1,"Album, Limited Edition",,,RI 026RI026,Germany,1995,Electronic,AbstractAmbientDowntempo,,Flashback SignalFlowerheadDeep ChairSo Much LightSixties Out Of Tune
I guess the missing delimiter is evaluating to neither null nor undefined for some reason, because I read that the nullish coalescing operator only returns the second operand "when the first one evaluates to either null or undefined (but no other falsy values)" source. So this seems to work instead:
const delimiter = document.getElementById("delimiter").value || "|";
Can anyone tell me why ?? isn't working for me, and is it OK to use || instead? Thanks.
Edit: I tried switching to ||, but I'm finding that the delimiter is only inserted correctly when I serve my app from my local machine, and not when I serve it from GitHub pages. So it seems this issue is specific to GitHub pages.
Your delimiter could be an empty string, which is falsy, but not nullish. That’s why the logical or works. An empty string is logical false, and so are undefined and null. The || operator will return the right-hand value in more cases than the ?? operator.
According to the docs:
The value (of a text input field) may be an empty string ("").
That's why you cannot rely on the nullish coalescing operator, it only works for null and undefined, while the logical || operator will check if the value is falsy, which is also the case for empty string.
i have input and array of object
i need when i type it will display the object. "airplaneCompany" is the object property that i need to compare
i was doing only if the input is equal to the "airplaneCompany" it will return it by the filter method
but i need for evrey char it will check it and if the object start with "a" it will show this object
const [txtInp, setTxtInp] = useState("");
const showFlight = users.filter((user) => {
return user.airplaneCompany == txtInp;
});
{showFlight.map((user, index) => {
const { id, airplaneCompany, passenger } = user;
return (
<div className="flightContainer" key={index}>
<div>{id}</div>
<div>{airplaneCompany}</div>
<div>{passenger}</div>
</div>
);
})}
You can use #Patrick answer, but JavaScript has its own startsWith function you can use.
Also, consider wrapping the filter with the useMemo hook to run it only when the input changes and not on every render.
const showFlight = useMemo(() => {
return users.filter((user) => {
return user.airplaneCompany == txtInp;
});
}, [txtInp]);
I think you can use your .filter function to check if the airplaneCompany starts with the user input?
Something like
return user.airplaneCompany.indexOf(txtInp) === 0;
just use regex. just place input value like /^airplaneCompany$/
const wrongInputText = 'q'
const rightInputText = 'airplaneCompany'
console.log('wrong', 'return value=', /^airplaneCompany$/.test(wrongInputText))
console.log('right', 'return value=',/^airplaneCompany$/.test(rightInputText))
I downloaded a weather API to get the value of the current conditions, which all works well except for the alert "event" and "description".
If an "alert" exists I get the value, but when there is none, the result is "TypeError: Cannot read property '0' of undefined".
What I need is an IF statement that says "if undefined, "0" else get the value" for these two lines:
const alerts = resJSON["alerts"][0]["event"]
const alertDs = resJSON["alerts"][0]["description"]
You could use optional chaining
const resJSON = {alerts: [{notevent: "test", description: "my description"}]};
const alerts = resJSON?.alerts?.[0]?.event || "0";
const alertDs = resJSON?.alerts?.[0]?.description || "0";
console.log(alerts);
console.log(alertDs);
I cant figure out why this is returning as an error.
item.Question.toUpperCase is not a function
I get this error in my expo application with react but no errors are thrown in the console
Error:
TypeError: item.Question.toUpperCase is not a function.
in item.Question.toUpperCase() item.Question.toUpperCase is undefined
I tried creating new variables as
var Question = item.Question.toUpperCase()
But that didn't seem to work so here is the full code
else if(item.Title == undefined){
const itemData = `${item.Question.toUpperCase()} ${item.answer.toUpperCase()} ${item.keyword.toUpperCase()}`;
const textData = search.toUpperCase();
return itemData.indexOf(textData) > -1;
item is an object in which Question is a string
Thank you
Edit:
So after some logging I found this area to be giving the error:
console.log(item.keyword,item.Title)
console.log(typeof item.Question, item.Question)
const itemData = `${item.Title.toUpperCase()} ${item.Question.toUpperCase()} ${item.answer.toUpperCase()} ${item.keyword.toUpperCase()}`;
const textData = search.toUpperCase();
console.log(typeof itemData,typeof textData)
when logging item.Question and the type I got number and NaN which is odd because from my database it should be pulling the string "this is a strng10"
All the other calls to the database seem to be working fine. They give the correct type for item.Question as String.
So I guess the problem I'm trying to solve is how the string is being converted to a number that is NaN?
This appears to work on my end. Are you certain you're passing the correct datatypes?
let item = {
Question: "test",
Title: undefined,
Answer: "thing",
Keyword: "wow"
}
if (item.Title === undefined) {
const itemData =
`${item.Question.toUpperCase()} ${item.Answer.toUpperCase()} ${item.Keyword.toUpperCase()}`
itemData
}
Console returns "TEST THING WOW"
So after logging all the way back to my call to the database I found an extra + before getting the question, removing that fixed the issue. So sorry for wasting all of your time.
The issuse was inside the object:
Question: + childData.Question
Background
I am learning Ramda and I am trying to use pipe. To this effect I made this simple example that doesn't work:
var getSQLQuery = ( { lang } ) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
var comp = ( country, queryParams ) => R.pipe(
getSQLQuery( queryParams ),
addAnd,
getMarket( country ),
R.tap( console.log )
)(country, queryParams);
comp("Spain", {lang: "uk"}); //Blows Up!?
The error I get is
First argument to _arity must be a non-negative integer no greater
than ten
I don't know how to fix this. How can I do it?
You can see it live here.
There are many ways one could write such a function. I know your goal is to learn how to use pipe, but let me first show a technique that starts with something similar to your functions:
const getSQLQuery = ( { lang } ) => `My query is ${lang}`;
const getMarket = country => `my country is ${country}`;
const flipAndJoin = pipe(reverse, join(' and '))
const comp = useWith(unapply(flipAndJoin), [getMarket, getSQLQuery])
comp("Spain", {lang: "uk"}); //=> ""My query is uk and my country is Spain"
Now the questions are:
Why does your function not work?
How can you make it work?
How do you make pipe work as desired?
Why does your function not work?
It's simple: pipe takes a number of functions as parameters, with at least one required. The first argument you supply is getSQLQuery( queryParams ), which is the result of calling getSQLQuery with an argument. That is a string, not a function. So when you try to wrap this in pipe, it fails. (The note about 'arity' has to do with the internals of Ramda: it uses the first function to pipe in order to determine how many parameters the resulting function should take.)
How can you make it work?
I gave an answer up above. The answer from MarioF does so with minimal change to your initial functions.
But none of these are as simple as
const comp2 = (country, queryParams) =>
`My query is ${queryParams.lang} and my country is ${country}`
comp2("Spain", {lang: "uk"}); //=> ""My query is uk and my country is Spain"
How do you make pipe work as desired?
You need to realize what pipe does.
Think of a function like this:
const getUpperAddr(userName, collection) {
const configStr = getUserConfig(userName, collection);
const config = JSON.parse(configStr);
const address = prop('address')(config);
const addrLine1 = prop('addrLine1')(address);
const upperAddr = toUpper(addrLine1);
return upperAddr;
}
Forgetting the details, especially of how getUserConfig works, and forgetting any potential errors, we can see one interesting feature of this function: each successive local variable is created by applying a function to the one before. The only exception to this is the first one, which uses the parameters to the function. The result is the final local variable.
pipe is simply a way to make this more declarative, and remove the need for all the local variables (and even the parameter names.) This is equivalent:
const getUpperAddr = pipe(
getUserConfig,
JSON.parse,
prop('address'),
prop('addrLine1'),
toUpper
);
This has the same signature as the above and returns the same result for the same input. If you can write your function in the first format, you can mechanically change to pipe. After a while, this becomes second nature, and you can skip the first step.
It is quite arguable whether this makes the code more readable than just using a single function, but this way you get what you are looking for:
var getSQLQuery = (_, {lang}) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
var comp = ( country, queryParams ) => R.pipe(
getSQLQuery,
addAnd,
getMarket( country ),
R.tap( console.log )
)(country, queryParams);
comp("Spain", {lang: "uk"});
In answer to the core question "how to use x with multiple arguments", technically you can use R.nthArg, but that doesn't immediately help you pass data down the pipe.
In my opinion, it's better to pass in an array - or use rest parameters. This works:
//Kept as original
var getSQLQuery = ( { lang } ) => `My query is ${lang}`;
var addAnd = str => str + " and";
var getMarket = country => data => `${data} my country is ${country}`;
//only modified this function
const comp = (...args) =>
getMarket(args[0]) (
R.compose(addAnd, getSQLQuery)(args[1])
);
comp("Spain", {lang: "uk"});
Repl here
Though I don't think R.compose really makes that any easier to reason about. Maybe if it's separated out into a named function like this?
const enhanceQuery = R.compose(addAnd, getSQLQuery)
const comp = (...args) =>
getMarket(args[0]) (enhanceQuery(args[1]));
Repl here