Deze keuzehulp heeft al meer dan 30.000 anderen geholpen in het kiezen van de beste radiator
Start de gratis
radiator keuzehulp
- Advies gebaseerd op jouw ruimte, budget en wensen
- Voorkom dure vergissingen met het juiste vermogen voor jouw ruimte
- Geen eindeloos zoeken meer tussen honderden radiatoren
Krijg binnen enkele minuten het beste advies, goedgekeurd en opgesteld door specialisten
Welke ruimte wilt u verwarmen?
Elke ruimte vraagt om een andere combinatie van vermogen, formaat en design.
Kies de ruimte dat u wilt verwarmen
Hoe goed is de isolatie van de ruimte?
Goede isolatie houdt warmte beter vast, waardoor u minder vermogen nodig heeft.
Kies de kwaliteit van isolatie
Wat zijn de afmetingen van de ruimte? (in centimeters)
We gebruiken dit om het benodigde vermogen te berekenen.
cm
cm
cm
Hoe wilt u de ruimte verwarmen?
De manier van verwarmen bepaalt het type en vermogen van de radiator.
Zijn er momenteel al verwarmingen in de ruimte die u wilt behouden?
Bestaande radiatoren tellen mee in het totale benodigde vermogen.
Hoeveel vermogen hebben deze radiatoren samen in Watt
Zo berekenen we precies wat er aanvullend nodig is.
Vul hier het vermogen van alle radiatoren samen in Watt
Watt
Wat is de gewenste temperatuur van uw ruimte?
Een hogere temperatuur vraagt om meer vermogen.
Kies de gewenste temperatuur van isolatie
Hoeveel radiatoren kunt en wilt u plaatsen in deze ruimte?
Meer radiatoren betekent dat elk minder vermogen hoeft te leveren.
Vul hier het aantal radiatoren voor in uw gekozen ruimte in
Welke kleur wilt u voor op uw radiator(en)?
Zo krijgt u enkel voorstellen binnen uw eigen smaak.
Kies de gewenste kleur
Wilt u een of meerdere verticale of horizontale radiatoren?
Kies de gewenste vorm
Zijn er harde eisen voor afmetingen?
Vink uit wat niet gewenst is bij de afmetingen (breedte x hoogte)
Breedte (cm)
Hoogte (cm)
Niet gewenst
Hoe wilt u dat de radiatoren eruit komen te zien?
Maak een keuze over de uitstraling van de radiator(en)
Hoe wil je de radiator(en) aansluiten?
Maak een keuze over de aansluiting van de radiator(en)
Perfect! We hebben ideale radiatoren gevonden
Speciaal geselecteerd voor jouw ruimte
Snelle leveringin Nederland en België
14 dagenbedenktijd
Laagsteprijsgarantie

