Utilizing KnockoutJS to Apply CSS Binding Based on Dropdown Selection

Check out the live example here: http://jsfiddle.net/0gmbbv5w/

In my application, I have an object retrieved from the database that I bind to a <select>

var NoticeType = function (noticeType) {
    this.NoticeTypeId = ko.observable(noticeType.NoticeTypeId);
    this.NoticeLevel = ko.observable(noticeType.NoticeLevel);
    this.FriendlyName = noticeType.FriendlyNoticeLevel;
}

In the viewmodel, this object will be populated like this

NoticeType: new NoticeType({
    NoticeTypeId: 2,
    NoticeLevel: 'info',
    FriendlyNoticeLevel: 'Informational'
})

The NoticeTypeId is stored in the database, the NoticeLevel is a CSS class bound to an element. 'FriendlyName' is displayed as the option text.

When adding a new notice, the NoticeLevel should change the CSS class as the dropdown selection changes.

<select data-bind="options: $parent.noticeTypes, optionsText: 'FriendlyName', value: noticeType"></select>


<div class="row-fluid">
    <div class="span12">
        <div class="alert" data-bind="css: alertLevel">
            <h4>Just a reminder!</h4>
            <span>This is a sample of what your notice will look like. The header is the Subject, and this text is the Message</span>
        </div>
    </div>
</div>

The issue I'm facing is with binding the CSS class when editing an existing notice. I have to remove the optionsValue binding to make it work properly. When editing, the binding doesn't map back the data correctly, always showing the "basic" notice type.

Is there a way to resolve this issue? Am I overlooking something? Adding or editing a notice updates the CSS class correctly, but when initially editing a notice, the CSS class binding fails.

self.editNotice = function (item) {
    self.noticeToAdd(new NoticeToAdd(ko.toJS(item)));
}

var NoticeToAdd = function (notice) {

    var self = this;

    if (!notice) {
        notice = {};
    }

    this.noticeId = ko.observable(notice.NoticeId || notice.noticeId);
    this.subject = ko.observable(notice.Subject || notice.subject);
    this.body = ko.observable(notice.Body || notice.body);
    this.publishDate = ko.observable(notice.PublishDate || notice.publishDate);
    this.expireDate = ko.observable(notice.ExpireDate || notice.expireDate);
    this.sticky = ko.observable(notice.Sticky || notice.sticky);
    this.includeDismiss = ko.observable(notice.IncludeDismissAction || notice.includeDismiss || true);
    this.noticeType = ko.observable(notice.NoticeType || notice.noticeType);
    this.showDismissal = ko.observable(false);

    //CSS binding
    this.alertLevel = ko.pureComputed(function() { 
        return self.noticeType() ? 'alert-' + self.noticeType().NoticeLevel() : 'alert-basic';
    });

    this.ableToAddNotice = ko.pureComputed(function () {
        return $.trim(self.body()) != "";
    });

}

Answer №1

In your test data, the noticeType objects are not the same as the objects in your noticeTypes observable array. They are different objects with the same data.

To ensure consistency, you should select the exact objects from the noticeTypes array:

//Test data!
var successType = ko.utils.arrayFirst(self.noticeTypes(), function (type) {
    return type.NoticeLevel() === 'success';
});
var warningType = ko.utils.arrayFirst(self.noticeTypes(), function (type) {
    return type.NoticeLevel() === 'warning';
});
var infoType = ko.utils.arrayFirst(self.noticeTypes(), function (type) {
    return type.NoticeLevel() === 'info';
});
var dangerType = ko.utils.arrayFirst(self.noticeTypes(), function (type) {
    return type.NoticeLevel() === 'danger';
});

Then, you can initialize your test data like this:

self.notices.push(new NoticeToAdd({
    NoticeId: 1,
    Subject: 'Notice this!',
    Body: '<strong>YO!</strong> this is a super cool notice man',
    NoticeType: successType
}));
self.notices.push(new NoticeToAdd({
    NoticeId: 2,
    Subject: 'Notice this!',
    Body: '<strong>YO!</strong> this is a super cool notice man',
    NoticeType: warningType
}));
self.notices.push(new NoticeToAdd({
    NoticeId: 3,
    Subject: 'Notice this!',
    Body: '<strong>YO!</strong> this is a super cool notice man',
    NoticeType: infoType
}));
self.notices.push(new NoticeToAdd({
    NoticeId: 4,
    Subject: 'Notice this!',
    Body: '<strong>YO!</strong> this is a super cool notice man',
    NoticeType: dangerType
}));
self.notices.push(new NoticeToAdd({
    NoticeId: 5,
    Subject: 'Notice this!',
    Body: '<strong>YO!</strong> this is a super cool notice man'
}));

View the updated fiddle:

When receiving proper data from the server, the process should be simplified:

var someType = ko.utils.arrayFirst(self.noticeTypes(), function (type) {
    return type.NoticeTypeId() === NoticeTypeIdFromTheServer;
});

Answer №2

Ensure that the noticeType selected for the options binding is part of the noticeTypes array. If the selected item is not found in the array, the <select> will default to the first option, "basic."

To fix this issue, locate the object in the noticeTypes array that matches the current noticeType and set that as the value.

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

