Set an attribute without replacing any existing class attributes

I have developed a script that updates the class attribute of the body element on my website when an option is selected from a dropdown menu. However, I am facing an issue where it overrides the existing dark mode attribute.

The purpose of this script is to modify the color scheme of the website and store the user's preference in local storage.

How can I resolve this conflict?

function updateTheme(value) { 
 var themes = { 
 chb: "griegos", 
 cj: "romanos", 
 hv: "celtas" 
 }; 
 document.getElementById("body").setAttribute("class", themes[value]);
}
.griegos {background: orange}
.romanos {background: purple}
.celtas {background: green}
<body id="body" class="griegos dark">
<select class="forminput" onchange="updateTheme(this.value)"><option value="chb">Camp Half-Blood</option><option value="cj">Camp Jupiter</option><option value="hv">Hotel Valhalla</option></select>

Answer №1

To achieve this, one approach is to utilize the Element.classList API:

// To ensure that we target elements only after the document has loaded and they are present,
// we wait for the 'DOMContentLoaded' event to trigger:
window.addEventListener('DOMContentLoaded', () => {
  // This is a named function that receives the 'evt'
  // (Event Object reference) automatically passed
  // from later use of EventTarget.addEventListener():
  function toggleClass(evt) {

    var index = {
      chb: "griegos",
      cj: "romanos",
      hv: "celtas"
    };

    // Locate the element by its id:
    document.getElementById("body")
      // Use Element.classList.remove() to eliminate
      // previously-selected class names:
      .classList.remove(
        // Construct an Array using spread syntax within
        // the <select> options:
        [...evt.target.options]
          // Array.prototype.map() allows us to generate
          // a new Array based on the existing Array:
          .map(
            // Assign the relevant class name retrieved from
            // the index Object based on the current option's value:
            (opt) => index[opt.value]
        )
      );
    // Once these class names are removed, select the element again
    // according to its id, and apply the appropriate class name
    // from the index Object using Element.classList.add():
    document.getElementById("body").classList.add(
      index[evt.currentTarget.value]
    );
  }

// Use document.querySelector() to locate the <select>
// element with a CSS selector:
document.querySelector('select.forminput')
  // Attach the event listener through
  // EventTarget.addEventListener(), assigning
  // the toggleClass() function to handle the 'change' event:
  .addEventListener('change', toggleClass);
});
.griegos {
  background: orange
}

.romanos {
  background: purple
}

.celtas {
  background: green
}
<body id="body" class="griegos dark">
  <select class="forminput">
    <option value="chb">Camp Half-Blood</option>
    <option value="cj">Camp Jupiter</option>
    <option value="hv">Hotel Valhalla</option>
  </select>
</body>

JS Fiddle demo

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What exactly do discrete animations entail?

In the MDN animation documentation, it mentions a type of animation known as "discrete". Can you explain what this term signifies? ...

Unable to direct to the main page in index.js of the next.js application

I have been working on a next.js application and encountered an issue with a component I created called <ButtonGroup>. I added a button with the code <Button href="index">Home</Button> to allow users to navigate back to the home ...

Client-Side Isomorphic JS: A Guide to Using HTTP Requests

