Tips on improving a function that verifies the existence of an image used as a CSS background to output a boolean value

I have encountered a challenge while working on a react file-upload component. The issue at hand is relatively simple - I aim to display an icon corresponding to the file extension for each uploaded file. These icons are loaded through css as background images (using inline styles). However, a problem arises when there is no specific icon available for a particular extension, and I need to show a fallback icon.

One approach I attempted was using multiple css background-image declarations like so:

style={{
  backgroundImage: `url(./icons/fallback.svg), url(./icons/${item.extension}.svg)`,
}}

or alternatively:

style={{
  backgroundImage: `url(./icons/fallback.svg)`,
  backgroundImage: `url(./icons/${item.extension}.svg)`,
}}

However, this method did not produce the desired results; either the fallback icon was not displayed or both icons were shown simultaneously, which was not what I intended.

I attempted to check if the file exists by fetching it, but my node server (utilized in create-react-app) always returns a 200 or 304 response even if the file is non-existent.

To address this issue, I explored a possible solution involving creating an image object with onload and onerror events, as proposed in this question. While this workaround worked well, refactoring the function to simply return a boolean proved challenging. Although using callbacks and console.log() worked fine, attempting to directly return a boolean resulted in undefined, likely due to the asynchronous nature of Image methods. I considered leveraging the Promise API to resolve this but faced obstacles in implementation.

The code snippet demonstrating my attempt:

exists = src => {
  const checks = {};
  return callback => {
    if (src in checks) {
      return callback(checks[src]);
    }
    let img = new Image();

    img.onload = function() {
      checks[src] = true;
      callback(true);
    };

    img.onerror = function() {
      checks[src] = false;
      callback(false);
    };

    img.src = src;
  };
};

The render method utilized:

render() {
  // Function logs as expected, but practical usage is limited
  console.log(this.exists('./icons/jpg.svg')(bool => {
    if(bool) {
      console.log('yes') 
    } else {
      console.log('no');
    }
  }));
// ...
}

While trying to directly return a boolean, the outcome is undefined:

render() {     
  console.log(this.exists('./icons/jpg.svg')(bool => bool));
  // ...
}

Answer №1

Correct, the function does not return a boolean due to being part of the callback for your exists function, which is executed asynchronously. To address this, you can also render your icon in an asynchronous manner, as demonstrated below:

this.exists(img)(bool => {
  if (bool) {
    render(img) 
  } else {
    render('fallback.svg');
  }
}

Answer №2

After much effort, I have successfully converted the entire process into a promise-driven system. I revamped the previous exists function to now be called checkImage, and integrated it into a chain of promises triggered by file uploads. This chain ultimately updates the state using setState and triggers a rerender:

The function for checking URLs:

checkImage = (path, fallback) => {
  return new Promise(resolve => {
    const img = new Image();
    img.src = path;
    img.onload = () => resolve(path);
    img.onerror = () => resolve(fallback);
  });
};

Using Promise.all():

// items are array of objects which contains file contents, name, extension etc...
checkIcons = items =>
Promise.all(
  items.map(item => {
    const url = `./icons/${item.extension}.svg`;
    return this.checkImage(url, this.state.fallbackIconUrl).then(result => {
      return { ...item, icon: result };
    });
  })
);

While not the most elegant solution out there and potentially needing some caching (or maybe not – the browser seems to handle it fine on its own), it gets the job done.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having difficulties accessing the git repository through the application

I am currently working on a Node.js application that needs to connect to a Git repository via the app. The connection works fine locally, and it also runs smoothly when I docker build and run it within a container on my local machine. However, upon deplo ...

What causes the variance in outcomes between employing a literal string versus a local variable?

Here is a loop that I am working with: for (var key in criteria) { var exists = Object.keys(item).some(function(k) { return item[k] === "Test"; }) } Initially, this loop functions as expected and returns 15 trues based on the number of i ...

Can I invoke an actions function within my reducer using an Express route?

In my Express route, I want to call an action function imported from my reducer: /* initial state */ export var usersStartState = { isAccountVerified: false, }; /* action types */ export const actionTypes = { IS_ACCOUNT_VERIFIED: 'IS_ACCOUNT_VER ...

Troubleshooting: Custom icons not displaying in Next.js application

Every time I attempt to use icons that I have loaded into my source code, I keep getting this default icon displayed: https://i.sstatic.net/AWhcW.png I'm uncertain about what exactly is causing this issue. Here is the layout of my file tree for ref ...

html5 Showing and hiding div elements

Here is a snippet of code to consider: @using App.Models @model App.Models.AllPeopleViewModel @{ ViewBag.Title = "Index"; } <html> <head> </head> <body> @foreach (Customer person in Model.Content) { <div class=&qu ...

Ways to display JSON objects containing nested key-value pairs

In my JSON structure, each Mealplan includes a key and a corresponding value which is an object called meal. id: 1, mealsPerWeek: { Monday: { id: 4, name: "Burger", }, Tuesday: { id: 3, name: "Salad&qu ...

Utilize AngularJS to bind a variable and display an external HTML file without the need to open it in a browser

In my setup, I have two HTML Views - one is for application purposes and the other is for printing. Let's call them Application.html and PrintForm.html, respectively. Here is a snippet from Application.html: <!DOCTYPE html> <html> < ...

Placing 2 elements next to each other - Where the left element remains static and the right element's width increases as the page expands

Hey there! I'm really struggling to position two elements, an aside and a section (I believe the use of these HTML5 elements is important for their content). On this page Click Here, my goal is to keep the 'Locations' (Aside) element static ...

How can I ensure that Chakra UI MenuList items are always visible on the screen?

Currently, I am utilizing Chakra UI to design a menu and here is what I have so far: <Menu> <MenuButton>hover over this</MenuButton> <MenuList> <Flex>To show/hide this</Flex> </MenuList> </ ...

Implementing seamless redirection to the login page with Passport in Node.js

I have encountered a persistent issue while using node.js, express, and passport. After successfully validating the user with passport, my application keeps redirecting back to the login page instead of rendering the index page. Is there a problem with the ...

Unable to add items to the global JavaScript array variable

My goal is to populate a global array variable within my ready function, but when I attempt to access the data later on, the array appears to be empty. This is how my ready function looks: var counter = 0; var services = []; var names = [] va ...

Issues with Axios POST requests

I've been facing an issue with using Axios to send a POST request to my Node.js server. Any suggestions on how I can troubleshoot this problem? Here is a snippet of the code in question: server.js: app.post('/registration', (req, res) =&g ...

Obtain the solar year using React

Is there a way to retrieve the current solar year in local Farsi format using React? All I need is the solar year in Jalali calendar, and currently I am using the following code: new Date().toLocaleDateString('fa-IR'); However, this code return ...

Storing JavaScript variables in a database: A step-by-step guide

For the past few days, I've been working with CakePHP and trying to save a javascript variable into a MySQL database using AJAX (jQuery). Here's the code I've been using: <!-- document javascripts --> <script type="text/javas ...

Having Trouble with Form Submission Button Across Different Web Browsers

Having some trouble with my form - all fields are properly closed with tags, but when I click the submit button, nothing happens. The page is loaded with code, so here's the link for you to check it out. Unfortunately, right-click is disabled, so ple ...

What's the best way to include various type dependencies in a TypeScript project?

Is there a more efficient way to add types for all dependencies in my project without having to do it manually for each one? Perhaps there is a tool or binary I can use to install all types at once based on the dependencies listed in package.json file. I ...

What is the best way to ensure the second navbar stays at the top when scrolling, after the first one?

Looking for a solution to create a navbar with two distinct sections for contact info and the menu. The goal is to have the contact info disappear when scrolling down, while the menu remains fixed at the top of the page. When scrolling back up, the menu sh ...

React button synchronization issue with start stop functionality

My React timer module has one input field and three buttons: Start (to begin the timer), Pause (to temporarily stop the timer), and Stop (to completely halt the timer). The issue I am encountering is that when I input a value, start the timer, then press t ...

Using the power of Selenium's XPath, we can easily navigate through a table to access

Looking for assistance in creating selenium xpath for the various column links within a table. Each row has a unique identifier and contains information about a product, including the name. Based on the product name, I need to locate other links within the ...

Empty results in NgRx Parameterized Selector

Having trouble implementing a parameterized query in NgRx and receiving empty results. Check out the StackBlitz version of the code here: https://stackblitz.com/edit/ngrx-parameterized-query Update to Reducer Code export const userAdapter = createEntity ...