2
\$\begingroup\$

I have been building a weather app that changes the background colour depending on the weather temperature and description.

This is the code I have to get it to work.

const body = document.querySelector('body');

const colorList = [
  {weather: 'Clear', color1: '#7AE7C7', color2: '#72C1E1'},
  {weather: 'Clouds', color1: '#F981BB', color2: '#7F7E84'},
  {weather: 'Drizzle', color1: '#b2c9c8', color2: '#698b8b'},
  {weather: 'Fog', color1: '#C5B2A6', color2: '#7F7E84'},
  {weather: 'Rain', color1: '#504AC4', color2: '#59AED1'},
  {weather: 'Snow', color1: '#bfc9cf', color2: '#77BDE0'},
  {weather: 'Thunderstorm', color1: '#314F71', color2: '#4A4176'},
  {weather: 'Tornado', color1: '#939393', color2: '#e47977c5'}


 ]



const colorList2 = [
      {color1: '#C94926', color2: '#BB9F34'},
      {color1: '#89a1dd', color2: '#E4E5E7' }
   ]



if(weather.list[0].main.temp < 5 && weather.list[0].weather[0].main == 'Clear') {
      body.style.backgroundImage = `linear-gradient(to bottom right, 
      ${colorList2[1].color1}, ${colorList2[1].color2})`;
   } else if(weather.list[0].main.temp > 15 && weather.list[0].weather[0].main == 'Clear'){
        body.style.backgroundImage = `linear-gradient(to bottom right, 
        ${colorList2[0].color1}, ${colorList2[0].color2})`;
     } else {
          colorList.forEach(color => {
             if(color.weather == weather.list[0].weather[0].main) {
                body.style.backgroundImage = `linear-gradient(to bottom right, 
                ${color.color1}, ${color.color2})`;
   }

Is there a more efficient way of doing the same thing? Are forEach loops overkills? Should I use if else statements? Should I be doing it at all in JavaScript?

Many thanks in advance.

\$\endgroup\$
2
\$\begingroup\$

First, your weather color list is unique by weather key, and you're querying the color based on it. I'd suggest turning this into an object of colors keyed by weather condition. This way, it's easier to locate the colors by condition than using a loop. You also gain one extra advantage: you can add your special cases of Clear in the same object, just keyed with a unique key value.

Next, you'll want to assign those properties into variables. Long property accesses are hard to read.

Now you'll want to split your logic. In your code, you're mixing color selection logic with background setting logic in a conditional. It's always important to figure out what thing is actually conditional from what can be extracted off of it. In this case, only color1 and color2 are conditional, not the setting of the background.

Here's how I'd do it.

const colorsByCondition = {
  Clear: {
    color1: '#7AE7C7',
    color2: '#72C1E1'
  },
  // Special forms of Clear
  Clear5: {
    color1: '#89a1dd',
    color2: '#E4E5E7'
  },
  Clear15: {
    color1: '#C94926',
    color2: '#BB9F34'
  },
  // Other conditions
  Clouds: {
    color1: '#F981BB',
    color2: '#7F7E84'
  },
  // and so on...
}

// Assign to variables
// const weather = weather.list[0]
// const temp = weather.main.temp
// const conditions = weather.weather[0].main

// Assuming these values represent our weather
const temp = 6
const conditions = 'Clear'

// Find the right colors
const { color1, color2 } = temp < 5 && conditions == 'Clear'
  ? colorsByCondition.Clear5
  : temp > 15 && conditions == 'Clear'
    ? colorsByCondition.Clear15
    : colorsByCondition[conditions]

// Apply to the body
document.body.style.backgroundImage = `linear-gradient(to bottom right, ${color1}, ${color2})`

\$\endgroup\$
1
  • \$\begingroup\$ Thank you, your help is very much appreciated! Yes, I did feel like having an extra list titled 'colorList2' was a bit messy. Your way seems much better and cleaner. \$\endgroup\$
    – MBY
    Mar 3 at 17:58
2
\$\begingroup\$

Use CSS for Style

You are trying to add styles by JavaScript. Doing so makes your JavaScript mix logic and styles together. I would suggests split styles into CSS.

For example, your Javascript:

{weather: 'Clear', color1: '#7AE7C7', color2: '#72C1E1'},
/* ... */
{color1: '#C94926', color2: '#BB9F34'},
/* ... */
body.style.backgroundImage = `linear-gradient(to bottom right, ${color.color1}, ${color.color2})`;

You may convert it to CSS like

.weather-clear { --color-start: #7AE7C7; --color-end: #72C1E1; }
/* ... */
.weather-clear.weather-cold { --color-start: #C94926; --color-end: #BB9F34; }
/* ... */
body { background-image: linear-gradient(to bottom right, var(--color-start), var(--color-end)); }

And you only need to set the className on body to make specified color applied.

const body = document.body;
body.classList.add('weather-' + weather.list[0].weather[0].main.toLowerCase());
if (weather.list[0].main.temp < 5) body.classList.add('weather-cold');
if (weather.list[0].main.temp > 15) body.classList.add('weather-hot');

Put all together:

const body = document.body;
const temp = 18, main = 'Clear';
body.classList.add('weather-' + main.toLowerCase());
if (temp < 5) body.classList.add('weather-cold');
if (temp > 15) body.classList.add('weather-hot');
.weather-clear { --color-start: #7AE7C7; --color-end: #72C1E1; }
.weather-clouds { --color-start: #F981BB; --color-end: #7F7E84; }
.weather-drizzle { --color-start: #b2c9c8; --color-end: #698b8b; }
.weather-fog { --color-start: #C5B2A6; --color-end: #7F7E84; }
.weather-rain { --color-start: #504AC4; --color-end: #59AED1; }
.weather-snow { --color-start: #bfc9cf; --color-end: #77BDE0; }
.weather-thunderstorm { --color-start: #314F71; --color-end: #4A4176; }
.weather-tornado { --color-start: #939393; --color-end: #e47977c5; }
.weather-clear.weather-cold { --color-start: #C94926; --color-end: #BB9F34; }
.weather-clear.weather-hot { --color-start: #89a1dd; --color-end: #E4E5E7; }

body { background-image: linear-gradient(to bottom right, var(--color-start), var(--color-end)); }
body { height: 100vh; box-sizing: border-box; margin: 0; }

[Note] If you are targeting to support older browsers (without CSS var support): Remove CSS variables, use linear-gradient directly in .weather-clear and so.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you. Could this be done using SASS? And if so, what would be the better option; CSS variables or SASS variables? \$\endgroup\$
    – MBY
    Mar 5 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.