Seeking advice on data population for isomorphic flux apps. (Using react, alt, iso, and node but principles are transferable) In my flux 'store' (), I need to fetch data from an api: getState() { return { data : makeHttpRequest(url) ...

Centered HTML Columns on the Screen

Figuring out this simple html + css issue is proving to be quite challenging for me. I am attempting to create a '3 column' layout. I envision a central column (approximately 10em in width) with two additional columns flanking it on each side (e ...

Numerous attributes for displaying ngOption values

I have an item that resembles the following: $scope.team = [ { name: "John", number: 1 }, { name: "Emma", number: 2 } ]; Currently, in my HTML code, I am using ngOption to populate a dropdown menu with values from the object. < ...

How can we incorporate "req.getParameter" within a "for loop" to store data in the database based on the user-defined quantity provided in another servlet?

Currently, I am working on a system where teachers have the ability to edit exams they have created. However, an issue arises when trying to save the questions and answers, as it depends on the number of questions in the exam. While requesting variables f ...

I'm having trouble receiving a response after uploading an image on Cloudinary using React js

Once the image is uploaded using the API, it should return a response. However, I am not receiving any response through the API even after uploading the image. if (pic.type === "image/jpeg" || pic.type === "image/png") { const da ...

Scaling images using jQuery for enhanced visual appeal

I implemented a jQuery hover effect on my image gallery where the images have a default size of 265 x 172 and are displayed horizontally. My goal is to have the images swap out for larger ones sized at 449 x 223 when a user hovers over them. However, I wan ...

Encountering difficulty invoking a component method from d3's call() function

My current setup involves using D3 to drag and drop links in the following manner: .call(d3.drag() .on("start", linkDragStart) .on("drag", linkDragging) .on("end", linkDragEnd)); Recently, I decided to extract this functionality into a separate met ...

How can we initiate an AJAX request in React when a button is clicked?

I'm fairly new to React and I'm experimenting with making an AJAX call triggered by a specific button click. This is how I am currently using the XMLHttpRequest method: getAssessment() { const data = this.data //some request data here co ...

Modifying the href attribute of links within various occurrences of an element using jQuery based on its content

Here is an illustration of a recurring element on a webpage <td class=" market all"> <a href="linktosomesite?param=123" target="_blank">123</a> </td> Similar elements change the parameter, resulting in links like: <td clas ...

Stripping out only the position attribute using jQuery

I have implemented a code with the following characteristics: The navigation items' texts are hidden behind certain Divs, which I refer to as Navigation Divs. When the mouse hovers over these pixels (navigation Divs), the text that is behind the ...

What is the proper way to utilize useRef with HTMLInputElements?

Dealing with React and hooks: In my code, there is a MainComponent that has its own operations and content which refreshes whenever the value of props.someData changes. Additionally, I have designed a customized InputFieldComponent. This component generat ...

Ensure that the token remains current with each axios operation

I need to access an Express REST API that demands a valid json web token for certain routes. In order to include the token from localstorage every time I needed, I had to create an "Axios config file". My http.js file includes the code below: import Vue ...

Allow the json array to be transformed into a format suitable for input

Hey there, I've received a JSON array as the response of my ajax request: {"chart":{"2016-03-08":"1","2016-03-07":"4","2016-03-06":0,"2016-03-05" :0,"2016-03-04":0,"2016-03-03":"145","2016-03-02":0}} Now, I'm looking to create a chart using the ...

JavaScript to enable button functionality for selected items

Currently, I am developing a To-Do List application. Once users input information, it gets displayed in a table format. My objective is to have the ability to select specific items from this table and apply various button functionalities to them such as ma ...

Tips for arranging cards in columns without causing vertical scrolling to be triggered

I am working with Bootstrap 5 and have created a column with multiple cards: https://jsfiddle.net/fzxc1v69/ Currently, all the cards are displayed one below the other, but I want them to be lined up horizontally instead. In my code, the .section class i ...

What is the best way to update a value and trigger a re-render in ReactJS?

this.state={ value: 'v1', newValue: '', } componentDidMount = () => { let nV = this.state.value + 'received'; this.setState({ newValue: nV, }); } tabClick = (val) => { this.setState({ value: val, ...

In HTML 5, you can use either #Header or the <header> tag

I'm feeling a bit puzzled about html right now, so I have a question regarding the use of semantic elements: Should I structure my code like this? <html> <head> <title>Some page</title> </head> <body> < ...

Is there a quick way to apply the !important rule to all properties in a CSS file?

Seeking a quick one-line shortcut to add !important to every CSS property in my extensive CSS file. Any suggestions on making the whole .css file !important? ...