dynamically assigning a style attribute based on the dimensions of an image retrieved from a URL

My aim is to determine whether or not I should use an image based on its dimensions. To achieve this, I came across a function on stack overflow that can retrieve the dimensions of an image just by using its URL.

Here is the code snippet they provided:

function getMeta(url){
    var img = new Image();
    img.onload = function(){
        alert(this.width + " " + this.height)
    };
    img.src = url;
}

For my specific requirements, I needed to access and evaluate the width and height of the image, so I made some modifications. Here's what I changed:

function getMeta(url){
    var img = new Image();
    img.onload = function(){
        return [this.width, this.height]
    };
    img.src = url;
}

Using this function, I created another function to process it:

function backgroundCss(url){
    const dims = getMeta(url);
    return (dims[0] >= 1000 && dims[1] >= 300) ? `url(${url})` : "none"
}

I called this function within my style attribute:

<Grid item xs={15} md={6} style={{
      backgroundImage: backgroundCss(url)
}}>

Although I thought my approach was logical and free of errors, I kept encountering an error indicating that 'Image()' is not defined. Even attempting a slightly different approach led to the same issue:

const [imageText, setImageText] = React.useState(null);
function getMeta(url){
    var img = new Image();
    img.src = url;
    if(imageText == null){
        img.onload = () => setImageText((img.width >= 1000 && img.height >= 300) ? `url(${url})` : "none");
        getMeta(url);
        return false;
    }
    return imageText;
}
...
<Grid item xs={15} md={6} style={{
      backgroundImage: getMeta(url)
}}>

Is my objective even achievable? Where did I make mistakes in my implementations?

Edit: Is this revised version heading in the correct direction?

function getMeta(url){
    return new Promise((resolve) => {
        var img = new Image();
        img.onload = function(){
            resolve([this.width, this.height]);
        };
        img.src = url;
    })
}

function backgroundCss(url) {
    getMeta(url).then((dims) => {
        return (dims[0] >= 1000 && dims[1] >= 300) ? `url(${url})` : "none"
    })
}

Answer №1

Dealing with Asynchronous Code

The return statement within the onload handler may not be functioning as expected:

function getMeta(url){
    var img = new Image();
    img.onload = function(){
        return [this.width, this.height]
        // ^^^ this returns for the `onload` handler, not `getMeta`
    };
    img.src = url;
}

To solve this issue, consider using a "callback" or a Promise to handle the asynchronous process and provide the return value once it's ready.

Using a Callback Function

function getMeta(url, callback){
    var img = new Image();
    img.onload = function(){
        // execute the provided callback with the return value
        callback([this.width, this.height]);
    };
    img.src = url;
}

// implementation example
getMeta('...', (dims) => {
    console.log(dims);
});

Implementing a Promise

function getMeta(url, callback){
    return new Promise((resolve) => {
        var img = new Image();
        img.onload = function(){
            // resolve the promise with the return value
            resolve([this.width, this.height]);
        };
        img.src = url;
    })
}

// example of usage
getMeta('...').then((dims) => {
    console.log(dims);
});

Handling React Asynchronous Rendering

Since react component render functions are synchronous, you may need to introduce state management. Consider utilizing another useState hook like the existing one. Here is an approach:

const [imageUrl, setImageUrl] = React.useState(null);

//...

// update the state after obtaining the necessary data
getMeta('...').then((dims) => {
    setImageUrl('...');
});

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

Utilize the Material UI Grid component to extend the content of the second column all the way

Currently, I am utilizing the Grid component from material UI and specifically using the auto property for the initial column. Here is my setup: <Grid container className={classes.borderclass}> <Grid item xs={"auto"}> <Items /> ...

transferring data from one HTML file to another using a loop with technologies such as HTML,

As a beginner in front end development, I am finding it a bit challenging at the moment. Here's what I have so far: 1 main HTML file (index.html) 1 JavaScript file (something.js) 2nd HTML file (something.html) Main HTML: <!DOCTYPE html> < ...

Can you propose a different approach to creating the "word stack" that overcomes the limitations of my current method?

