问题
So this is piling libraries on top of libraries, but I'm not sure what else to do.
Our application has a number of drop-down elements all of which are Bootstrap Select objects. These replace the standard set of option tags inside the select with a complex series of other elements that give you much greater control over the styling of the children and make them searchable.
Most of these objects exist as reusable components with an HTML view and a Typescript ViewModel, bound together with Knockout.
A number of these menus have icons next to the text. This is handled with optionsAfterRender. Here's an example.
View:
<select
data-bind="options: items,
value: selectedValue,
optionsText: 'value',
optionsValue: 'id',
selectPicker: {},
optionsAfterRender: applyOptionAttributes">
</select>
ViewModel:
export default class SelectComponent {
selectedValue: KnockoutObservable<string>;
items: KnockoutObservableArray<SelectOption>
constructor(koObservable: KnockoutObservable<string>) {
// items fetched and bound
}
applyOptionAttributes(option: Node, item: SelectOption): void {
ko.applyBindingsToNode(option, { attr: { "data-content": `<img src="${item.iconurl}" />`, title: item.value } }, item);
}
}
interface SelectOption {
value: string;
id: string
iconurl: string;
}
And this is fine. However, because of the way Bootstrap Select styles the items inside it, the icon is not applied to the currently selected item - it's only displayed when the user clicks on the menu and it pops up.
Now, of course, we have a requirement to display the icon in currently selected item too. But I don't know how to get that element to bind to it. I can't fetch it directly because of the view-viewmodel pattern. It doesn't seem to be among the nodes passed by optionsAfterRender.
How can I get hold of it to style it?
EDIT: pretty sure this is a bug in bootstrap-select. Have raised an issue
https://github.com/snapappointments/bootstrap-select/issues/2129
回答1:
You could try to fix this by preventing the post-processing of the options:
- Replace the
options
binding with aforeach
binding in theselect
element, binding eachoption
with the appropriate ko-bindings. - Make sure the selectPicker binding has its descendant bindings bound before calling
selectpicker
on the element. - Profit!
ko.bindingHandlers['selectPicker'] = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.applyBindingsToDescendants(bindingContext, element);
$(element).selectpicker();
return { controlsDescendantBindings: true };
}
}
ko.applyBindings({
selectedValue: ko.observable(3),
options: [
{ id: 1, name: 'Mustard', dc: '<span class="badge badge-warning">Mustard</span>' },
{ id: 3, name: 'Ketchup', dc: '<span class="badge badge-danger">Ketchup</span>' },
{ id: 4, name: 'Relish', dc: '<span class="badge badge-success">Relish</span>' }
]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.3/css/bootstrap-select.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.3/js/bootstrap-select.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="selectPicker, value: selectedValue">
<!-- ko foreach: options -->
<option data-bind="text: name, attr: { value: id, 'data-content': dc }"></option>
<!-- /ko -->
</select>
来源:https://stackoverflow.com/questions/52947292/knockout-applying-styles-to-the-selected-item-in-a-bootstrap-select