The Facebook JavaScript API function FB.api() is limited to posting messages and does not support media attachments

I am attempting to share a message with an mp3 attachment on the active user's wall. It works perfectly fine within Facebook's Test Console, but when I try it from my mobile app, only the message gets posted. Can anyone help me figure out what I ...

jQuery and HTML: Need help enabling an <input> or <select> element?

Currently, I am using Mozilla Firefox 14.0.1 and Google Chrome 20.0.1132.57 (which I believe is the latest version). The code I am working with looks like this: http://jsfiddle.net/SVtDj/ Here is what I am trying to accomplish: Type something into inpu ...

How can I send a file and a string request using the POST method to a Spring REST controller that accepts byte[] and Strings with Angular

Need help with sending a post method that includes a file and another string request parameter to a spring rest controller using angular. The server controller parameter is set up to receive an array of bytes for the file and another string request wrappe ...

Tips for eliminating any default white space visible between tags:

What is the best way to eliminate white space gaps between div tags and adjust pixel differences between them in HTML code? My current alignment is off and there are noticeable white spaces between div tags. I have tried using a reset link but it didn&apo ...

Trouble with innerHTML in a for loop when using getJSON

My current challenge involves displaying a series of JSON results within a div tag using innerHTML. <script> $(document).ready(function() { var html2 = ''; var thread_id = ''; var created_thread_ids ...

Encountering a JavaScript Error: "e is null" while utilizing assert for checking JavaScript alert text

I encountered a javascript alert in my program that I was able to interact with by reading the text and clicking on the buttons. However, when I tried to verify the alert text using assertequals function, I faced an error. Here is the code snippet: String ...

Creating a dynamic link in Vue JS is a cinch!

I currently have the following code snippet: <b-dropdown text="Select Factory" block variant="primary" class="m-2" menu-class="w-100"> <b-dropdown-item @click="selectedFactory='China'"> ...

Setting the default selected option in Vue for an object

Can the v-model data be different from the default option in this scenario? data: function() { return { user: { usertype: {}, } } <select v-model="user.usertype" class="btn btn-secondary d-flex header-input"> <option v-for= ...

Running two servers at the same time using nodemon might seem complex, but it

Is it possible to run two servers (www.js and apiServer.js) simultaneously using nodemon? I have set the value for the "start" key in package.json as https://i.stack.imgur.com/r8M7p.jpg After running nodemon in the command prompt with the current working ...

Why does my array become empty once it exits the useEffect scope?

const [allJobs, setAllJobs] = useState([]); useEffect(() => { axios.get('http://localhost:3002/api/jobs') .then(res => setAllJobs(res.data)); allJobs.map((job, i) => { if (job.language.toLowerCas ...

Rdash Angular: How to Implement a Fixed Header Position on Page Scroll

Hi there, I am currently utilizing Rdash Angular Js. I am wondering if it's achievable to keep the header position fixed while scrolling through the page. I attempted a solution using CSS as shown below, unfortunately it didn't have the desired ...

Guide to creating a React Hooks counter that relies on the functionality of both a start and stop button

I am looking to create a counter that starts incrementing when the start button is clicked and stops when the stop button is pressed. Additionally, I want the counter to reset to 1 when it reaches a certain value, for example 10. I have tried using setInte ...

Looking for someone who has successfully upgraded React Native code from version 0.59 to the most recent version

Is there a way to make my React Native project compatible with the latest version? I am facing a challenge in updating an old React Native project running on version 0.59.10 to the most recent version. Despite trying various methods, I have been unable to ...

The code functions properly within the emulator, however, it fails to execute on an actual device

Yesterday, I posted a question about the background related to this topic: on click event inside pageinit only works after page refresh. I received an answer for my question and tested it in Chrome devtools where it worked perfectly. However, today when ...

Issue with parent-child communication in React.js causing malfunction

I am facing an issue with maintaining state between two different JavaScript files using React. The parent class, break.js, is defined as follows: export default function AlertDialog(props) { const [demoOpen, setDemoOpen] = React.useState(true); ...

Adjust the dimensions of the image carousel in Twitter Bootstrap

Here is the code that I am currently working with: <div class="col-sm-4"> <div class="card"> <div class="card-block"> <div class="col-sm-4"> <div id="carouselExampleIndi ...

JS showcase of object literals and their corresponding properties

Just starting out with Javascript and eager to learn about arrays of objects. I'm currently exploring how to display an object along with its properties. Here's an example showcasing the colors of different fruits: var fruitColor = {'apples ...

Show several fresh windows

Greetings everyone. Let me explain my current situation: I have a search page where users can select a product from a drop-down list, and upon clicking a button, a gridview is displayed showing the specifications of the selected product. What I'm a ...

Issue with VueJS rendering data within a for loop

As a newcomer to VueJS, I appreciate your patience as I navigate through this. Let me provide as much detail as possible. I am currently working on a Vue app that needs to retrieve a response from a server, iterate through the data, and set a Vue data var ...

Changing the color of a selected list element using an Angular directive

I'm currently facing an issue with my directive that is supposed to turn a list element red when clicked. It works fine, but I also want it to revert back to black when another list item is selected, so only one item stays in red color. Here is how I ...