I have an array of URLs and base64 hashed data, and I want to make a function that finds the key of that element in React.js. I have made a handler as such:
showModalSpeceficHandler = (image) =>{
this.state.images.forEach(function(image){
console.log(Object.keys[image]);
})
console.log('someting')
The image property I pass in is the value of the given image. The way the function works now is it returns an array of the keys for each, character in the URL or base64 data. Is there a way, that I can get the index that matches the key of the given object?
Here is the way that I have declared my image objects:
let image= this.state.images.map(image => {
return (
<img
key={image}
src={image}
onClick={() => this.showModalSpeceficHandler(image)}
/>
)
});
Maybe I should give another key instead, would that make my code easier and more maintainable?
The map() function also gives the index in the parameters for the callback: list.map((value,index) => { /* your function */ }). You could use like below:
let image= this.state.images.map((image,index) => {
return <img key={`image-${index}`} src={image}
onClick={() =>this.showModalSpeceficHandler(image)}/>
});
Related
I have the following dataset that I am trying to get values from, using JavaScript.
My code is as follows:
{companies.map(({ matches }) => (
<Company
key={matches}
name={matches}
symbol={matches}
/>
))}
I have tried to get the values by providing the key in the map function as follows:
name={matches['2. name']}
My question is, what syntax should I be using to get a value where the key has spacing and full-stops?
Your issue is this:
companies.map(({ matches }) => { … })
^^^^^^^^^^^
This is saying that for each item in the companies array, use a property named matches (through parameter destructuring), which, from what you're showing, doesn't exist.
Instead, I think you meant this:
companies.map(( matches ) => { … });
// or shorter:
// companies.map( matches => { … });
I am working with bigger arrays in React, and want the following display like this: image/name image/name image/name. I have the following the code but I don't know how I can map over the images array to so it shows it's image. Thank you
function showProtocolsNames() {
if (supportedVaults) {
let arr = supportedVaults
.map((item) => item.protocolName)
.filter((item, index, arr) => {
return arr.indexOf(item) == index;
});
let arrImages = supportedVaults
.map((item) => item.protocolKey)
.filter((item, index, arr) => {
return arr.indexOf(item) == index;
});
let protocolsName = [...new Set(arr)];
let protocolsImages = [...new Set(arrImages)];
console.log(protocolsName, protocolsImages);
return protocolsName.map((vault) => {
return (
<>
{' '}
<img
src={getVaultIcon(vault)}
width="42px"
height="42px"
style={{
marginRight: '12px',
}}
/>
<p className="vaults-protocol">{vault}</p>
</>
);
});
}
return null;
}
Solved: By creating an array of the images and names together and just mapping over it like DBS suggested in comments.
I believe there is a much simpler solution to your problem than your current approach. For example, you could use the supportedVaults data immediately while mapping the image/name components, like this:
function showProtocolsNames() {
// added check to ensure there is data inside supportedVaults
if (supportedVaults.length) {
// removed the two mapped arrays
// added index which is generated by map function
return protocolsName.map((vault, index) => {
// added div instead of <> in order to include a key, which is required in a map function
return (
<div key={`${index}-${vault?.protocolKey}`}>
{" "}
<img
src={getVaultIcon(vault?.protocolKey)} // here we pass protocolKey to the getVaultIcon function
width="42px"
height="42px"
style={{
marginRight: "12px",
}}
/>
{/* here we add protocolName inside the paragraph */}
<p className="vaults-protocol">{vault?.protocolName}</p>
</div>
);
});
}
return null;
}
This logic above is based on your description of the issue, assuming protocolKey is what you need to pass to get the vault icon in getVaultIcon function and protocolName is the value you need to show as the name. If my perception is wrong, please edit your question to reflect more info on what exact data you need to get from the supportedVaults array, or what format supportedVaults has.
I'm working with a gallery of cards in react.
Each card needs to have its own distinct state and toggle method, which is currently specified by a number at the end of the function, e.g. onDropdownToggle1.
The array is applied using this.state.cards.map((product, key) => ( ....
Is there a way to call each function distinctly using the key in the name of the function? Like directly modifying the function name onDropdownToggle + {key}? Or is it better to take the key in as a parameter somehow?
Here is the link to my sandbox which shows exactly what's going on: https://codesandbox.io/s/weathered-worker-0y5vm
Any suggestions would be very much appreciated. Thanks!
Just pass the key as a parameter. Either do it inline like this:
onToggle={(isDropdownOpen) => this.onDropdownToggle(key, isDropdownOpen)}
Or you could curry it like this:
this.onDropdownToggle = key => isDropdownOpen => {
...
}
...
onToggle={this.onDropdownToggle(key)}
Then you can use a single handler to modify each card.
You will have to use a computed property name when settings state
this.setState({
[key]: isDropdownOpen
});
Final result:
// One toggle function that uses the key to update state
this.onDropdownToggle = (key, isDropdownOpen) => {
this.setState({
[key]: isDropdownOpen
});
};
// One dropdown select function that uses the key to update state
this.onDropdownSelect = (key, event) => {
this.setState({
[key]: !this.state[key]
});
};
...
<Dropdown
isPlain
position="right"
onSelect={(e) => this.onDropdownSelect(key,e)}
toggle={
<KebabToggle
onToggle={(isDropdownOpen) => this.onDropdownToggle(key, isDropdownOpen)} />}
isOpen={this.state[key]}
dropdownItems={kebabDropdownItems}
/>
You could also consider using the item.name instead of the key to pass to the functions. But only if they are always unique.
So...long story short, I'm using an API that has 714 rows of data and unfortunately does not include image URls. There's just NO WAY I can enter a URL for every API row or each objet in the data array.
So I created a separate JS file that is an array of image URLs that I use to connect the exact API property name to the image url.
For example:
External images.js
const Images = {
"Canis lupus familiaris": {
image:'https://cdn.pixabay.com/photo/2018/03/08/23/14/dalmatians-3210166_1280.jpg'
}
}
Live API:
[
{
"science_name": "Canis lupus familiaris"
}
]
I know this is ugly but inside a map loop of the data, I have this code. :
let animalList = this.state.dataResults.map((animal, id) => {
return (
<img id={id} src={Images[animal.science_name] && Images[animal.science_name].image} aria-hidden />
)
}
Is there a way to write conditional code in there to display a general picture for the data records missing an image???? Since I can't get to all 714?
Can I fit an OR statement in there to use a general image.
<img id={id} src={Images[animal.common_name] && Images[animal.common_name].image} || if(no image) then use this general image pic />
OR put an if statement somewhere in the return?
let animalList = this.state.dataResults.map((animal, id) => {
return (
if (Images[plant.common_name].image === null) {
return (or display) "general.img"
I'm freaking out because this is due in hours. Thank you!
Using ternary operator
return (
<img key={id} src={Images[animal.science_name] ? Images[animal.science_name].image : 'http://general.png'} aria-hidden />
)
You were close. Try:
return (
<img id={id} src={Images[animal.science_name] && Images[animal.science_name].image || 'http://URL.for/missing.image'} aria-hidden />
)
Basically, what goes inside the {}s is a JavaScript expression. So all you need to do is to add a string after || so that if the preceding expression evaluates to a falsy value it gets used.
You can also do it in other ways, just as long as they are valid JavaScript expressions, for instance:
let defaultImage = {image: 'http://URL.for/missing.image'};
let animalList = this.state.dataResults.map((animal, id) => {
return (
<img id={id} src={(Images[animal.science_name] || defaultImage).image} aria-hidden />
)
}
I have a Map object:
let dateJobMap = new Map();
for (let jobInArray of this.state.jobs) {
let deliveryDate: Date = new Date(jobInArray.DeliveryDate);
let deliveryDateString: string = deliveryDate.toLocaleDateString("en-US");
if (dateJobMap.has(deliveryDateString)) {
let jobsForDate: IDeliveryJob[] = dateJobMap.get(deliveryDateString);
jobsForDate.push(jobInArray);
}
else {
let jobsForDate: IDeliveryJob[] = [jobInArray];
dateJobMap.set(deliveryDateString, jobsForDate);
}
}
In my render method, I want to call a TruckJobComp object for each delivery job in the value's array to display it:
<div className={ styles.column }>
<p className={ styles.description }>{escape(this.props.description)}</p>
{
dateJobMap.forEach(function(jobsForDate, dateString) {
jobsForDate.map(job => (
<TruckJobComp job = { job } />
))
})
}
</div>
This seems like it should work but doesn't. It never creates a TruckJobComp. I do a .forEach iteration on my Map, and for each value's array, I use .map to get the individual job object to send to TruckJobComp object.
When I create a temp array to grab the jobs from the last loop:
let tempJobs: IDeliveryJob[];
and in the loop add in:
if (dateJobMap.has(deliveryDateString)) {
let jobsForDate: IDeliveryJob[] = dateJobMap.get(deliveryDateString);
jobsForDate.push(jobInArray);
tempJobs = jobsForDate;
}
and then use that array in the render:
<div className={ styles.column }>
<p className={ styles.description }>{escape(this.props.description)}</p>
{
tempJobs.map(job => (
<TruckJobComp job = { job }/>
))
}
</div>
It displays as expected.
I do have a warnings in Visual Studio Code:
Warning - tslint - ...\TruckDeliverySchedule.tsx(104,38): error no-function-expression: Use arrow function instead of function expression
I don't know enough to understand. Line 104 corresponds with:
dateJobMap.forEach(function(jobsForDate, dateString) {
I am very new to this so I'm not 100% sure how most of this works. Just trying to put pieces I've learned together to get things to work.
Second Edit:
{escape(this.props.description)}
{
[...dateJobMap.keys()].map(jobsForDate => // line 154
jobsForDate.map(job => (
<TruckJobComp job = { job } />
))
)
}
Produces error:
[09:06:56] Error - typescript - src\...\TruckDeliverySchedule.tsx(154,27): error TS2461: Type 'IterableIterator<any>' is not an array type.
dateJobMap.forEach(...) returns undefined, so it cannot be mapped to a collection of elements.
ES6 maps have forEach method for compatibility purposes (generally for..of is preferred to iterate over iterables) and don't have map method. A map should be converted to array first, then it could be mapped to an element. Since values aren't used, only keys need to be retrieved:
{
[...dateJobMap.keys()].map(jobsForDate =>
jobsForDate.map(job => (
<TruckJobComp job = { job } />
))
)
}
All this warning is saying is that instead of using the syntax function(jobsForDate, dateString) {} you should use the syntax (jobsForDate, dateString) => {}.
The reason could be the way this is scoped in arrow functions versus function expressions. See this post.
My guess as to the reason your first approach didn't work but your second one did is that forEach doesn't actually return an array, and if it did, calling map within forEach would return an array of arrays (but, again, it doesn't). Not sure how React would handle that, but React does know how to handle a single array, which is what your last approach returns.