Prijs filter
€0 - €1000
€0€1000
Producten laden...
Voor een optimale circulatie heeft u ook een stromingsbuis nodig.
Wilt u een stromingsbuis toevoegen voor optimale circulatie?
Stromingsbuizen laden...
Geen geschikte radiator gevonden voor het benodigde wattage
Het benodigde wattage ({wattage} Watt per radiator) kan niet worden gehaald met de gekozen aantal radiatoren.
Wilt u een extra radiator plaatsen om het totale wattage te behalen?
Hoe wilt u de radiator aansluiten?
Wij adviseren u bij deze radiator een aansluitset mee te bestellen, zodat u alle onderdelen heeft om de radiator op te hangen en aan te sluiten.
Welke situatie is van toepassing?
Waarom vragen we naar de leidingsituatie?
Maak je bestelling compleet
Kies net zoals vele een totaalpakket.
Kies uw aansluitset
Aansluitsets laden...
Heeft u een (thermostatische) aansluitset nodig?
ECA Insert voor uw radiatoren
Speciaal geselecteerd voor onderblokset installaties
Nog een ruimte verwarmen of afrekenen?
Snelle
levering
14 dagen
bedenktijd
Laagste
prijsgarantie
de radiateur gratuit", subtitle: "Ici, nous pouvons placer un sous-titre.", benefit_1: "Conseils adaptés à votre espace, budget et souhaits", benefit_2: "Évitez les erreurs coûteuses grâce à la puissance adaptée à votre espace", benefit_3: "Fini les recherches interminables parmi des centaines de radiateurs", cta_button: "Commencer l'outil de sélection gratuit", footer_note: "Obtenez les meilleurs conseils en quelques minutes, approuvés et préparés par des spécialistes", // Step 2 translations step2_title: "Quelle pièce voulez-vous chauffer?", step2_expert_message: "Chaque pièce demande une combinaison différente de puissance, de taille et de design.", step2_more_info: "Plus d'informations", step2_question_text: "Choisissez la pièce que vous voulez chauffer", step2_question_label: "Choisissez la pièce que vous voulez chauffer", room_woonkamer: "Salon", room_woonkamer_desc: "Grande pièce avec beaucoup de confort", room_slaapkamer: "Chambre à coucher", room_slaapkamer_desc: "Chaleur calme et uniforme", room_keuken: "Cuisine", room_keuken_desc: "Réchauffement rapide souhaité", room_badkamer: "Salle de bain", room_badkamer_desc: "Humidité élevée et chaleur", room_kantoor: "Bureau/salle d'étude", room_kantoor_desc: "Température constante", room_gang: "Couloir/hall", room_gang_desc: "Espace de passage", next_button: "Question suivante", progress_step1: "Votre pièce", progress_step2: "Radiateur", progress_step3: "Conseil", // Step 3 translations step3_title: "À quel point l'isolation de la pièce est-elle bonne?", step3_expert_message: "Une bonne isolation retient mieux la chaleur, vous avez donc besoin de moins de puissance.", step3_more_info: "Plus d'informations", step3_question_text: "Choisissez la qualité d'isolation", isolation_slecht: "Mauvais", isolation_slecht_desc: "Vieille maison, beaucoup de courants d'air", isolation_normaal: "Normal", isolation_normaal_desc: "Isolation standard", isolation_goed: "Bon", isolation_goed_desc: "Isolation moderne", // Step 4 translations step4_title: "Quelles sont les dimensions de la pièce? (en centimètres)", step4_expert_message: "Nous utilisons ceci pour calculer la puissance nécessaire.", step4_more_info: "Plus d'informations", dimension_height: "Entrez la hauteur en centimètres", dimension_width: "Entrez la largeur en centimètres", dimension_length: "Entrez la longueur en centimètres", // Step 5 translations step5_title: "Comment voulez-vous chauffer la pièce?", step5_expert_message: "La méthode de chauffage détermine le type et la puissance du radiateur.", step5_more_info: "Plus d'informations", heating_elektrisch: "Chauffage électrique", heating_elektrisch_desc: "Le chauffage électrique utilise l'électricité pour générer de la chaleur, est durable, économe en énergie, flexible et sans gaz.", heating_cv_ketel: "Chaudière centrale", heating_cv_ketel_desc: "Une chaudière centrale chauffe l'eau de manière centralisée pour les radiateurs et les robinets, offre un confort rapide et de l'efficacité.", heating_stadsverwarming: "Chauffage urbain", heating_stadsverwarming_desc: "Le chauffage urbain fournit de la chaleur à partir d'un réseau central, sans chaudière propre, chauffage efficace et respectueux de l'environnement.", heating_warmtepomp: "Pompe à chaleur", heating_warmtepomp_desc: "Une pompe à chaleur extrait l'énergie de l'air, de l'eau ou du sol, offre un chauffage durable et économise l'énergie.", // Step 6 translations step6_title: "Y a-t-il actuellement des chauffages dans la pièce que vous souhaitez conserver?", step6_expert_message: "Les radiateurs existants comptent dans la puissance totale nécessaire.", step6_more_info: "Plus d'informations", keep_heating_yes: "Oui, je souhaite conserver un ou plusieurs radiateurs.", keep_heating_no: "Non, je ne veux pas conserver de radiateurs.", // Step 7 translations step7_title: "Quelle est la puissance de ces radiateurs ensemble en Watts", step7_expert_message: "Ainsi nous calculons précisément ce qui est nécessaire en plus.", step7_more_info: "Plus d'informations", step7_question_text: "Entrez ici la puissance de tous les radiateurs ensemble en Watts", radiator_power_label: "Entrez la puissance en Watts", // Step 8 translations step8_title: "Quelle est la température souhaitée de votre pièce?", step8_expert_message: "Une température plus élevée demande plus de puissance.", step8_more_info: "Plus d'informations", step8_question_text: "Choisissez la température souhaitée d'isolation", temperature_placeholder: "Choisissez le nombre de degrés", // Step 9 translations step9_title: "Combien de radiateurs pouvez-vous et voulez-vous placer dans cette pièce?", step9_expert_message: "Plus de radiateurs signifie que chacun doit fournir moins de puissance.", step9_more_info: "Plus d'informations", step9_question_text: "Entrez ici le nombre de radiateurs pour votre pièce choisie", radiator_count_label: "Entrez le nombre de radiateurs", // Step 10 translations step10_title: "Quelle couleur voulez-vous pour votre/vos radiateur(s)?", step10_expert_message: "Ainsi vous n'obtenez que des suggestions selon votre propre goût.", step10_more_info: "Plus d'informations", step10_question_text: "Choisissez la couleur souhaitée", color_zwart: "Noir", color_wit: "Blanc", color_antraciet: "Anthracite", color_chroom: "Chrome", color_goud: "Or", // Step 11 translations step11_title_single: "Voulez-vous un radiateur vertical ou horizontal?", step11_title_multiple: "Voulez-vous un ou plusieurs radiateurs verticaux ou horizontaux?", step11_expert_message: "Pourquoi demandons-nous un radiateur vertical ou horizontal?", step11_more_info: "Plus d'informations", step11_question_text: "Choisissez la forme souhaitée", orientation_vertical: "Radiateurs verticaux", orientation_horizontal: "Radiateurs horizontaux", // Step 12 translations step12_title: "Comment voulez-vous que les radiateurs apparaissent?", step12_expert_message: "Pourquoi demandons-nous l'apparence du radiateur?", step12_more_info: "Plus d'informations", step12_question_text: "Faites un choix sur l'apparence du/des radiateur(s)", step12_size_question_text: "Cochez ce qui n'est pas souhaité pour les dimensions (largeur x hauteur)", step12_size_title: "Y a-t-il des exigences strictes pour les dimensions ?", variant_ribbel: "Façade nervurée (standard)", variant_vlak: "Façade plate", variant_groef: "Façade rainurée (lignes)", // Step 13 translations step13_title_single: "Comment voulez-vous connecter le radiateur?", step13_title_multiple: "Comment voulez-vous connecter les radiateurs?", step13_title_single_paneel: "Comment voulez-vous connecter le radiateur panneau?", step13_title_multiple_paneel: "Comment voulez-vous connecter les radiateurs panneaux?", step13_expert_message: "Pourquoi demandons-nous comment connecter les radiateurs?", step13_more_info: "Plus d'informations", step13_question_text: "Faites un choix sur la connexion du/des radiateur(s)", connection_boven: "Sur les connexions latérales supérieures du radiateur", connection_onder: "Sur les connexions latérales inférieures du radiateur", connection_middenonder: "Connexion milieu-bas", connection_rechtlinks_onder: "Connexion droite ou gauche en bas", connection_zijkant: "Sur les côtés du radiateur", // Step 13a translations step13a_title: "Comment voulez-vous connecter le/les radiateur(s)?", step13a_question_text: "Faites un choix sur la connexion du/des radiateur(s)", // Step 14 translations step14_title: "Souhaitez-vous monter la tête thermostatique sur un autre raccordement que sur le bloc de raccordement inférieur lui-même ?", step14_expert_message: "Pourquoi demandons-nous si vous avez besoin d'un kit de connexion?", step14_more_info: "Plus d'informations", insert_product_title: "ECA Insert pour vos radiateurs", insert_product_subtitle: "Spécialement sélectionné pour les installations de blocs de raccordement inférieurs", aansluitset_ja: "Oui", aansluitset_nee: "Non", // Step 15 translations step15_title_default: "Quelle situation s'applique?", step15_title_zijkant: "Vous avez choisi de connecter sur les côtés du radiateur. Quelle situation s'applique?", step15_title_onder: "Vous avez choisi de connecter en bas du radiateur. Quelle situation s'applique?", step15_title_boven: "Vous avez choisi de connecter en haut du radiateur. (Cette option n'est pas recommandée pour les radiateurs verticaux) Quelle situation s'applique?", step15_expert_message: "Le raccordement par le haut est déconseillé, sauf s’il est réalisé avec une canne de déflexion (tube plongeur). Sans canne de déflexion, la circulation peut être entravée, ce qui réduit le rendement. La canne de déflexion peut être sélectionnée à l’étape suivante.", step15_more_info: "Plus d'informations", leidingen_plafond: "Conduites depuis le plafond", leidingen_vloer: "Conduites depuis le sol", leidingen_wand: "Conduites sortant du mur", leidingen_parallel: "Conduites parallèles au mur", // Step 16 translations step16_title: "
) if (key === 'main_title' || key === 'footer_note' || key === 'step2_question_text' || key === 'step3_question_text' || key === 'step7_question_text' || key === 'step8_question_text' || key === 'step9_question_text' || key === 'step10_question_text' || key === 'step11_question_text' || key === 'step12_size_question_text' || key === 'step12_question_text' || key === 'step13_question_text' || key === 'step13a_question_text' || key.startsWith('dimension_') || key.startsWith('radiator_') || key.startsWith('color_') || key.startsWith('orientation_') || key.startsWith('variant_') || key.startsWith('connection_') || key === 'step16_title' || key === 'get_advice' || key.startsWith('delivery_bar_') || key.startsWith('usp_')) { element.innerHTML = translations[currentLanguage][key]; } else { element.textContent = translations[currentLanguage][key]; } }else{ console.warn(`Missing translation for key: ${key} in language: ${currentLanguage}`); } }); // Update page title document.title = translations[currentLanguage].page_title; } function changeLanguage() { const select = document.getElementById('languageSelect'); currentLanguage = select.value; updateTexts(); } function closeModal() { console.log('Close modal clicked'); document.querySelector('.radiator-keuzetool').classList.remove('active'); } function startSelection() { console.log('Start selection clicked'); showStep('step2'); } // Aansluitset products mapping with filtering rules const aansluitsetProducts = { 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-haakse-aansluitingen-tbv-rad.html': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['wand', 'plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-haakse-aansluitingen-tbv-rad.html#': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['wand'] }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-haakse-aansluitingen-tbv-rad.html##': { 'kw__aansluiting': ['boven'], 'kw__leidingen': ['parallel', 'wand', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-haakse-aansluitingen-tbv-rad.html###': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-haakse-aansluitingen-tbv-rad.html####': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['parallel', 'plafond'] }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-h.html': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['wand', 'plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-h.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': ['parallel', 'wand', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-h.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['wand'] }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-h.html###': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-h.html####': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['parallel', 'plafond'] }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-h.html': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['wand', 'plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-h.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': ['parallel', 'wand', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-h.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['wand'] }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-h.html###': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-h.html####': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['parallel', 'plafond'] }, // 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-ha.html': { // 'kw__aansluiting': ['rechtlinks-onder','zijkant'], // 'kw__leidingen': ['wand'] // }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-ha.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': ['parallel', 'wand', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-ha.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['wand'] }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-ha.html###': { 'kw__aansluiting': ['zijkant'], 'kw__leidingen': ['plafond', 'vloer'] }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-ha.html####': { 'kw__aansluiting': ['onder'], 'kw__leidingen': ['parallel', 'plafond'] }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-rechte-aansluitingen-tbv-rad.html': { 'kw__aansluiting': ['rechtlinks-onder', 'zijkant'], 'kw__leidingen': 'parallel' }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-rechte-aansluitingen-tbv-rad.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': 'plafond' }, 'https://www.radiator-outlet.nl/nl/oppio-thermostatische-rechte-aansluitingen-tbv-rad.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-r.html': { 'kw__aansluiting': ['rechtlinks-onder', 'zijkant'], 'kw__leidingen': 'parallel' }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-r.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': 'plafond' }, 'https://www.radiator-outlet.nl/nl/luxe-chrome-thermostatische-radiator-aansluitset-r.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-r.html': { 'kw__aansluiting': ['rechtlinks-onder', 'zijkant'], 'kw__leidingen': 'parallel' }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-r.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': 'plafond' }, 'https://www.radiator-outlet.nl/nl/luxe-zwarte-thermostatische-radiator-aansluitset-r.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-re.html': { 'kw__aansluiting': ['rechtlinks-onder', 'zijkant'], 'kw__leidingen': 'parallel' }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-re.html#': { 'kw__aansluiting': ['boven'], 'kw__leidingen': 'plafond' }, 'https://www.radiator-outlet.nl/nl/luxe-witte-thermostatische-radiator-aansluitset-re.html##': { 'kw__aansluiting': ['onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/universele-chrome-radiator-aansluitset-midden-onde.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/oppio-universele-radiator-aansluitset-zwart-midden.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/universele-witte-radiator-aansluitset-midden-onder.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': 'vloer' }, 'https://www.radiator-outlet.nl/nl/oppio-universele-chrome-radiator-aansluitset.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': ['wand', 'plafond'] }, 'https://www.radiator-outlet.nl/nl/universele-zwarte-radiator-aansluitset-midden-onde.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': ['wand', 'plafond'] }, 'https://www.radiator-outlet.nl/nl/universele-witte-radiator-aansluitset-mi-134802606.html': { 'kw__aansluiting': ['middenonder', 'rechtlinks-onder'], 'kw__leidingen': ['wand', 'plafond'] }, }; // Function to toggle insert product selection in step 14 function toggleInsertSelection() { const jaRadio = document.getElementById('aansluitset_ja'); const insertSection = document.getElementById('insertProductSection'); if (jaRadio && jaRadio.checked && insertSection) { insertSection.style.display = 'block'; loadInsertProduct(); } else if (insertSection) { insertSection.style.display = 'none'; } // Update next button state updateNextButtonState(); } function showStep(stepId) { const container = document.querySelector('.container'); // Remove previous step classes from container container.classList.remove('step1', 'step2', 'step3'); // Add current step class to container container.classList.add(stepId); // Hide all steps document.querySelectorAll('.step').forEach(step => { step.classList.remove('active'); }); // Show the requested step document.getElementById(stepId).classList.add('active'); // Make next button sticky with JavaScript makeNextButtonSticky(); // Handle conditional color options for step 10 if (stepId === 'step10') { showConditionalColors(); } // Handle conditional step 11 and dynamic title if (stepId === 'step11') { updateStep11Title(); } // Handle size filtering step if (stepId === 'step12-size') { populateSizeFilterOptions(); } // Handle conditional step 12 variant options if (stepId === 'step12') { updateVariantOptions(); } // Handle conditional step 13a and dynamic connection options if (stepId === 'step13a') { updateConnectionOptions(); } // Handle conditional step 13 and dynamic options if (stepId === 'step13') { updateStep13Title(); } // Handle conditional step 15 and dynamic title if (stepId === 'step15') { updateStep15Title(); updateLeidingenOptions(); } // Handle step 16 product results if (stepId === 'step16') { // Get required radiator count and create footer const formData = getCurrentFormData(); requiredRadiatorCount = parseInt(formData.radiator_count) || 1; // Create the selection footer immediately when step 16 loads createSelectionFooter(); // Load products after a short delay to allow the step to render setTimeout(() => { fetchAndDisplayProducts(true); }, 100); } // Handle step 16a stromingsbuis selection if (stepId === 'step16a') { // Add radio button event listeners for stromingsbuis choice setupStromingsbuisRadioListeners(); } // Update progress bar based on step (19 steps total, ~5.26% per step) if (stepId === 'step1') { setProgress(5); } else if (stepId === 'step2') { setProgress(11); } else if (stepId === 'step3') { setProgress(16); } else if (stepId === 'step4') { setProgress(21); } else if (stepId === 'step5') { setProgress(26); } else if (stepId === 'step6') { setProgress(32); } else if (stepId === 'step7') { setProgress(37); } else if (stepId === 'step8') { setProgress(42); } else if (stepId === 'step9') { setProgress(47); } else if (stepId === 'step10') { setProgress(53); } else if (stepId === 'step11') { setProgress(58); } else if (stepId === 'step12-size') { setProgress(60); } else if (stepId === 'step12') { setProgress(63); } else if (stepId === 'step13a') { setProgress(68); } else if (stepId === 'step13') { setProgress(74); } else if (stepId === 'step14') { setProgress(84); } else if (stepId === 'step15') { setProgress(79); } else if (stepId === 'step16') { setProgress(89); // Push dataLayer event for reaching product results pushDataLayerEvent('keuzetool_step_16', { reached_product_results: true }); } else if (stepId === 'step17') { setProgress(68); } else if (stepId === 'step18') { setProgress(79); // Load aansluitset products when step18 is shown loadAansluitsetProducts(); } else if (stepId === 'step19') { setProgress(100); } } function updateProgressBar(percentage) { const progressFill = document.getElementById('progressFill'); const progressLabels = document.querySelectorAll('.progress-label'); const progressDots = document.querySelectorAll('.progress-dot'); // Remove active class from all labels and dots progressLabels.forEach(label => label.classList.remove('active')); progressDots.forEach(dot => dot.classList.remove('active')); // Update progress bar width progressFill.style.width = percentage + '%'; // Update active labels based on progress - keep previous steps active if (percentage > 0) { progressLabels[0].classList.add('active'); // Uw ruimte } if (percentage > 33) { progressLabels[1].classList.add('active'); // Radiator } if (percentage > 66) { progressLabels[2].classList.add('active'); // Advies } // Update active dots based on progress if (percentage >= 50) { progressDots[0].classList.add('active'); // middle dot } if (percentage >= 100) { progressDots[1].classList.add('active'); // end dot } } function setProgress(percentage) { currentProgress = percentage; updateProgressBar(percentage); } function incrementProgress() { currentProgress = Math.min(currentProgress + 10, 100); updateProgressBar(currentProgress); } function decrementProgress() { currentProgress = Math.max(currentProgress - 10, 10); updateProgressBar(currentProgress); } function goBack() { const currentStep = document.querySelector('.step.active'); if (currentStep.id === 'step2') { showStep('step1'); } else if (currentStep.id === 'step3') { showStep('step2'); } else if (currentStep.id === 'step4') { showStep('step3'); } else if (currentStep.id === 'step5') { showStep('step4'); } else if (currentStep.id === 'step6') { showStep('step5'); } else if (currentStep.id === 'step7') { showStep('step6'); } else if (currentStep.id === 'step8') { // Check if we came from step 7 or should go back to step 6 const keepExistingValue = document.querySelector('input[name="keep_existing"]:checked')?.value; if (keepExistingValue === 'yes') { showStep('step7'); } else { showStep('step6'); } } else if (currentStep.id === 'step9') { showStep('step8'); } else if (currentStep.id === 'step10') { showStep('step9'); } else if (currentStep.id === 'step11') { showStep('step10'); } else if (currentStep.id === 'step12-size') { showStep('step11'); } else if (currentStep.id === 'step12') { showStep('step11'); } else if (currentStep.id === 'step13a') { showStep('step12'); } else if (currentStep.id === 'step13') { // Check if we came from step13a (connection) or need to go somewhere else const selectedHeating = document.querySelector('input[name="heating"]:checked'); selectedRadiators = []; if (selectedHeating && selectedHeating.value === 'elektrisch') { // For electric heating, step13 shouldn't be reachable normally, but go back to step12 showStep('step16'); } else { // For non-electric heating, go back to step13a (connection step) showStep('step16'); } } else if (currentStep.id === 'step14') { showStep('step18'); } else if (currentStep.id === 'step15') { // Go back to step 13 (connection and aansluitset selection) showStep('step13'); } else if (currentStep.id === 'step16') { // Check heating type to determine where to go back const selectedHeating = document.querySelector('input[name="heating"]:checked'); if (selectedHeating && selectedHeating.value === 'elektrisch') { // For electric heating, go back to step12 (surface variant) showStep('step12'); } else { // For non-electric heating, go back to step13 (aansluitset question) showStep('step13a'); } } else if (currentStep.id === 'step16a') { // Go back to step 15 (pipe situation) showStep('step15'); } else if (currentStep.id === 'step17') { // Go back to step 16 (product results) showStep('step16'); } else if (currentStep.id === 'step18') { // Go back based on whether we came from stromingsbuis step if (shouldShowStromingsbuisStep()) { // Go back to step 16a (stromingsbuis selection) showStep('step16a'); } else { // Go back to step 15 (pipe situation) showStep('step15'); } } else if (currentStep.id === 'step19') { // Go back based on how we reached step 19 const formData = getCurrentFormData(); if (window.isOnderbloksetSelected) { // Came from step 14 (onderblokset flow) showStep('step14'); } else if (shouldShowStromingsbuisStep()) { // Came from step 16a (stromingsbuis selection) showStep('step16a'); } else if (formData.aansluitset_needed === 'ja') { // Came from step 18 (regular aansluitset selected) showStep('step18'); } else { // Came directly from step 13 (no aansluitset needed) showStep('step13'); } } } function nextStep() { const currentStep = document.querySelector('.step.active'); if (currentStep.id === 'step2') { const selectedRoom = document.querySelector('input[name="room"]:checked'); if (selectedRoom) { console.log('Selected room:', selectedRoom.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_2', { room_type: selectedRoom.value }); // Increment progress by 10% incrementProgress(); // Go to isolation quality step showStep('step3'); } } else if (currentStep.id === 'step3') { const selectedIsolation = document.querySelector('input[name="isolation"]:checked'); if (selectedIsolation) { console.log('Selected isolation:', selectedIsolation.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_3', { isolation_quality: selectedIsolation.value }); // Increment progress by 10% incrementProgress(); // Go to dimensions step showStep('step4'); } } else if (currentStep.id === 'step4') { const height = document.getElementById('height').value; const width = document.getElementById('width').value; const length = document.getElementById('length').value; if (height && width && length) { console.log('Dimensions:', {height, width, length}); // Push dataLayer event pushDataLayerEvent('keuzetool_step_4', { room_height: height, room_width: width, room_length: length, room_volume: (height * width * length).toFixed(2) }); // Increment progress by 10% incrementProgress(); // Go to heating type step showStep('step5'); } } else if (currentStep.id === 'step5') { const selectedHeating = document.querySelector('input[name="heating"]:checked'); if (selectedHeating) { console.log('Selected heating:', selectedHeating.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_5', { heating_type: selectedHeating.value }); // Increment progress by 10% incrementProgress(); // Go to keep existing heating step showStep('step6'); } } else if (currentStep.id === 'step6') { const selectedKeepExisting = document.querySelector('input[name="keep_existing"]:checked'); if (selectedKeepExisting) { console.log('Keep existing heating:', selectedKeepExisting.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_6', { keep_existing_radiators: selectedKeepExisting.value }); // Increment progress by 10% incrementProgress(); // Check if user wants to keep existing radiators if (selectedKeepExisting.value === 'yes') { // Go to step 7 for radiator power input showStep('step7'); } else { // Skip step 7 and go directly to step 8 showStep('step8'); } } } else if (currentStep.id === 'step7') { const radiatorPower = document.getElementById('radiator_power').value; if (radiatorPower) { console.log('Radiator power:', radiatorPower); // Push dataLayer event pushDataLayerEvent('keuzetool_step_7', { existing_radiator_power: radiatorPower }); // Increment progress by 10% incrementProgress(); // Go to step 8 for temperature selection showStep('step8'); } } else if (currentStep.id === 'step8') { const selectedTemperature = document.getElementById('desired_temperature').value; if (selectedTemperature) { console.log('Selected temperature:', selectedTemperature); // Push dataLayer event pushDataLayerEvent('keuzetool_step_8', { desired_temperature: selectedTemperature }); // Increment progress by 10% incrementProgress(); // Go to step 9 for radiator count showStep('step9'); } } else if (currentStep.id === 'step9') { const radiatorCount = document.getElementById('radiator_count').value; if (radiatorCount) { console.log('Radiator count:', radiatorCount); // Push dataLayer event pushDataLayerEvent('keuzetool_step_9', { radiator_count: radiatorCount }); // Increment progress by 10% incrementProgress(); // Go to step 10 for color selection showStep('step10'); } } else if (currentStep.id === 'step10') { const selectedColor = document.querySelector('input[name="radiator_color"]:checked'); if (selectedColor) { console.log('Selected color:', selectedColor.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_10', { radiator_color: selectedColor.value }); // Increment progress by 10% incrementProgress(); // Check if we should show step 11 (orientation) - not for bathroom const selectedRoom = document.querySelector('input[name="room"]:checked')?.value; const selectedHeating = document.querySelector('input[name="heating"]:checked')?.value; if (selectedRoom !== 'badkamer') { showStep('step11'); } else { // For bathroom, skip orientation and variant steps, but still show connection steps for non-electric heating if (selectedHeating !== 'elektrisch') { // Skip to connection step for bathroom with non-electric heating showStep('step13a'); } else { // For electric heating in bathroom, generate search directly console.log('Bathroom with electric heating selected, generating product search...'); createProductSearchUrl(); showStep('step16'); } } } } else if (currentStep.id === 'step11') { const selectedOrientation = document.querySelector('input[name="radiator_orientation"]:checked'); if (selectedOrientation) { console.log('Selected orientation:', selectedOrientation.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_11', { radiator_orientation: selectedOrientation.value }); // Increment progress by 10% incrementProgress(); // Go to size filtering step showStep('step12'); } } else if (currentStep.id === 'step12-size') { // Size filtering step - always proceed to step 12 (surface variant) // Increment progress by 10% incrementProgress(); showStep('step12'); } else if (currentStep.id === 'step12') { const selectedVariant = document.querySelector('input[name="radiator_variant"]:checked'); if (selectedVariant) { console.log('Selected variant:', selectedVariant.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_12', { radiator_variant: selectedVariant.value }); // Increment progress by 10% incrementProgress(); // After variant selection, check heating type const selectedHeating = document.querySelector('input[name="heating"]:checked'); if (selectedHeating && selectedHeating.value === 'elektrisch') { // For electric heating, skip connection step and go directly to products createProductSearchUrl(); showStep('step16'); } else { // For non-electric heating, go to connection step showStep('step13a'); } } } else if (currentStep.id === 'step13a') { const selectedConnection = document.querySelector('input[name="radiator_connection"]:checked'); if (selectedConnection) { console.log('Selected connection:', selectedConnection.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_13a', { radiator_connection: selectedConnection.value }); // Increment progress by 10% incrementProgress(); // Go to step 13 for aansluitset question showStep('step16'); } } else if (currentStep.id === 'step13') { const selectedAansluitsetNeeded = document.querySelector('input[name="aansluitset_needed"]:checked'); if (selectedAansluitsetNeeded) { console.log('Selected aansluitset needed:', selectedAansluitsetNeeded.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_13', { aansluitset_needed: selectedAansluitsetNeeded.value }); // Increment progress by 10% incrementProgress(); if (selectedAansluitsetNeeded.value === 'ja') { // User wants aansluitset, go to step 15 for pipe situation showStep('step15'); } else { // User doesn't want aansluitset, go to product results createProductSearchUrl(); showStep('step19'); } } } else if (currentStep.id === 'step14') { const selectedAansluitset = document.querySelector('input[name="aansluitset"]:checked'); if (selectedAansluitset) { console.log('Selected aansluitset:', selectedAansluitset.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_14', { aansluitset: selectedAansluitset.value }); // Increment progress by 10% incrementProgress(); // Go to step 19 (final step) after aansluitset selection showStep('step19'); } } else if (currentStep.id === 'step15') { const selectedLeidingen = document.querySelector('input[name="leidingen"]:checked'); if (selectedLeidingen) { console.log('Selected leidingen:', selectedLeidingen.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_15', { leidingen: selectedLeidingen.value }); // Increment progress by 10% incrementProgress(); // Check if stromingsbuis step should be shown if (shouldShowStromingsbuisStep()) { console.log('Going to stromingsbuis step after leidingen selection'); showStep('step16a'); } else { // Go to step 18 for aansluitset product selection showStep('step18'); } } } else if (currentStep.id === 'step17') { // Handle extra radiator response const extraRadiatorChoice = document.querySelector('input[name="extra_radiator"]:checked'); if (extraRadiatorChoice) { // Push dataLayer event pushDataLayerEvent('keuzetool_step_17', { extra_radiator: extraRadiatorChoice.value }); } handleExtraRadiatorResponse(); } else if (currentStep.id === 'step18') { // Handle aansluitset selection const aansluitsetChoice = document.querySelector('input[name="aansluitset_needed"]:checked'); if (aansluitsetChoice) { // Push dataLayer event pushDataLayerEvent('keuzetool_step_18', { aansluitset_needed: aansluitsetChoice.value }); if (aansluitsetChoice.value === 'no') { // User doesn't want aansluitset, go to step 19 showStep('step19'); } else if (aansluitsetChoice.value === 'yes') { // User wants aansluitset, but need to wait for product selection // This will be handled by selectAansluitset function console.log('Waiting for aansluitset product selection'); } } } else if (currentStep.id === 'step16a') { // Handle stromingsbuis choice const stromingsbuisChoice = document.querySelector('input[name="stromingsbuis_needed"]:checked'); if (stromingsbuisChoice) { console.log('Stromingsbuis choice:', stromingsbuisChoice.value); // Push dataLayer event pushDataLayerEvent('keuzetool_step_16a', { stromingsbuis_needed: stromingsbuisChoice.value }); incrementProgress(); // If "yes" was chosen, check if a product was actually selected if (stromingsbuisChoice.value === 'yes') { const productSelected = document.querySelector('.stromingsbuis-product.selected'); if (!productSelected) { alert('Selecteer eerst een stromingsbuis product'); return; } } // After stromingsbuis step, continue to step18 for aansluitset product selection showStep('step18'); } } } // Handle radio button selection function handleRadioSelection() { const radioButtons = document.querySelectorAll('input[type="radio"]'); radioButtons.forEach(radio => { radio.addEventListener('change', function () { const currentStep = this.closest('.step'); const nextButton = currentStep.querySelector('.next-button'); // Remove selected class from all options in this step currentStep.querySelectorAll('.radio-option,.color-option').forEach(option => { option.classList.remove('selected'); }); // Add selected class to the current option if (this.checked) { this.closest('.radio-option,.color-option').classList.add('selected'); if (nextButton) { nextButton.disabled = false; } // Handle aansluitset selection visibility if (this.name === 'aansluitset_needed') { // For step 18: show/hide aansluitset products (original logic) const productsSection = document.getElementById('aansluitset-products'); if (productsSection) { if (this.value === 'yes') { productsSection.style.display = 'block'; // Disable next button until product is selected if (nextButton) { nextButton.disabled = true; } } else { productsSection.style.display = 'none'; // Enable next button for "no" selection if (nextButton) { nextButton.disabled = false; } } } } } }); }); } // Handle dropdown selection function handleDropdownSelection() { const dropdowns = document.querySelectorAll('select'); dropdowns.forEach(dropdown => { dropdown.addEventListener('change', function () { const currentStep = this.closest('.step'); const nextButton = currentStep.querySelector('.next-button'); // Add valid class when a value is selected if (this.value) { this.classList.add('valid'); if (nextButton) { nextButton.disabled = false; } } else { this.classList.remove('valid'); if (nextButton) { nextButton.disabled = true; } } }); }); } // Handle dimension inputs function handleDimensionInputs() { const dimensionInputs = document.querySelectorAll('.dimension-input'); dimensionInputs.forEach(input => { input.addEventListener('input', function () { const inputGroup = this.closest('.input-group'); const value = parseInt(this.value); const min = parseInt(this.min); const max = parseInt(this.max); // Check if value is valid if (value >= min && value <= max) { this.classList.add('valid'); inputGroup.classList.add('valid'); } else { this.classList.remove('valid'); inputGroup.classList.remove('valid'); } // Check if all dimensions are filled and valid if (this.closest('#step4')) { checkDimensionsComplete(); } else if (this.closest('#step7')) { checkRadiatorPowerComplete(); } else if (this.closest('#step9')) { checkRadiatorCountComplete(); } }); }); } function checkDimensionsComplete() { const step4 = document.getElementById('step4'); if (!step4) return; const height = document.getElementById('height'); const width = document.getElementById('width'); const length = document.getElementById('length'); const nextButton = step4.querySelector('.next-button'); const allValid = height && width && length && height.classList.contains('valid') && width.classList.contains('valid') && length.classList.contains('valid'); if (nextButton) { nextButton.disabled = !allValid; } } function checkRadiatorPowerComplete() { const step7 = document.getElementById('step7'); if (!step7) return; const radiatorPower = document.getElementById('radiator_power'); const nextButton = step7.querySelector('.next-button'); const isValid = radiatorPower && radiatorPower.classList.contains('valid'); if (nextButton) { nextButton.disabled = !isValid; } } function checkRadiatorCountComplete() { const step9 = document.getElementById('step9'); if (!step9) return; const radiatorCount = document.getElementById('radiator_count'); const nextButton = step9.querySelector('.next-button'); const isValid = radiatorCount && radiatorCount.classList.contains('valid'); if (nextButton) { nextButton.disabled = !isValid; } } function showConditionalColors() { // Get the selected room from step 2 const selectedRoom = document.querySelector('input[name="room"]:checked')?.value; // Get all color options const colorOptions = document.querySelectorAll('#step10 .color-option'); // Show/hide colors based on room selection colorOptions.forEach(option => { const colorValue = option.querySelector('input').value; if (colorValue === 'zwart' || colorValue === 'wit') { // Always show black and white option.style.display = 'flex'; } else if (selectedRoom === 'badkamer') { // Show all colors for bathroom option.style.display = 'flex'; } else { // Hide special colors for other rooms option.style.display = 'none'; } }); } async function populateSizeFilterOptions() { const container = document.getElementById('sizeFilterOptions'); if (!container) return; container.innerHTML = '
Formaten ophalen...
';
try {
// Generate product search URL
const searchUrl = createProductSearchUrl();
// Fetch products with JSON format
const response = await fetch(searchUrl);
const data = await response.json();
// Extract unique size combinations from actual products
const sizeCombinations = new Set();
console.log(response, searchUrl, data.products, Object.keys(data.products).length > 0);
if (data.products && Object.keys(data.products).length > 0) {
// Fetch individual product details to get accurate size information
const productPromises = Object.values(data.products).map(async (product) => {
console.log(product);
if (product.url) {
try {
const productUrl = baseUrl + "/" + currentLanguage + "/" + product.url + '?format=json';
const productResponse = await fetch(productUrl);
const productData = await productResponse.json();
if (productData.product.size && productData.product.size.x && productData.product.size.y) {
const width = Math.round(productData.product.size.x);
const height = Math.round(productData.product.size.y);
sizeCombinations.add(`${width}x${height}`);
}
} catch (error) {
console.error('Error fetching product details:', product.url, error);
}
}
});
// Wait for all product fetches to complete
await Promise.all(productPromises);
}
// Clear loading message
container.innerHTML = '';
if (sizeCombinations.size === 0) {
container.innerHTML = 'Geen formaten gevonden
';
return;
}
// Sort combinations by width, then height
const sortedCombinations = Array.from(sizeCombinations).sort((a, b) => {
const [aWidth, aHeight] = a.split('x').map(Number);
const [bWidth, bHeight] = b.split('x').map(Number);
if (aWidth !== bWidth) return aWidth - bWidth;
return aHeight - bHeight;
});
// Create options for each unique size combination
sortedCombinations.forEach(combination => {
const [width, height] = combination.split('x');
const optionDiv = document.createElement('div');
optionDiv.className = 'size-filter-option';
optionDiv.innerHTML = `
${width} cm
${height} cm
`;
container.appendChild(optionDiv);
});
} catch (error) {
console.error('Error fetching size options:', error);
container.innerHTML = 'Fout bij laden van formaten
';
}
}
function updateStep11Title() {
// Get the radiator count from step 9
const radiatorCount = parseInt(document.getElementById('radiator_count')?.value) || 1;
const titleElement = document.getElementById('step11-title');
if (titleElement) {
// Use single or multiple title based on radiator count
const titleKey = radiatorCount === 1 ? 'step11_title_single' : 'step11_title_multiple';
if (translations[currentLanguage] && translations[currentLanguage][titleKey]) {
titleElement.textContent = translations[currentLanguage][titleKey];
}
}
}
function updateStep13Title() {
// Get the radiator count and heating type
const radiatorCount = parseInt(document.getElementById('radiator_count')?.value) || 1;
const selectedHeating = document.querySelector('input[name="heating"]:checked')?.value;
const selectedRoom = document.querySelector('input[name="room"]:checked')?.value;
const selectedOrientation = document.querySelector('input[name="radiator_orientation"]:checked')?.value;
const titleElement = document.getElementById('step13-title');
if (titleElement) {
console.log(selectedHeating, selectedRoom, selectedOrientation);
// Determine if it's a panel radiator (non-electric heating)
const isPanelRadiator = selectedHeating !== 'elektrisch' && selectedRoom !== 'badkamer' && selectedOrientation == 'horizontaal';
// Use appropriate title based on count and type
let titleKey;
if (isPanelRadiator) {
titleKey = radiatorCount === 1 ? 'step13_title_single_paneel' : 'step13_title_multiple_paneel';
} else {
titleKey = radiatorCount === 1 ? 'step13_title_single' : 'step13_title_multiple';
}
if (translations[currentLanguage] && translations[currentLanguage][titleKey]) {
titleElement.textContent = translations[currentLanguage][titleKey];
}
}
}
function updateVariantOptions() {
// Get the selected heating type and room from previous steps
const selectedHeating = document.querySelector('input[name="heating"]:checked')?.value;
const selectedRoom = document.querySelector('input[name="room"]:checked')?.value;
const ribbelOption = document.querySelector('label[for="variant_ribbel"]');
if (ribbelOption) {
// Hide "Geribbeld (standaard) voorzijde" option for electric bathroom radiators
if (selectedHeating === 'elektrisch') {
ribbelOption.style.display = 'none';
// If this option was selected, deselect it and select the first available option
const ribbelInput = document.getElementById('variant_ribbel');
if (ribbelInput && ribbelInput.checked) {
ribbelInput.checked = false;
// Select the first visible option (variant_glad)
const gladInput = document.getElementById('variant_glad');
if (gladInput) {
gladInput.checked = true;
}
}
} else {
// Show the option for other combinations
ribbelOption.style.display = 'block';
}
}
}
function updateConnectionOptions() {
// Get the selected orientation
const selectedOrientation = document.querySelector('input[name="radiator_orientation"]:checked')?.value;
const connectionContainer = document.getElementById('connection-options');
if (!connectionContainer) return;
// Clear existing options
connectionContainer.innerHTML = '';
// Define connection options based on orientation
const verticalOptions = [
{value: 'boven', key: 'connection_boven'},
{value: 'onder', key: 'connection_onder'},
{value: 'middenonder', key: 'connection_middenonder'},
];
const horizontalOptions = [
{value: 'middenonder', key: 'connection_middenonder'},
{value: 'rechtlinks-onder', key: 'connection_rechtlinks_onder'},
{value: 'zijkant', key: 'connection_zijkant'}
];
// Choose options based on orientation, default to both if no orientation selected yet
let optionsToShow = [];
if (selectedOrientation === 'verticaal') {
optionsToShow = verticalOptions;
} else if (selectedOrientation === 'horizontaal') {
optionsToShow = horizontalOptions;
} else {
// If no orientation selected yet (e.g., bathroom), show all options
optionsToShow = [...verticalOptions];//, ...horizontalOptions
}
// Create HTML for options
optionsToShow.forEach(option => {
const optionHTML = `
`;
connectionContainer.innerHTML += optionHTML;
});
// Re-initialize radio button handling for new options
handleRadioSelection();
}
function updateStep15Title() {
// Get the selected connection type from step 13
const selectedConnection = document.querySelector('input[name="radiator_connection"]:checked')?.value;
const titleElement = document.getElementById('step15-title');
const formData = getCurrentFormData();
if (titleElement) {
// Use appropriate title based on connection type
let titleKey = 'step15_title_default';
if (selectedConnection === 'zijkant') {
titleKey = 'step15_title_zijkant';
} else if (selectedConnection === 'onder' || selectedConnection === 'middenonder' || selectedConnection === 'rechtlinks-onder') {
titleKey = 'step15_title_onder';
} else if (selectedConnection === 'boven') {
titleKey = 'step15_title_boven';
if (formData.room === 'badkamer')
document.querySelector('#step15 .expert-info').style.display = 'block';
}
if (translations[currentLanguage] && translations[currentLanguage][titleKey]) {
titleElement.textContent = translations[currentLanguage][titleKey];
}
}
}
function updateLeidingenOptions() {
// Get the selected connection type from step 13a
const selectedConnection = document.querySelector('input[name="radiator_connection"]:checked')?.value;
const parallelOption = document.querySelector('label[for="leidingen_parallel"]');
if (parallelOption) {
// Hide "leidingen parallel" option for middenonder and rechtlinks-onder connections
if (selectedConnection === 'middenonder' || selectedConnection === 'rechtlinks-onder') {
parallelOption.style.display = 'none';
// If this option was selected, deselect it and select the first available option
const parallelInput = document.getElementById('leidingen_parallel');
if (parallelInput && parallelInput.checked) {
parallelInput.checked = false;
// Select the first visible option (leidingen_wand)
const wandInput = document.getElementById('leidingen_wand');
if (wandInput) {
wandInput.checked = true;
}
}
} else {
// Show the option for other connection types
parallelOption.style.display = 'block';
}
}
}
// Final step action functions
function restartTool() {
// Reset all form data
document.querySelectorAll('input[type="radio"]').forEach(input => {
input.checked = false;
});
document.querySelectorAll('input[type="number"]').forEach(input => {
input.value = '';
});
document.querySelectorAll('select').forEach(select => {
select.selectedIndex = 0;
});
// Reset selection state (if variables are defined globally)
if (typeof selectedRadiators !== 'undefined') {
selectedRadiators = [];
requiredRadiatorCount = 0;
}
if (typeof selectedAansluitsets !== 'undefined') {
selectedAansluitsets = [];
requiredAansluitsetCount = 0;
}
// Hide selection footer
const footer = document.querySelector('.radiator-selection-footer');
if (footer) footer.style.display = 'none';
// Reset progress and go to first step
setProgress(5);
showStep('step1');
}
function directCheckout() {
// Here you would typically redirect to your checkout page or handle checkout logic
console.log('Direct checkout clicked');
//alert('Direct afrekenen functionaliteit wordt geïmplementeerd');
window.location.href = `/${currentLanguage}/checkout/`;
}
function viewCart() {
// Here you would typically show cart modal or redirect to cart page
console.log('View cart clicked');
//alert('Winkelwagen bekijken functionaliteit wordt geïmplementeerd');
window.location.href = `/${currentLanguage}/cart`;
}
function shouldShowStromingsbuisStep() {
const formData = getCurrentFormData();
return formData.room === 'badkamer' && formData.radiator_connection === 'boven';
}
let stickyButtonTimeout;
function makeNextButtonSticky() {
const container = document.querySelector('.radiator-keuzetool .container');
const nextButton = container.querySelector('.step.active .next-button');
if (!container || !nextButton) return;
// Remove any existing sticky positioning
nextButton.style.position = 'relative';
if (window.innerWidth < 900){
nextButton.style.bottom = '';
nextButton.style.left = '';
nextButton.style.right = '';
nextButton.style.zIndex = '';
nextButton.style.borderRadius = '';
nextButton.style.boxShadow = '';
}
const containerRect = container.getBoundingClientRect();
const buttonRect = nextButton.getBoundingClientRect();
// Only make sticky if button would appear above container bottom
//if (buttonRect.bottom < containerRect.bottom) {
if (window.innerWidth < 900){
nextButton.style.position = 'fixed';
nextButton.style.bottom = `${window.innerHeight - containerRect.bottom - 10}px`;
nextButton.style.left = `${containerRect.left}px`;
nextButton.style.right = `${window.innerWidth - containerRect.right}px`;
nextButton.style.zIndex = '1000';
nextButton.style.borderRadius = '0 0 12px 12px';
nextButton.style.boxShadow = '0 -2px 10px rgba(0,0,0,0.1)';
}
/*}else{
// Reset styles if not sticky
nextButton.style.position = 'relative';
nextButton.style.bottom = '';
nextButton.style.left = '';
nextButton.style.right = '';
nextButton.style.zIndex = '';
nextButton.style.borderRadius = '';
nextButton.style.boxShadow = '';
}*/
}
function debouncedMakeNextButtonSticky() {
// Clear existing timeout
if (stickyButtonTimeout) {
clearTimeout(stickyButtonTimeout);
}
// Set new timeout
stickyButtonTimeout = setTimeout(() => {
makeNextButtonSticky();
}, 300);
}
function setupContentObserver() {
const contentElement = document.querySelector('.radiator-keuzetool .content');
if (!contentElement) return;
const observer = new MutationObserver((mutations) => {
let shouldUpdate = false;
mutations.forEach((mutation) => {
if (mutation.type === 'childList' || mutation.type === 'attributes' || mutation.type === 'subtree') {
shouldUpdate = true;
}
});
if (shouldUpdate) {
debouncedMakeNextButtonSticky();
}
});
observer.observe(contentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class', 'style', 'disabled']
});
console.log('Content observer setup for sticky button');
}
function setupStromingsbuisRadioListeners() {
const radioButtons = document.querySelectorAll('input[name="stromingsbuis_needed"]');
const productResults = document.getElementById('stromingsbuisResults');
const nextButton = document.querySelector('#step16a .next-button');
radioButtons.forEach(radio => {
radio.addEventListener('change', function () {
if (nextButton) {
nextButton.disabled = false;
}
// Remove selected class from all options
document.querySelectorAll('#step16a .radio-option').forEach(option => {
option.classList.remove('selected');
});
// Add selected class to current option
if (this.checked) {
this.closest('.radio-option').classList.add('selected');
if (this.value === 'yes' && productResults) {
// Show product section and load stromingsbuis products
productResults.style.display = 'block';
setTimeout(() => {
loadStromingsbuisProducts();
}, 100);
} else if (productResults) {
// Hide product section
productResults.style.display = 'none';
}
}
});
});
}
function startKeuzetool() {
// Set initial step class on container
document.querySelector('.container').classList.add('step1');
// Activate the keuzetool
document.querySelector('.radiator-keuzetool').classList.add('active');
// Initialize with default language
updateTexts();
// Start the USP carousel
startUSPCarousel();
// Initialize radio button handling
handleRadioSelection();
// Initialize dimension inputs handling
handleDimensionInputs();
// Initialize dropdown handling
handleDropdownSelection();
// Initialize progress bar and set initial step
setProgress(5);
// Setup content observer for sticky button
setupContentObserver();
}
let openKiesWijzer = (e) => {
e?.preventDefault();
startKeuzetool();
}
const setKieswijzerPopup = (node) => {
node.addEventListener('click', e => {
e.preventDefault();
startKeuzetool();
});
node.classList.remove('openkeuzehulp');
}
// observe, alle .openkeuzehulp buttons omzetten naar onclick openkieswijzer. Daarna openkeuzehulp class verwijderen,
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.classList.contains('openkeuzehulp')) {
setKieswijzerPopup(node)
}
});
});
});
observer.observe(document.body, {childList: true, subtree: true});
document.querySelectorAll('.openkeuzehulp').forEach(node => setKieswijzerPopup(node));
if (window.location.search.includes('?keuzehulp')) {
openKiesWijzer();
}
// Keuzetool Product Functions - Part 2
// Product filtering, search, and cart functionality
// Product filtering and search logic
const baseUrl = 'https://www.radiator-outlet.nl/';
const category = 'collection';
let resultUrl = '';
let forcedWattage = false;
let zoekWattage = 0;
let maxForcedWattageTried = 0;
// Filter mappings
const manieren = {'elektrisch': 0.75, 'cv': 1, 'stadsverwarming': 1, 'warmtepomp': 1.4};
const kamers = {
"badkamer": 829873,
"woonkamer": 829871,
"slaapkamer": 829872,
"keuken": 829874,
"kantoor": 829875,
"gang": 829876
};
const filters = {
breedte: {
"823387": [30],
"823388": [40],
"823389": [45],
"823390": [50],
"823391": [60],
"825019": [90],
},
hoogte: {
"823372": [50],
"823373": [60],
"823375": [70],
"823376": [80],
"823378": [100],
"823379": [120],
"823380": [140],
"823381": [160],
"825029": [170],
"823382": [180],
"823383": [200],
},
watt: {
"823421": [300, 400],
"823418": [400, 500],
"823419": [500, 600],
"823420": [600, 700],
"823422": [700, 800],
"823423": [800, 900],
"823424": [900, 1000],
"823425": [1000, 1250],
"823426": [1250, 1500],
"823427": [1500, 2000],
"823428": [2000, 2500],
"823429": [2500, 3000],
"823430": [3000, 3500],
"823431": [3500, 4000],
"823432": 4000
},
kleur: {
"zwart": 824894,
"wit": 824891,
"antraciet": 824895,
"chroom": 824892,
"goud": 824893
},
variant: {
"ribbel": 823691,
"vlak": 823694,
"groef": 823693
},
orientatie: {
"verticaal": [823367, 829878],
"horizontaal": 829877
},
aansluiting: {
"zijkant": [823367, 823368],
"rechtlinks-onder": [823367, 823368],
"middenonder": 823368,
"boven": [823367, 823368],
"onder": [823367, 823368]
}
};
async function getProductHeight(product) {
let specs = {};
try {
const productUrl = baseUrl + "/" + currentLanguage + "/" + product.url + '?format=json';
const productResponse = await fetch(productUrl);
const productData = await productResponse.json();
specs = productData.product.specs || {};
} catch (error) {
console.error('Error fetching product details:', product.url, error);
return '';
}
console.log(specs)
if (!specs || Object.values(specs).length === 0) {
return '';
}
// Find the spec with title "Hoogte"
const heightSpec = Object.values(specs).find(spec => spec.title === 'Hoogte');
console.log(heightSpec)
if (!heightSpec || !heightSpec.value) return '';
// Extract numeric value and remove " cm" suffix
const heightValue = heightSpec.value.replace(/\s*cm\s*$/i, '').trim();
// Convert to number and return
const numericHeight = parseInt(heightValue);
return isNaN(numericHeight) ? '' : numericHeight.toString();
}
function getNextWattageRange(currentWattage) {
const numericCurrent = Math.round(parseFloat(currentWattage) || 0);
if (numericCurrent <= 0) {
forcedWattage = false;
return false;
}
if (numericCurrent > maxForcedWattageTried) {
maxForcedWattageTried = numericCurrent;
}
const wattageKeys = Object.keys(filters.watt).sort((a, b) => {
const rangeA = Array.isArray(filters.watt[a]) ? filters.watt[a][0] : filters.watt[a];
const rangeB = Array.isArray(filters.watt[b]) ? filters.watt[b][0] : filters.watt[b];
return rangeA - rangeB;
});
for (let i = 0; i < wattageKeys.length; i++) {
const range = filters.watt[wattageKeys[i]];
if (
(Array.isArray(range) && numericCurrent >= range[0] && numericCurrent <= range[1]) ||
(!Array.isArray(range) && numericCurrent <= range)
) {
const nextRange = filters.watt[wattageKeys[i + 1]];
if (!nextRange) {
forcedWattage = false;
return false;
}
const candidateWattage = Array.isArray(nextRange)
? nextRange[0] + 1
: nextRange + 1;
if (candidateWattage <= numericCurrent || candidateWattage <= maxForcedWattageTried) {
forcedWattage = false;
return false;
}
forcedWattage = candidateWattage;
maxForcedWattageTried = candidateWattage;
return true;
}
}
forcedWattage = false;
return false;
}
function createProductSearchUrl() {
const zoekfilters = [];
// Get form data from current selections
const formData = getCurrentFormData();
// Calculate wattage requirements
const badkamer_toeslag = formData.room === 'badkamer'
? (formData.heating === 'warmtepomp' ? 1.25 : 0.75)
: 1;
const inhoud =
(parseFloat(formData.height) || 0) / 100 *
(parseFloat(formData.width) || 0) / 100 *
(parseFloat(formData.length) || 0) / 100;
const temperatuurverschil = parseFloat(formData.temperature) || 70;
const isolatiefactor = 1 + (formData.isolation === 'slecht' ? 0.5 :
formData.isolation === 'normaal' ? 0.25 : 0);
const basis_warmtevraag = badkamer_toeslag * inhoud * temperatuurverschil * isolatiefactor;
const vermogen_behouden = formData.keep_existing === 'yes'
? parseFloat(formData.radiator_power) || 0
: 0;
const manieren_factor = manieren[formData.heating] || 1;
const totaal_wattage = (basis_warmtevraag * manieren_factor) - vermogen_behouden;
const radiatoren = parseInt(formData.radiator_count) || 1;
const zoek_wattage = forcedWattage !== false ? forcedWattage : (totaal_wattage / radiatoren);
const roundedZoekWattage = Math.round(zoek_wattage || 0);
if (forcedWattage === false) {
maxForcedWattageTried = roundedZoekWattage;
} else {
maxForcedWattageTried = Math.max(maxForcedWattageTried, roundedZoekWattage);
}
if (zoekWattage === 0) {
zoekWattage = zoek_wattage;
}
console.log('Calculated wattage:', zoek_wattage, 'Total wattage:', totaal_wattage, 'Form data:', formData);
// Add wattage filter
for (const [key, range] of Object.entries(filters.watt)) {
if (Array.isArray(range)) {
if (zoek_wattage >= range[0] && zoek_wattage <= range[1]) {
zoekfilters.push(key);
break;
}
} else if (zoek_wattage >= range) {
zoekfilters.push(key);
break;
}
}
// Add room filter
if (formData.room && kamers[formData.room]) {
zoekfilters.push(kamers[formData.room]);
}
// Add heating type filter
if (formData.heating) {
if (formData.heating === 'elektrisch') {
zoekfilters.push(829883);
} else {
zoekfilters.push(913796);
zoekfilters.push(829884);
}
}
// Add color filter
if (formData.radiator_color && filters.kleur[formData.radiator_color]) {
zoekfilters.push(filters.kleur[formData.radiator_color]);
}
// Add orientation filter
if (formData.radiator_orientation && filters.orientatie[formData.radiator_orientation]) {
const orient = filters.orientatie[formData.radiator_orientation];
if (Array.isArray(orient)) {
if(formData.heating === 'elektrisch') // remove value 823367
orient.splice(orient.indexOf(823367), 1);
zoekfilters.push(...orient);
} else {
zoekfilters.push(orient);
}
}
if (formData.radiator_orientation === undefined && formData.room === 'badkamer' && formData.heating !== 'elektrisch') {
zoekfilters.push(823367);
zoekfilters.push(824151);
}
// Add variant filter
if (formData.radiator_variant && filters.variant[formData.radiator_variant]) {
zoekfilters.push(filters.variant[formData.radiator_variant]);
}
// Add connection filter
if (formData.radiator_connection && filters.aansluiting[formData.radiator_connection]) {
const aansluitingFilter = filters.aansluiting[formData.radiator_connection];
if (Array.isArray(aansluitingFilter)) {
zoekfilters.push(...aansluitingFilter);
} else {
zoekfilters.push(aansluitingFilter);
}
}
// Add size filters based on allowed dimensions (not excluded ones)
const excludedSizeCombinations = Array.from(document.querySelectorAll('input[name="excluded_sizes"]:checked'))
.map(checkbox => checkbox.value);
if (excludedSizeCombinations.length > 0) {
// Get all available size combinations from the UI
const allSizeCombinations = Array.from(document.querySelectorAll('input[name="excluded_sizes"]'))
.map(checkbox => checkbox.value);
// Calculate allowed (non-excluded) size combinations
const allowedSizeCombinations = allSizeCombinations.filter(
combination => !excludedSizeCombinations.includes(combination)
);
// Convert allowed size combinations to filter IDs
const allowedWidths = new Set();
const allowedHeights = new Set();
allowedSizeCombinations.forEach(combination => {
const [width, height] = combination.split('x').map(Number);
allowedWidths.add(width);
allowedHeights.add(height);
});
// Add filter IDs for allowed dimensions
for (const [filterId, widthArray] of Object.entries(filters.breedte)) {
if (allowedWidths.has(widthArray[0])) {
zoekfilters.push(filterId);
}
}
for (const [filterId, heightArray] of Object.entries(filters.hoogte)) {
if (allowedHeights.has(heightArray[0])) {
zoekfilters.push(filterId);
}
}
}
// Store excluded sizes for client-side filtering as backup
window.excludedSizeCombinations = excludedSizeCombinations;
// remove duplicates from zoekfilters
const uniqueFilters = [...new Set(zoekfilters)];
// Generate the URL
const url = `${baseUrl}${currentLanguage}/${category}/page1.json?` +
uniqueFilters.map(filter => `filter[]=${filter}`).join('&') +
'&limit=2000&mode=grid&sort=lowest';
console.log('Generated search URL:', url);
resultUrl = url;
return url;
}
function getCurrentFormData() {
return {
room: document.querySelector('input[name="room"]:checked')?.value,
isolation: document.querySelector('input[name="isolation"]:checked')?.value,
height: document.getElementById('height')?.value,
width: document.getElementById('width')?.value,
length: document.getElementById('length')?.value,
heating: document.querySelector('input[name="heating"]:checked')?.value,
keep_existing: document.querySelector('input[name="keep_existing"]:checked')?.value,
radiator_power: document.getElementById('radiator_power')?.value,
temperature: document.getElementById('desired_temperature')?.value,
radiator_count: document.getElementById('radiator_count')?.value,
radiator_color: document.querySelector('input[name="radiator_color"]:checked')?.value,
radiator_orientation: document.querySelector('input[name="radiator_orientation"]:checked')?.value,
radiator_variant: document.querySelector('input[name="radiator_variant"]:checked')?.value,
radiator_connection: document.querySelector('input[name="radiator_connection"]:checked')?.value,
aansluitset: document.querySelector('input[name="aansluitset"]:checked')?.value,
leidingen: document.querySelector('input[name="leidingen"]:checked')?.value
};
}
async function fetchResultsAndUpdateUI(retries = 3) {
if (!resultUrl || resultUrl === '') {
createProductSearchUrl();
}
try {
console.log('Fetching results from:', resultUrl);
const response = await fetch(resultUrl);
const data = await response.json();
const count = data.count ?? 0;
const products = data.products ?? {};
if (count === 0 && retries > 0) {
console.log("No results found, trying next wattage range...");
const nextWattageRange = getNextWattageRange(
forcedWattage !== false ? forcedWattage : zoekWattage
);
if (nextWattageRange) {
console.log(`Retrying with forced wattage: ${forcedWattage}`);
createProductSearchUrl();
return fetchResultsAndUpdateUI(retries - 1);
} else {
// No wattage range found, show extra radiator question
console.log("No suitable wattage range found, showing extra radiator question");
showExtraRadiatorStep();
return;
}
}
let minPrice = Infinity;
let maxPrice = -Infinity;
Object.values(products).forEach(product => {
const price = product.price?.price_incl ?? 0;
if (price < minPrice) minPrice = price;
if (price > maxPrice) maxPrice = price;
});
minPrice = minPrice === Infinity ? 0 : minPrice;
maxPrice = maxPrice === -Infinity ? 0 : maxPrice;
// Show results in console for now - we'll implement UI display later
console.log(`Results: ${count} products found, €${minPrice.toFixed(2)} - €${maxPrice.toFixed(2)}`);
return {
count,
minPrice,
maxPrice,
products,
url: resultUrl
};
} catch (error) {
console.error("Error fetching results:", error);
return {
count: 0,
minPrice: 0,
maxPrice: 0,
products: {},
error: error.message
};
}
}
// Global variables for price range
let originalPriceRange = {min: 0, max: 3000};
// Product rendering functions
async function fetchAndDisplayProducts(isInitialLoad = false) {
if (!resultUrl || resultUrl === '') {
createProductSearchUrl();
}
const productsContainer = document.getElementById('productResults');
try {
console.log('Fetching products from:', resultUrl);
const response = await fetch(resultUrl);
const data = await response.json();
const count = data.count ?? 0;
const products = data.products ?? {};
// On initial load, determine price range and setup slider
if (isInitialLoad && Object.keys(products).length > 0) {
let minPrice = Infinity;
let maxPrice = -Infinity;
Object.values(products).forEach(product => {
const price = product.price?.price_incl || product.price?.price || 0;
if (price > 0) {
if (price < minPrice) minPrice = price;
if (price > maxPrice) maxPrice = price;
}
});
originalPriceRange.min = minPrice === Infinity ? 0 : Math.floor(minPrice);
originalPriceRange.max = maxPrice === -Infinity ? 3000 : Math.ceil(maxPrice);
// Initialize price slider with actual price range
updatePriceSliderRange(originalPriceRange.min, originalPriceRange.max);
}
// Update the product count in the filter tab
const allProductsTab = document.querySelector('[data-translate="all_products"]');
if (allProductsTab) {
allProductsTab.textContent = allProductsTab.textContent.replace(/\(\d+\)/, `(${count})`);
}
// Update radiator count in step title
const radiatorCountSpan = document.getElementById('radiator-count');
if (radiatorCountSpan) {
if (currentLanguage === 'nl') {
radiatorCountSpan.textContent = count > 0 ? `${count} ideale` : 'geen';
} else {
radiatorCountSpan.textContent = count > 0 ? `${count} radiateurs idéaux` : 'aucun radiateur idéal';
}
}
if (count === 0) {
if (isInitialLoad) {
// Try next wattage range first
const nextWattageRange = getNextWattageRange(
forcedWattage !== false ? forcedWattage : zoekWattage
);
if (nextWattageRange) {
console.log("No results found, trying next wattage range...", zoekWattage, forcedWattage);
createProductSearchUrl();
return fetchAndDisplayProducts(true); // Retry with new wattage
} else {
// No higher wattage range available, show extra radiator question
console.log("No suitable wattage range found, showing extra radiator question");
showExtraRadiatorStep();
return;
}
} else {
// Not initial load, just show no products message
productsContainer.innerHTML = `
Geen producten gevonden met de geselecteerde filters.
Probeer andere filterinstellingen.
Er is een fout opgetreden bij het laden van de producten.
ELEKTRISCH
' :
'';
// Determine if this product should show recommended badge
const isRecommended = first || product.isRecommended;
const recommendedBadge = isRecommended ?
'#1 AANBEVOLEN
' : '';
// Calculate savings (example: random between 15-35%)
const originalPrice = product.price.price_old ? parseFloat(product.price.price_old) : 199.95;
const currentPrice = product.price ? parseFloat(product.price.price) : 159.95;
const discount = Math.floor((originalPrice - currentPrice) / originalPrice * 100);
const productFeatures = isElectric ?
[translateText('fast_heating'), translateText('energy_efficient')] :
[translateText('thermostat_control'), translateText('timer_function')];
const prodHeight = await getProductHeight(product);
return `
${recommendedBadge}
${electricBadge}
${originalPrice > currentPrice ? `
`;
}
function addProductEventListeners() {
// Add any additional event listeners for product interactions
console.log('Product event listeners added');
}
// Global selection state
let selectedRadiators = [];
let selectedRadiatorHeights = [];
let requiredRadiatorCount = 0;
let selectedAansluitsets = [];
let requiredAansluitsetCount = 0;
async function selectProduct(productId) {
console.log('Product selected:', productId);
// Get required radiator count from form data
const formData = getCurrentFormData();
requiredRadiatorCount = parseInt(formData.radiator_count) || 1;
// Allow multiple selections of the same product
if (selectedRadiators.length < requiredRadiatorCount) {
// Find the button that was clicked
const button = document.querySelector(`button[onclick="selectProduct('${productId}')"]`);
if (button) {
// Store original button content
const originalContent = button.innerHTML;
const originalClass = button.className;
// Add to cart first
try {
await addProductToCart(button);
// Change to "Toegevoegd" state only if cart addition was successful
button.innerHTML = translateText('added_to_cart');
button.className = 'btn-added';
button.disabled = true;
// Revert after 2.5 seconds
setTimeout(() => {
button.innerHTML = originalContent;
button.className = originalClass;
button.disabled = false; // Allow re-selection
button.style.opacity = '1';
}, 2500);
selectedRadiators.push(productId);
const height = button.getAttribute('data-height');
if (height && !selectedRadiatorHeights.includes(height)) {
selectedRadiatorHeights.push(height);
}
updateSelectionFooter();
// Check if we need connection sets
if (selectedRadiators.length >= requiredRadiatorCount) {
setTimeout(() => {
checkForConnectionSets();
}, 3000); // Increased to allow button animation to complete
}
} catch (error) {
console.error('Failed to add to cart:', error);
// Show error state
button.innerHTML = '❌ Fout';
button.className = 'btn-error';
setTimeout(() => {
button.innerHTML = originalContent;
button.className = originalClass;
button.disabled = false;
}, 2000);
}
}
} else {
console.log('Maximum number of radiators already selected');
// Optionally show a message that max is reached
checkForConnectionSets();
}
}
async function addProductToCart(button, qty) {
const pid = button.getAttribute('data-vid');
const title = button.getAttribute('data-title');
const cartUrl = button.getAttribute('data-cart-url');
console.log('Adding to cart:', title);
// Create form data for cart addition
const formData = {
'quantity': qty || '1',
}
// Prepare cart URL (convert product URL to cart URL)
const baseUrl = 'https://www.radiator-outlet.nl';
const cartAddUrl = `${baseUrl}/${currentLanguage}/cart/add/${pid}/`;
try {
const response = await fetch(cartAddUrl, {
method: 'POST',
body: new URLSearchParams(formData),
credentials: 'same-origin'
});
if (!response.ok) {
throw new Error(`Cart addition failed: ${response.status}`);
}
const result = await response.text();
console.log('Product added to cart successfully:', title);
// Update cart UI if elements exist
updateCartUI();
return result;
} catch (error) {
console.error('Error adding to cart:', error);
throw error;
}
}
function updateCartUI() {
// Update cart quantity if element exists
const cartQty = document.querySelector('#qty, .cart-qty');
if (cartQty) {
// This would need to be updated based on actual cart response
// For now, just increment by 1
const currentQty = parseInt(cartQty.textContent) || 0;
cartQty.textContent = currentQty + 1;
}
console.log('Cart UI updated');
}
function updateSelectionFooter() {
let footerElement = document.querySelector('.radiator-selection-footer');
if (!footerElement) {
createSelectionFooter();
footerElement = document.querySelector('.radiator-selection-footer');
}
const radiatorRemaining = requiredRadiatorCount - selectedRadiators.length;
const aansluitsetRemaining = requiredAansluitsetCount - selectedAansluitsets.length;
const totalRemaining = radiatorRemaining + aansluitsetRemaining;
const footerText = footerElement.querySelector('.selection-text');
const continueBtn = footerElement.querySelector('.continue-btn');
if (totalRemaining > 0) {
let text = '';
if (radiatorRemaining > 0) {
text += translateText('select_more_radiators').replace('{count}', radiatorRemaining).replace('{plural}', radiatorRemaining > 1 ? translateText('plural_radiator') : '');
}
if (aansluitsetRemaining > 0) {
if (text) text += ` ${translateText('and')} `;
text += translateText('select_more_aansluitsets').replace('{count}', aansluitsetRemaining).replace('{plural}', aansluitsetRemaining > 1 ? translateText('plural_aansluitset') : '');
}
footerText.textContent = text;
continueBtn.style.display = 'none';
} else {
let text = '';
if (requiredRadiatorCount > 0) {
text += translateText('radiators_selected').replace('{count}', requiredRadiatorCount).replace('{plural}', requiredRadiatorCount > 1 ? translateText('plural_radiator') : '');
}
if (requiredAansluitsetCount > 0) {
if (text) text += ` ${translateText('and')} `;
text += translateText('aansluitsets_selected').replace('{count}', requiredAansluitsetCount).replace('{plural}', requiredAansluitsetCount > 1 ? translateText('plural_aansluitset') : '');
}
footerText.textContent = text;
continueBtn.style.display = 'block';
}
footerElement.style.display = 'block';
}
function createSelectionFooter() {
// Remove existing footer if it exists
const existingFooter = document.querySelector('.radiator-selection-footer');
if (existingFooter) {
existingFooter.remove();
}
const footer = document.createElement('div');
footer.className = 'radiator-selection-footer';
footer.innerHTML = `
${generateStars(product.score || 0)}
${(product.score * 5).toFixed(1)}/5${product.brand?.title || 'OPPIO'}
${product.title || '80x50 cm - Oppio E-Basis Mat Zwart'}
${generateProductSubtitle(product)}
${productFeatures.map(feature => `
${feature}
`).join('')}
Laden...
€${currentPrice.toFixed(2)}
${originalPrice > currentPrice ? `€${originalPrice.toFixed(2)}
` : ''}
${translateText('save_amount').replace('{amount}', (originalPrice - currentPrice).toFixed(2)).replace('{discount}', discount)}
` : ''}
✓Snelle levering
✓14 dagen bedenktijd
${first ? `` :
``}
${translateText('select_radiators').replace('{count}', requiredRadiatorCount).replace('{plural}', requiredRadiatorCount > 1 ? translateText('plural_radiator') : '')}
`;
// Insert footer as first child in delivery-bar (before delivery-bar-content)
const deliveryBar = document.querySelector('.delivery-bar');
const deliveryBarContent = document.querySelector('.delivery-bar-content');
if (deliveryBar && deliveryBarContent) {
deliveryBar.insertBefore(footer, deliveryBarContent);
} else if (deliveryBar) {
deliveryBar.insertBefore(footer, deliveryBar.firstChild);
} else {
document.body.appendChild(footer);
}
// Show footer immediately
footer.style.display = 'block';
}
function checkForConnectionSets() {
const formData = getCurrentFormData();
const deliveryBar = document.querySelector('.delivery-bar');
if (deliveryBar) {
deliveryBar.style.display = 'none';
}
// Check if connection sets are needed (non-electric heating and aansluitset step was answered with "ja")
if (formData.heating !== 'elektrisch') { // && formData.aansluitset === 'ja'
// Show aansluitset selection step
showStep('step13');
} else {
// Go to final checkout/confirmation
showFinalStep();
}
}
async function loadAansluitsetProducts() {
const formData = getCurrentFormData();
const connection = formData.radiator_connection;
const leidingen = formData.leidingen;
const productsSection = document.getElementById('aansluitset-products');
productsSection.style.display = 'block';
console.log('Loading aansluitset products for connection:', connection, 'leidingen:', leidingen);
// Filter products based on connection type and pipe situation
const matchingUrls = [];
for (const [url, rules] of Object.entries(aansluitsetProducts)) {
let matches = true;
// Check leidingen rule
if (Array.isArray(rules.kw__leidingen))
matches = rules.kw__leidingen.includes(leidingen)
else if (rules.kw__leidingen && rules.kw__leidingen !== leidingen)
matches = false;
// Check aansluiting rule if it exists
if (matches && rules.kw__aansluiting) {
if (rules.kw__aansluiting[0] === 'not') {
// If rule is ['not', 'middenonder', 'rechtlinks-onder'], connection should NOT be in the rest of the array
const excludedConnections = rules.kw__aansluiting.slice(1);
if (excludedConnections.includes(connection)) {
matches = false;
}
} else {
// If rule is ['middenonder', 'rechtlinks-onder'], connection should be in the array
if (!rules.kw__aansluiting.includes(connection)) {
matches = false;
}
}
}
if (matches) {
matchingUrls.push(url);
}
}
console.log('Matching aansluitset URLs:', matchingUrls);
// Fetch and render products
const resultsContainer = document.getElementById('aansluitsetResults');
if (resultsContainer) {
try {
let validProducts = [];
if (matchingUrls.length > 0) {
// Fetch all products in parallel
const productPromises = matchingUrls.map(url => fetchAansluitsetProduct(url));
const products = await Promise.all(productPromises);
// Filter out failed fetches
validProducts = products.filter(product => product !== null);
}
// Always add hardcoded product to the list
//validProducts.push(hardcodedProduct);
// Update product count
const countSpan = document.getElementById('aansluitset-count');
if (countSpan) {
countSpan.textContent = validProducts.length;
}
const productHTML = validProducts.map(product => renderAansluitsetCard(product)).join('');
resultsContainer.innerHTML = productHTML;
// Fetch stock information for each product (skip hardcoded product)
validProducts.forEach(product => {
if (product.id !== '134802320') {
fetchAansluitsetStock(product);
}
});
} catch (error) {
console.error('Error loading aansluitset products:', error);
resultsContainer.innerHTML = `${translateText('error_loading_aansluitsets')}
Product laden...
${translateText('error_loading_insert')}
${translateText('error_loading_insert')}
${translateText('recommended')}
${stars}
${(product.score * 5).toFixed(1)}/5${product.brand?.title || 'ECA'}
${product.title}
${product.subtitle}
Laden...
€${currentPrice.toFixed(2)}
${originalPrice > currentPrice ? `€${originalPrice.toFixed(2)}
` : ''}
${translateText('save_amount_simple').replace('{amount}', (originalPrice - currentPrice).toFixed(2))}
` : ''}
✓${translateText('free_shipping_text')}
✓${translateText('return_policy')}
${translateText('popular_choice')}
${stars}
${(product.score * 5).toFixed(1)}/5${product.brand?.title || 'OPPIO'}
${product.title}
${product.subtitle}
Laden...
€${currentPrice.toFixed(2)}
${originalPrice > currentPrice ? `€${originalPrice.toFixed(2)}
` : ''}
${translateText('save_amount_simple').replace('{amount}', (originalPrice - currentPrice).toFixed(2))}
` : ''}
✓${translateText('free_shipping_text')}
✓${translateText('return_policy')}
${translateText('loading_stromingsbuis')}
`;
try {
const maxHeight = getSelectedRadiatorMaxHeight();
const stromingsbuisUrl = getStromingsbuisUrl(maxHeight);
if (!stromingsbuisUrl) {
container.innerHTML = `${translateText('no_suitable_stromingsbuis')}
`;
return;
}
const response = await fetch(stromingsbuisUrl + '?format=json');
const productData = await response.json();
if (productData && productData.product) {
displayStromingsbuisProduct(productData.product, container);
} else {
container.innerHTML = `${translateText('error_loading_stromingsbuis')}
`;
}
} catch (error) {
console.error('Error loading stromingsbuis:', error);
container.innerHTML = `${translateText('error_loading_stromingsbuis')}
`;
}
}
function getSelectedRadiatorMaxHeight() {
let maxHeight = 0;
selectedRadiatorHeights.forEach(height => {
const numericHeight = parseInt(height);
if (!isNaN(numericHeight) && numericHeight > maxHeight) {
maxHeight = numericHeight;
}
});
console.log('Max radiator height:', maxHeight);
return maxHeight;
}
function getStromingsbuisUrl(height) {
if (height >= 180) {
return 'https://www.radiator-outlet.nl/nl/stromingsbuis-1740-x-1-2.html';
} else if (height >= 111) {
return 'https://www.radiator-outlet.nl/nl/stromingsbuis-1110-x-1-2.html';
} else if (height >= 80) {
return 'https://www.radiator-outlet.nl/nl/stromingsbuis-720-x-1-2.html';
} else {
return 'https://www.radiator-outlet.nl/nl/stromingsbuis-720-x-1-2.html';
}
}
function displayStromingsbuisProduct(product, container) {
const productHTML = `
${product.title}
€${product.price.price}
${product.price.price_old ? `€${product.price.price_old}` : ''}













