简体   繁体   中英

KnockoutJS CSS binding with a dropdown value

Fiddle here: http://jsfiddle.net/0gmbbv5w/

I've got an object that I pull from the database and bind to a <select>

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

These will be populated in my viewmodel like so

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

The NoticeTypeId is being stored in the database, and the NoticeLevel is a CSS class that is bound to an element. 'FriendlyName` is what shows as the option text.

When adding a new notice, when selecting the type, the NoticeLevel should change the CSS class when the dropdown 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 only way I can figure out to bind the CSS class when selecting it, is to remove the optionsValue binding. My problem comes from when selecting an item to edit , the binding doesn't work properly, so the NoticeType when editing always shows as the "basic" notice type because it can't map the data back.

Is there some way I can accomplish this? Or am I missing something obvious here? When adding a new one, or selecting one to edit and changing the select value, it will update the CSS class properly. When initially selecting one to edit, it does not properly bind the CSS class.

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()) != "";
    });

}

The noticeType used as the value of the options binding needs to be one of the objects in the noticeTypes array. Right now you're telling the <select> to have the selected item be something not in its list. This is causing the <select> to default to the first value in the list, the "basic" option.

One solution would be find the object in the noticeTypes array that "equals" the existing noticeType and use that as the value .

Your noticeType objects in test data are not the same objects as in your noticeTypes observable array (instead they are different objects with the same data).

You will need to grab exact objects from 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';
});

And then you can initialise your test data like this:

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

See updated fiddle :

Obviously with proper data coming from the server this should be much simpler:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM