Load html and css file in build file

USE case: Load a static template.html and styles.css dynamically at runtime from index.js
I have one html file(template.html) as below

<template id="frame">
    <div class="outerwrap h-screen ">
        <header class="bg-deep-ocean-140">
            <div class="flex flex-row items-center min-h-4-5">
                <div class="px-4 grow">
                    <div data-slot="SomeComponentSlot"></div>
                </div>
                <div class="px-4">
                    <div data-slot="LogoutButton"></div>
                </div>
            </div>
        </header>
        <main class="h-full p-4">
            <div data-slot="main">Main Content</div>
        </main>
        <footer class="p-4">
            <div data-slot="footer">Footer</div>
        </footer>
    </div>
</template>

A css file(styles.css) which contains css for above classes.

I am importing these files in index.js as following:

const TEMPLATE_LOCATION = './src/template.html';
const TEMPLATE_STYLES = './src/styles.css';

async function loadAndCloneViewTemplate() {
  const response = await fetch(TEMPLATE_LOCATION);
  const content = await response.text();
  const container = document.createElement('div');
  container.innerHTML = content;
  const template = findInNodeList(
    container.children,
    (o) => o.nodeName === 'TEMPLATE'
  );
  return template.content.cloneNode(true);
}
async function addStyleForViewTemplate() {
  const link = document.createElement('link');
  link.type = 'text/css';
  link.rel = 'stylesheet';
  link.href = TEMPLATE_STYLES;
  return link;
}

Then we simply use this function to append them to dom.

const template = await loadAndCloneViewTemplate();
const styles = await addStyleForViewTemplate();
const root = document.querySelector('#root');
root.appendChild(template);
root.appendChild(styles);

I am using plain vanilla js. This works locally. But when we run build file for this, I am getting following error:
GET https://<---->.com/src/template.html net::ERR_ABORTED 403 (Forbidden)
When I checked build file it did not contain css and html content.

I tried changing the fetch with import with some different path for html file. But nothing worked. I am looking for something very simple which could do the job.

Can you disable the delay/animation when cancelling a native drag event?

While a drag event is occurring, if you drop the element in a droppable area the handler activates immediately. However, if you’re over a non-droppable area, or cancel by pressing escape, there’s a brief delay as the preview returns to the original spot. However, if you have the preview hidden then you want the drag cancel immediately.

One solution is to make everything a droppable area, but this only solves the problem of dropping outside the intended area, as cancelling will still be delayed.

I recognize that only modifier keys are accepted during a drag, overriding listening for a keydown. I’ve also seen this question: how to disable dragend animation in html5

Does one have to use a library, or build a custom drag solution using only pointer events?

How can I load the 4th list item from the end? [closed]

Here is jQuery code I am using to load 4th list item till end on scrolling down. Please guide. Thank You!