I am attempting to convert a set of two radio buttons into a stack of two labels, one blue and one gray, to represent the selected radio button and the unselected one. Clicking on this stack will toggle which label is blue (and consequently which radio but ...

Issue with DWR and Android web browser

I recently encountered an issue while trying to access an application through the Android browser. The application uses DWR to maintain connections with connected clients. Everything seems to be working fine, except for the fact that if there is a 2-minut ...

Display a custom toast from a list using Bootstrap 5

I've been utilizing the toast feature from Bootstrap, and it works perfectly when displaying a single toast. However, I encountered an issue when trying to display a specific toast, like an error toast, from a list of predefined toasts. It ended up sh ...

The $scope variable fails to reflect updates in the view following a broadcast event triggered by a

I have been troubleshooting a similar issue and I can't seem to figure out why the update is not reflecting in the view. While I am able to see the scope variable updating in the catch events logs, the changes are not being displayed in the view. For ...

Dynamically Generate Nested Objects in JavaScript

I have an object that is currently empty and I am looking to dynamically create a nested object within it. const obj = {} obj["test1"]["test1.1"] = x //initialize to some variable However, I encountered this error message: Uncaught Typ ...

Enhancing the functionality of radio buttons through event changes and optimizing related features

I am searching for a more efficient method to reuse functions that serve a similar purpose. For example, I would like to modify various radio buttons that toggle a hide class on different divs. JSFiddle Link How can jQuery be used to create a reusable fu ...

Struggling to get this bootstrap carousel up and running

I can't seem to get this bootstrap carousel to switch slides, whether I use the indicators or arrows. My other carousel works perfectly fine and I've added all necessary Bootstrap and JavaScript CDNs. I'm puzzled as to why it's not func ...

Is it possible to automate a query to an API through PHP and store the results on a local drive?

Recently, I created a webpage that fetches data from an API. However, the response time from the server is quite slow, taking around 10-20 seconds to retrieve the information. To mitigate cross-domain issues, I have set up a PHP proxy for the JavaScript re ...

React Material UI - DataGrid Continuously Distracting Focus Away from Input Field

I'm currently facing an issue with my React web app using Material-UI. The problem arises when I try to type in the search input field, but the focus keeps getting stolen by the Material-UI DataGrid whenever I click on it. Oddly enough, this only occu ...

Using *ngFor to iterate through a nested collection in an Angular 2 application

I'm currently working on a challenge involving drilling down to iterate over an array within another collection of arrays within an Angular 2 application. To start off, I have set up my component to subscribe to an observable in the ngOnInit lifecycle ...

Vanishing Act: React-js MUI Tooltip vanishes upon clicking

The standard behavior of the MUI Tooltip is as follows:
 If the button/icon to trigger a tooltip is not in focus, the tooltip will not disappear when clicking directly on the popper. However, if the button/icon is focused, the tooltip will disappear upo ...

How can I adjust the spacing system in Material UI according to the screen width?

Recently, I've come across a component that looks like this: <Box px={3}> <Content /> </Box> While rendering this code on mobile, everything seems to work fine. However, the paddingX remains fixed at 24px (calculated using an 8 b ...

Why isn't Freichat displaying the name of the user who logged in?

After creating my own small social networking site, I decided to add a chat script called freichat. However, I am facing an issue where when a user logs in, their name appears as "Guest102" instead of their actual name. I am quite confused by this problem ...

Vuejs is throwing an uncaught promise error due to a SyntaxError because it encountered an unexpected "<" token at the beginning of a JSON object

I am currently attempting to generate a treemap visualization utilizing data sourced from a .json file. My approach involves employing d3 and Vue to assist in the implementation process. However, upon attempting to import my data via the d3.json() method ...

I would like my division to split into two halves, each with a width of 50%, and be aligned next to each other using fxLayout

<div fxLayout="row" fxLayoutAlign="space-between" style="background-color: blue;"> <div fxLayout="column" style="width: 50%;">1stOne </div> <div fxLayout="column" styl ...

The Alert Component fails to display when the same Error is triggered for the second time

In the midst of developing a Website using Nuxt.js (Vue.js), I've encountered an issue with my custom Alert Component. I designed a contact form on the site to trigger a specialized notification when users input incorrect data or omit required fields ...

Utilize JavaScript conditions to dynamically apply styles within your web application

I am facing a challenge with managing two separate <style> tags that each contain a large number of styles and media queries. The issue is that one set of styles is intended for desktop users, while the other is meant for mobile users. When both se ...

Hide a div when multiple classes are filtered using jQuery

I have several divs with the class .item. When the user clicks on the Classfilter submit button, all .item elements that also have at least one class from the dateClasses array (for example ['28.09.2015', '29.09.2015']) should be hidden ...