The weather widget had two issues:
- "Loading weather..." text remained visible even after weather data loaded successfully
- City information (header with city name) disappeared after data loaded
Issue 1: Loading Element Not Hidden Properly
Problem: The #weather-loading element remained visible with "Loading weather..." text even after data loaded.
Root Causes:
- Invalid JavaScript Syntax: Attempted to use
loading.style.display = 'none !important'- JavaScript inline styles don't support!importantsyntax. This was silently ignored, showing as empty string in computed styles. - CSS Specificity: The loading element needed explicit CSS rules to ensure it stays hidden when the container is loaded.
Evidence from Logs:
loading.style.display = 'none !important'resulted inInline style.display value: nonebut computed display showed as empty string- Loading element had
offsetWidth: 0, offsetHeight: 0but was still visible (likely due to text content)
Solution:
- Use
element.style.setProperty('display', 'none', 'important')instead of invalid syntax - Added CSS rule:
#weather-container.loaded #weather-loading { display: none !important; } - Clear textContent to ensure no text is visible
Problem: The header (<h3>) showing "5-Day Weather (City Name)" disappeared after data loaded.
Root Cause: The header element was inside .weather-content-inner (which contains server-rendered HTML via {{ weather_html }}). When we hid contentInner with display: none, all its children (including the header) were also hidden, regardless of their individual visibility settings.
Evidence from Logs:
- Header had
visibility: hiddeninitially (inherited from container) contentInnercontained the header HTML:<h3>5-Day Weather</h3>- When
contentInnerwas hidden, the header disappeared despite being set tovisibility: visible
Solution:
- Extract the header from
contentInnerbefore hiding it - Move the header element directly into
#weather-container(beforecontentInner) - Update the header reference to point to the extracted element
- Then hide
contentInner(header is now outside and safe) - Set header visibility with
!importantto override any inherited styles
- Added extensive console logging to track element states
- Verified data loading worked correctly
- Found forecast element attachment issue (already fixed)
- Used
this.hideElement(loading)- partial success - Set
loading.style.display = 'none'- worked but needed CSS backup - Set
loading.style.display = 'none !important'- FAILED (invalid syntax, silently ignored) - Added
visibility: hiddenandopacity: 0- worked but needed CSS backup - Discovered invalid
!importantsyntax doesn't work in JavaScript inline styles
- Discovered header was inside
contentInnerfrom server-rendered HTML - Realized hiding
contentInneralso hid the header - Extracted header before hiding
contentInner - Set header visibility with
setProperty('visibility', 'visible', 'important')
<div id="weather-container" class="weather-container">
<div class="weather-content-inner">{{ weather_html }}</div> <!-- Contains <h3>5-Day Weather</h3> -->
<div id="weather-forecast" class="weather-forecast"></div>
<div id="weather-loading" class="weather-loading">Loading weather...</div>
<div id="weather-error" class="weather-error"></div>
</div>Key Insight: The {{ weather_html }} template variable contains server-rendered HTML that includes the header (<h3>). This HTML is injected into .weather-content-inner.
#weather-container {
visibility: hidden; /* Initially hidden */
}
#weather-container.loaded {
visibility: visible; /* Shown when loaded */
}
#weather-container.loaded .weather-forecast {
display: flex;
visibility: visible;
}
/* CRITICAL FIX: Hide loading when container is loaded */
#weather-container.loaded #weather-loading,
#weather-container.loaded .weather-loading {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}Key Fixes Applied:
- Extract Header Before Hiding contentInner:
// Extract header from contentInner before hiding it
const headerInContentInner = contentInner.querySelector('h3');
if (headerInContentInner) {
container.insertBefore(headerInContentInner, contentInner);
this.elements.set('header', headerInContentInner);
header = headerInContentInner;
}- Proper Loading Element Hiding:
// Use setProperty with 'important' parameter (correct way)
loading.style.setProperty('display', 'none', 'important');
loading.style.setProperty('visibility', 'hidden', 'important');
loading.style.setProperty('opacity', '0', 'important');
loading.textContent = '';- Ensure Header Visibility:
header.style.setProperty('display', 'block', 'important');
header.style.setProperty('visibility', 'visible', 'important');-
Invalid
!importantSyntax: JavaScript inline styles don't supportelement.style.property = 'value !important'. Useelement.style.setProperty('property', 'value', 'important')instead. -
CSS Inheritance: When a parent element has
display: none, all children are hidden regardless of their individual visibility settings. This is why hidingcontentInneralso hid the header. -
DOM Structure Matters: Server-rendered HTML structure can affect JavaScript element references. The header was inside
contentInnerbut needed to be outside for proper visibility control. -
CSS Backup Rules: Even with JavaScript inline styles, CSS rules with
!importantprovide a backup to ensure elements stay hidden/shown correctly. -
Element Extraction: Moving DOM elements preserves their references -
insertBeforemoves the element and updates references automatically.
- ✅ Loading Element: Properly hidden using
setProperty()with'important'parameter and CSS backup rule - ✅ Header Visibility: Extracted from
contentInnerbefore hiding, then explicitly set to visible with!important - ✅ CSS Rules: Added explicit rules to hide loading and ensure header visibility when container is loaded
- ✅ Code Cleanup: Removed excessive debugging logs, kept essential error logging
- ✅ Loading text properly hidden after data loads
- ✅ City information (header) displays correctly with city name
- ✅ Weather forecast displays correctly in the right location
- ✅ Widget is fully functional
- ✅ Code is production-ready with appropriate logging
-
JavaScript
!importantSyntax: Never useelement.style.property = 'value !important'. Always useelement.style.setProperty('property', 'value', 'important'). -
CSS Inheritance: Parent
display: nonehides all children. Extract needed elements before hiding parents. -
DOM Element References: When moving elements with
insertBefore()orappendChild(), the element reference remains valid - no need to re-query. -
Server-Rendered HTML: Be aware of HTML structure from server templates - elements may be nested differently than expected.
-
Defensive CSS: Use CSS rules with
!importantas backup even when JavaScript sets inline styles, ensuring elements stay in correct state.