$(document).ready(function() {
  $(window).on("scroll");
  var status = [];
  $(window).scroll(function() {
    $(".hideme").each(function(i, el) {
      if (status[i] !== "showing") {
        var bottom_of_object = $(this).position().top + $(this).outerHeight();
        var bottom_of_window = $(window).scrollTop() + $(window).height();
        if (bottom_of_window > bottom_of_object - $(this).outerHeight() / 1.1) {
          $(this).animate({
            opacity: "1"
          }, 500);
          status[i] = "showing";
          if ($(".hideme").index($(this)) + 1 === $(".hideme").length) {
            $(window).off("scroll");
          }
        }
      }
    });
  });
});
.hideme {
  opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<ul>
  <li>some content</li>
  <li>some content</li>
  <li>some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
  <li class="hideme">some content</li>
</ul>

Need to show alert in an Chrome extension and backend is in Node JS

I need help I have developed a chrome extension where I have developed an API for user validation so on the backend side which is on Node JS. Its working fine. I am able to check the API in Postman and everything is fine but I want to show the alert if user enters wrong email id then on the frontend it show some alert like Access Denied

I have CHATGPT but its not working

How to export function in module

I used modular web api to install firebase, which works. This means I added my code in script type=”module”. The only issue with this is that I have a button that needs to add a document to the database. However, for some reason, when i call on the function using the button, it says its not defined. Below is my code

The button:

<div id="myDIV" class="todoheader">
  <h2 style="margin:5px">My To Do List</h2>
  <input type="text" id="myInput" placeholder="Task...">
  <span onclick="newElement()" class="addBtn">Add</span>
</div>

and the javascript


<script type="module">
  import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.7.2/firebase-app.js'
import { getFirestore, collection, doc, setDoc, query, where, getDocs  } from 'https://www.gstatic.com/firebasejs/10.7.2/firebase-firestore.js'

const firebaseApp = initializeApp({
    apiKey: "AIzaSyDx6xuNnelTuWLQVoJQQ_13_q3u2kULpCE",
    authDomain: "tododatabase-8cc76.firebaseapp.com",
    projectId: "tododatabase-8cc76",
    storageBucket: "tododatabase-8cc76.appspot.com",
    messagingSenderId: "342835299624",
    appId: "1:342835299624:web:2864e35382d74599ef7c1d",
    measurementId: "G-NVT04Z3FYN"
});
const db = getFirestore(firebaseApp);
const todolist = []
// Specify the collection you want to read from
const collectionName = "tododata";

// Get the collection reference
const collectionRef = collection(db, collectionName);
const q = query(collectionRef);
// Get all documents in the collection
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  todolist.push(doc.data())
  console.log(doc.id, " => ", doc.data());
});
console.log(todolist)
// Create a "close" button and append it to each list item
var list = document.querySelector('list-ul'); // Select the <ul> element
for( var i =0; i < todolist.length; i++) {
  const liElement = document.createElement("li");
  liElement.textContent = todolist[i]['Name'];
  if (todolist[i]['Crossed'] === true) {
    liElement.classList.add("checked");
  }
  console.log(liElement)
  list.appendChild(liElement);
}




// Create a "close" button and append it to each list item
var list = document.querySelector('list-ul'); // Select the <ul> element

var myNodelist = list.querySelectorAll('LI');
var i;
for (i = 0; i < myNodelist.length; i++) {
  var span = document.createElement("SPAN");
  var txt = document.createTextNode("u00D7");
  span.className = "close";
  span.appendChild(txt);
  myNodelist[i].appendChild(span);
}

// Click on a close button to hide the current list item
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
  close[i].onclick = function() {
    var div = this.parentElement;
    div.style.display = "none";
    console.log(i)
  }
}

// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('list-ul');
list.addEventListener('click', function(ev) {
  if (ev.target.tagName === 'LI') {
    ev.target.classList.toggle('checked');
    let name = ev.target.textContent
    

  }
}, false);

// Create a new list item when clicking on the "Add" button


function newElement() {
  print("e")
  var li = document.createElement("li");
  var inputValue = document.getElementById("myInput").value;
  var t = document.createTextNode(inputValue);
  li.appendChild(t);
  if (inputValue === '') {
    alert("You must write something!");
  } else {
    document.getElementById("myUL").appendChild(li);
  }
  document.getElementById("myInput").value = "";

  var span = document.createElement("SPAN");
  var txt = document.createTextNode("u00D7");
  span.className = "close";

  span.appendChild(txt);
  li.appendChild(span);

  for (i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentElement;
      div.style.display = "none";
    }
  }
}
</script>

The issue is that when i click “add” then it gives an error saying “newElement() is not defined”. I am new to javascript and firebase, and do not know what to do. Can someone help?

momentjs parseZone function weird behaviour when date-time string contains UTC offset +00:00

I am seeing a weird behaviour with momentjs parseZone function when using it to parse a date-time string containing UTC offset +00:00. The issue is mentioned as comments in the code snippet below:

var a1 = 'Jan 24, 2024 12:43 +00:00';
var a = moment.parseZone(a1, 'MMM DD, YYYY  hh:mm A Z');
console.log(">>>> a: " + a.format()); 
// outputs unexpected 2024-01-23T18:30:00Z

var b1 = 'Jan 24, 2024 12:43';
var b = moment.parseZone(b1, 'MMM DD, YYYY  hh:mm A');
console.log(">>>> b: " + b.format()); 
// outputs expected 2024-01-24T12:43:00Z

var c1 = "Jan 24, 2024  10:54 +00:00";
var c = moment.parseZone(c1, 'MMM DD, YYYY  hh:mm Z')
console.log(">>>> c: " + c.format());
// outputs expected 2024-01-24T10:54:00Z
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>

Can anybody please explain why a holds unexpected result but b and c expected result?

Thanks.

The page should not refresh when adding or removing a project

Good morning. Here is my code, I have been stuck for almost a week, I have tried several things, for the moment, I do not have the expected result, namely when adding or removing a project (work) the modification is displayed without the page reloading. For this I tried to put the list of projects retrieved via the API in localStorage then empty the gallery which contains the projects then display this gallery again. Thanks to anyone who helps me understand where the problem is coming from and how to fix it!


// Fonction pour créer un élément dans la galerie
const createGalleryItem = (work) => {
  const figure = document.createElement("figure");
  const img = document.createElement("img");

  // Ajouter les données récupérées à la balise img
  img.src = work.imageUrl;
  img.alt = work.title;

  figure.classList.add("itemGallery");
  figure.appendChild(img);

  // Création du bouton de suppression
  const deleteButton = document.createElement("button");
  deleteButton.type = "button"; //pour éviter la soumission du formulaire
  deleteButton.classList.add("delete-button");

  // Création du SVG trash
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
  svg.setAttribute("width", "9");
  svg.setAttribute("height", "11");
  svg.setAttribute("viewBox", "0 0 9 11");
  svg.setAttribute("fill", "none");

  // Création du chemin du SVG
  const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  path.setAttribute(
    "d",
    "M2.71607 0.35558C2.82455 0.136607 3.04754 0 3.29063 0H5.70938C5.95246 0 6.17545 0.136607 6.28393 0.35558L6.42857 0.642857H8.35714C8.71272 0.642857 9 0.930134 9 1.28571C9 1.64129 8.71272 1.92857 8.35714 1.92857H0.642857C0.287277 1.92857 0 1.64129 0 1.28571C0 0.930134 0.287277 0.642857 0.642857 0.642857H2.57143L2.71607 0.35558ZM0.642857 2.57143H8.35714V9C8.35714 9.70915 7.78058 10.2857 7.07143 10.2857H1.92857C1.21942 10.2857 0.642857 9.70915 0.642857 9V2.57143ZM2.57143 3.85714C2.39464 3.85714 2.25 4.00179 2.25 4.17857V8.67857C2.25 8.85536 2.39464 9 2.57143 9C2.74821 9 2.89286 8.85536 2.89286 8.67857V4.17857C2.89286 4.00179 2.74821 3.85714 2.57143 3.85714ZM4.5 3.85714C4.32321 3.85714 4.17857 4.00179 4.17857 4.17857V8.67857C4.17857 8.85536 4.32321 9 4.5 9C4.67679 9 4.82143 8.85536 4.82143 8.67857V4.17857C4.82143 4.00179 4.67679 3.85714 4.5 3.85714ZM6.42857 3.85714C6.25179 3.85714 6.10714 4.00179 6.10714 4.17857V8.67857C6.10714 8.85536 6.25179 9 6.42857 9C6.60536 9 6.75 8.85536 6.75 8.67857V4.17857C6.75 4.00179 6.60536 3.85714 6.42857 3.85714Z"
  );
  path.setAttribute("fill", "white");

  // Ajout du chemin au SVG
  svg.appendChild(path);

  // Ajout du SVG au bouton de suppression
  deleteButton.appendChild(svg);

  // Ajout du gestionnaire d'événement pour le bouton de suppression
  deleteButton.addEventListener("click", async (event) => {
    event.preventDefault();
    if (confirm(`Êtes-vous sûr de vouloir supprimer "${work.title}" ?`)) {
      try {
        const response = await fetch(
          `http://localhost:5678/api/works/${work.id}`,
          {
            method: "DELETE",
            headers: {
              Authorization: "Bearer " + localStorage.getItem("token"),
            },
          }
        );
        if (!response.ok) {
          throw new Error(
            `Erreur lors de la suppression : ${response.statusText}`
          );
        }

        // Suppression de l'œuvre du localStorage
        let works = JSON.parse(localStorage.getItem("works"));
        works = works.filter((storedWork) => storedWork.id !== work.id);
        localStorage.setItem("works", JSON.stringify(works));

        // Mise à jour de la galerie
        displayWorks(works);

        // Suppression de l'élément du DOM
        figure.remove();
      } catch (error) {
        console.error("Erreur lors de la suppression :", error);
      }
    }
  });
  // Ajout du bouton de suppression à l'élément figure
  figure.appendChild(deleteButton);

  return figure;
};

// Fonction pour afficher les œuvres dans la galerie
const displayWorks = (works) => {
  galleryModal.innerHTML = ""; // Vide la galerie avant d'ajouter de nouveaux éléments
  works.forEach((work) => {
    const galleryItem = createGalleryItem(work);
    galleryModal.appendChild(galleryItem);
  });
};

// Fonction asynchrone pour initialiser la galerie
const initializeGalleryModal = async () => {
  try {
    works = await fetchWorks();
    displayWorks(works);
  } catch (error) {
    console.error("Erreur lors de l'initialisation de la galerie :", error);
  }
};

// Appeler la fonction d'initialisation de la galerie
document.addEventListener("DOMContentLoaded", initializeGalleryModal);
////////////////////////ENVOIE//////////////////////////////////////////////////
// Fonction asynchrone pour récupérer les œuvres depuis l'API dans la modal
const fetchWorks = async () => {
  try {
    const response = await fetch("http://localhost:5678/api/works");
    if (!response.ok) {
      throw new Error(
        `Erreur de chargement des œuvres. Code HTTP : ${response.status}`
      );
    }
    const data = await response.json();

    // Stocker les œuvres récupérées dans le localStorage
    localStorage.setItem("works", JSON.stringify(data));

    return data;
  } catch (error) {
    console.error(
      "Erreur lors de la récupération des données de l'API :",
      error
    );
    throw error;
  }
};

document.addEventListener("DOMContentLoaded", () => {
  const addWorkForm = document.getElementById("addWorkForm");
  if (addWorkForm) {
    addWorkForm.addEventListener("submit", addWorkToGallery);
  } else {
    console.error("Le formulaire est introuvable dans le DOM.");
  }
});

async function addWorkToGallery(event) {
  event.preventDefault(); // Empêche le comportement par défaut du formulaire

  // Récupération du token d'authentification (si nécessaire pour l'API)
  const token = localStorage.getItem("token");
  if (!token) {
    console.error("Vous devez être connecté pour effectuer cette action.");
    return;
  }

  // Récupération des éléments et des valeurs du formulaire
  const titleInput = document.getElementById("title");
  const categorySelect = document.getElementById("categorie");
  const selectedImage = imageInput.files[0];

  if (titleInput.value.trim() === "" || categorySelect.value.trim() === "") {
    alert("Certains champs du formulaire ne sont pas remplis.");
    return;
  }

  // Création de l'objet FormData pour contenir les champs du formulaire
  const formData = new FormData();
  formData.append("image", selectedImage);
  formData.append("title", titleInput.value.trim());
  formData.append("category", categorySelect.value);

  try {
    // Envoi de la requête avec le token dans l'entête Authorization
    const response = await fetch("http://localhost:5678/api/works", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
      },
      body: formData,
    });
    if (!response.ok) {
      // Récupérer plus d'informations sur l'erreur
      const errorData = await response.json();
      throw new Error(`Erreur: ${response.statusText}` || errorData.message);
    }

    const newWork = await response.json();

    // Récupérez les œuvres stockées précédemment du localStorage
    let works = JSON.parse(localStorage.getItem("works")) || [];
    // Ajoutez le nouvel ouvrage à la liste
    works.push(newWork);
    // Mettez à jour les œuvres dans le localStorage
    localStorage.setItem("works", JSON.stringify(works));
    // Mettez à jour la galerie avec le nouvel ouvrage ajouté
    displayWorks(works);
  } catch (error) {
    console.error("Erreur lors de l'ajout de l'œuvre:", error);
  }
}

// Associer le gestionnaire de soumission au formulaire
document.addEventListener("DOMContentLoaded", () => {
  const addWorkForm = document.getElementById("addWorkForm");
  if (addWorkForm) {
    addWorkForm.addEventListener("submit", addWorkToGallery);
  } else {
    console.error("Le formulaire est introuvable dans le DOM.");
  }
});

// Fonction asynchrone pour récupérer les œuvres depuis l'API et les stocker dans le localStorage
const fetchWorksAndUpdateLocalStorage = async () => {
  try {
    // Vérifie si les œuvres sont déjà stockées dans le localStorage
    let works = localStorage.getItem("works");

    // Si les œuvres ne sont pas dans le localStorage ou si le localStorage a été vidé, les récupérer à partir de l'API
    if (!works) {
      const response = await fetch("http://localhost:5678/api/works");
      if (!response.ok) {
        throw new Error(
          `Erreur de chargement des œuvres. Code HTTP : ${response.status}`
        );
      }
      works = await response.json();

      // Stocke les œuvres récupérées dans le localStorage pour un accès rapide la prochaine fois
      localStorage.setItem("works", JSON.stringify(works));
    } else {
      // Si les données sont déjà présentes dans le localStorage, les parser pour les utiliser
      works = JSON.parse(works);
    }

    // Mettre à jour l'interface utilisateur avec les œuvres récupérées
    displayWorks(works);
  } catch (error) {
    console.error(
      "Erreur lors de la récupération des données de l'API :",
      error
    );
    throw error;
  }
};

// Sélectionne l'élément de la galerie
const galleryElement = document.getElementById("gallery");

// Vide la galerie avant de rajouter des éléments
galleryElement.innerHTML = "";

////////////////////////ENVOIE fin//////////////////////////////////



I want the page not to refresh when adding and deleting a project.

Working on vue2 to vue3 migration, found the problem ‘’Unexpected token ‘export’‘’

During my migration from vue2 to vue3, while running the application, I found an error line in the node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js file, which reads SyntaxError: Unexpected token 'export' The content of the error file reads

/* eslint-disable no-var */
// This file is imported into lib/wc client bundles.

if (typeof window !== 'undefined') {
  var currentScript = window.document.currentScript
  if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {
    var getCurrentScript = require('@soda/get-current-script')
    currentScript = getCurrentScript()

    // for backward compatibility, because previously we directly included the polyfill
    if (!('currentScript' in document)) {
      Object.defineProperty(document, 'currentScript', { get: getCurrentScript })
    }
  }

  var src = currentScript && currentScript.src.match(/(.+/)[^/]+.js(?.*)?$/)
  if (src) {
    __webpack_public_path__ = src[1] // eslint-disable-line
  }
}

// Indicate to webpack that this file can be concatenated
export default null

I’d like to solve the problem without modifying the code in this file, as I’m sharing the code with others, so I’m trying not to modify the code in the node_modules directory

HTMX – how to conditionally set target and swap?

I have a datatable and add item form which shows as a modal ( bootstrap ) I’m using htmx to add an entry and swap the datatable with latest data.

Now, I want to handle things like validation and errors.

How to approach this problem, I want to close modal and show updated table if request was successful, or I want to keep the modal and show form with error messages on modal.

Can i conditionally swap the target ? if xhr.status == 400, swap id_add_form else if xhr.status == 201 modal.close(); swap id_item_list

here is the outline of my code

<!--begin::Card-->
<div class="card" id="user_list_table">
...
    <button
                type="button"
                class="btn btn-primary"
                data-bs-toggle="modal"
                data-bs-target="#modal_add_item"
                hx-get="/add-item"
                hx-target="#add_user_form"
                hx-swap="innerHTML"
                hx-trigger="click">
    Add Item
    </button>

    <div class="modal">
    <form
        id="add_item_form"
        class="form"
        hx-post="/add-item"
        hx-trigger="submit"
        hx-swap="none"
    >
    ...
    </form>
    </div>
    ...

    <div id="item_list">
    ...
    </div>

...
</div>

and js


    document.addEventListener("htmx:afterRequest", function (event) {
    
                if (event.detail.elt == "add_item_form") {
    
                    var form = document.getElementById('add_item_form');
    
                    // if event is 200 ok
                    if (event.detail.xhr.status == 200) {
                        // close modal
                        form.reset();
                        modal.hide();
            }
        }
    }

Unable to identify value of input in JavaScript

I have watched many tutorials on how to solve this problem and even trying to log it into the console. However since I am quite new to this part of coding I feel like I have made a mistake, could someone please identify so I understand?

I tried using the <.value> but it didn’t seem to exist on VScode which was very odd.

here is my code:

const email = document.getElementById('emailId');
const password = document.getElementById('passwordId');
const repassword = document.getElementById('passwordreconfirmId'); 

let evalue = email.setAttribute(value,);
let pvalue = password.setAttribute(value,);
let rpvalue = repassword.setAttribute(value,);

function popup() {
    if (evalue, pvalue, rpvalue === 4) {
        document.getElementById('nextButton').removeAttribute('disabled', 'disabled');
    } else {
        document.getElementById('nextButton').setAttribute('disabled', 'disabled');
    }
}
<div class="Password-Text">
    <input type="password" onload="passwordvalue" class="pswd" id="passwordId">
</div>

<div class="Password-Text-Reconfirm">
    <input type="password" onload="repasswordvalue" class="re-pswd" id="passwordreconfirmId">
</div>

<div class="next_page"> 
    <button disabled="disabled" onload="popup()" type="submit" id="nextButton">
        <style>
        </style>
    </button>
</div>

No overload matches this call. NGRX

todo.selector.ts
No overload matches this call.
Overload 1 of 9, ‘(mapFn: (state: object) => Todo[]): Observable<Todo[]>’, gave the following error.
Argument of type ‘MemoizedSelector<AppState, Todo[], (s1: TodoState) => Todo[]>’ is not assignable to parameter of type ‘(state: object) => Todo[]’.
Types of parameters ‘state’ and ‘state’ are incompatible.
Property ‘todos’ is missing in type ‘{}’ but required in type ‘AppState’.
Overload 2 of 9, ‘(key: never): Observable’, gave the following error.
Argument of type ‘MemoizedSelector<AppState, Todo[], (s1: TodoState) => Todo[]>’ is not assignable to parameter of type ‘never’.ts(2769)
app.state.ts(4, 3): ‘todos’ is declared here.

Getting this above error will try to access the store.
while try to access the store

how to rectify this?

Any better way to internationalize Metadata with next-intl in a Next.js 13+ page?

I would like to internationalize text on every page in my app, as well as the title of the pages.

Starting with the text, as per the next-intl documentation page on internationalizing components, it can be done like this:

import {useTranslations} from 'next-intl';
 
export default function UserDetails({user}) {
  const t = useTranslations('UserProfile');
 
  return (
    <section>
      <h2>{t('heading')}</h2>
    </section>
  );
}

As for the metadata, as per the relevant page from the documentation, it is done like this:

import {getTranslations} from 'next-intl/server';
 
export async function generateMetadata({params: {locale}}) {
  const t = await getTranslations({locale, namespace: 'Metadata'});
 
  return {
    title: t('title')
  };
}

So, overall, for each page, the boilerplate will look like this:

import {useTranslations} from 'next-intl';
import {getTranslations} from 'next-intl/server';

export async function generateMetadata({params: {locale}}) {
  const t = await getTranslations({locale, namespace: 'Metadata'});

  return {
    title: t('title')
  };
}

export default function UserDetails({user}) {
  const t = useTranslations('UserProfile');

  return (
    <section>
      <h2>{t('heading')}</h2>
    </section>
  );
}

Is there a way to achieve this without declaring t twice on every page?

My variable starts with ‘undefined’ followed by the variable when viewed in HTML [duplicate]

so I am making a converter from Decimal to Binary using JS and HTML. I’m nearly finished with my task, but my code keeps printing ‘undefined‘ along with the answer.

For example, if I enter the number 9, I will get an output of:

0bundefined1001

Why is the ‘undefined’ there, and how do I get rid of it? Thank you a ton in advance. ^^

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1> Converter from Decimal to Binary</h1>
    <label for ="decimalNum" title = "A positive whole number (1, 2, 3, etc.), excluding 0 and inifinity."> Decimal (natural number) </div>: </label>
    <input id="decimalNum" type = "number"> 
    <button id="mySubmit"> Submit </button>
    <p id="binaryNum">  </p> <!-- Placeholder for the printed form in the Binary system.-->
    <i> Please note that the <b>0b</b> index in the Binary number is a prefix to indicate its system.</i>
    <script>
// NECESSARY VARIABLES DEFINED
        let decimalNum; // User's input
        let binaryNum; // (soon) converted decimalNum
        let x = 0; // explained in the algorithm 

// THIS FUNCTION CHECKS WHETHER THE USER'S INPUT IS A NATURAL NUMBER
        function is_Natural(n) 
            {
            if (typeof n !== 'number') 
                    return 'Not a number'; 
                    
            return (n > 0) && (Math.floor(n) === n) && n !== Infinity;
                }

// THIS SECTION CONVERTS THE USER'S INPUT TO THE BINARY SYSTEM

        document.getElementById("mySubmit").onclick = function() {
            decimalNum = document.getElementById("decimalNum").value; //retrieves the user's input and stores it in the previously defined variable
            decimalNum = Number(decimalNum) 
            if(is_Natural(decimalNum) === true) {
                while(true){
                    if(decimalNum < 2**x) {
                        x = x-1 // For it to let the left-most value be equal to 1
                        break
                    } else {
                        x = x+1
                    }
                }

                while(true) {
                    if(decimalNum>= 2**x) {
                        binaryNum = binaryNum + '1';
                        decimalNum = decimalNum - 2**x;
                        x = x-1
                    } else {
                        binaryNum = binaryNum + '0'
                        x = x-1
                    }
                    if(x < 0) {
                        break
                    }
                    else {
                        continue
                    }
                } }

                

            document.getElementById("binaryNum").textContent = `Here is your number in the Binary system: 0b${binaryNum}`; // replaces the placeholder
            }
        
    </script>
</body>
</html>

Is using an object with identical keys & values in a switch statement bad/pointless code?

So I’ve come across some of my old code, which is something like :

const valStore = {
  val1: "val1"
  val2: "val2"
  val3: "val3"
}

And it then is calls this like so:

switch (val) {
  case "val4":
    function()
  break;
  case "val5":
    coolFunction()
  break;
  case valStore[val]:
    otherFunction(val)
...

I don’t like that there is an entire object with identical keys & values it seems messy as it’s only 5 values in the real version, although a fall-through switch statement doesn’t seem much better:

switch (val) {
  case "val4":
    function()
    break;
  case "val5":
    coolFunction()
    break;
  case val1:
  case val2:
  case val3:
    otherFunction(val)
...

I’ve considered using sets and an else if, I’m not sure about if I want a replacement or if I’m wasting my time. It just got me thinking.