Reputation: 43
So basically I have this input text box:
<input id="usersInputField" data-bind="hasFocus: isSearchInputFocused"/>
There is a table which pops whenever the input field has focus:
<div data-bind="visible: isSearchInputFocused">
<table>
<tbody data-bind="foreach: usersFromSearch">
<!-- some info -->
</tbody>
</table>
</div>
...which works great. Although, I want the table to stay visible in case the user clicks on the div also.
Instead of the isSearchInputFocused
observable in the table binding, I tried to use a ko.computed
observable which returned true if the text box or the user table was focused and added a hasFocus
binding on it, but that doesn't seem to work. I assume the hasFocus
binding has priority over the click
binding.
How can I keep the div open while either the table or the input have focus?
Upvotes: 2
Views: 593
Reputation: 39014
A table isn't focusable by default, so that your first idea will not work. However, if you add a tabindex
attribute, you can safely set the focus on the table. Thus, if you do so, you can use a focus observable for each element, and a computed which determines if either of them is focused to keep the div visible.
var vm = {
inputHasFocus: ko.observable(),
tableHasFocus: ko.observable(),
};
// Don't take completing a model like this as a good practice:
vm.somethingHasFocus = ko.pureComputed(function() {
var inputHasFocus = vm.inputHasFocus(); // ensures subscription
var tableHasFocus = vm.tableHasFocus(); // ensures subscription
return inputHasFocus || tableHasFocus;
}, vm);
ko.applyBindings(vm);
// IE Hack
$('table *').on('click', function() { vm.tablehasFocus(true); })
table {
border: solid 1px black;
border-collapse: true;
width: 80%;
margin: 20px 0;
}
*:focus {
border-color: #FF0000;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(255, 0, 0, 0.6);
outline: none;
}
div {
background-color: silver;
margin: 20px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input tabindex="0" type="text" data-bind="hasFocus: inputHasFocus"/>
<table tabindex="1" data-bind="hasFocus: tableHasFocus">
<tr>
<td>I'm a table cell</td>
<td>I'm another</td>
<tr>
</table>
<div data-bind='visible: inputHasFocus'>Input has focus</div>
<div data-bind='visible: tableHasFocus'>Table has focus</div>
<div data-bind='visible: somethingHasFocus'>Something has focus</div>
NOTE: as usual IE has a strange behavior: at least IE10 allows to focus on a table cell. The solution included in the script it's a hack. There are smarter options:
elementOrDescendantHasFocus
, which should not be too difficult: you can use delegated event handling to detect the focus events in the table or childrentabindex
attribute to themSo, if you have to support IE (at least IE10), choose any of these solutions, including the hack. In Chrome and Firefox there is no such problem
Upvotes: 2
Reputation: 8548
Maybe you can solver this question using focus event, like fallowing example:
http://jsbin.com/jewozilofe/edit?html,js,output
Upvotes: 1
Reputation: 8206
idk if you want to do it this way, but you can make it so the table opens on focus of the input and stays open until you close it.
// Here's my data model
var ViewModel = function() {
var self = this;
self.focusMePlease = ko.observable(false);
self.focusMePlease.subscribe(function() {
if (self.focusMePlease() == true) {
self.isSearchInputFocused(true);
}
});
self.isSearchInputFocused = ko.observable(false);
self.close = function() {
self.isSearchInputFocused(false);
};
};
ko.applyBindings(new ViewModel());
td {
border: 1px solid black;
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script><input id="usersInputField" data-bind="hasFocus: focusMePlease"/>
<br/><br/>
<div data-bind="visible: isSearchInputFocused">
<table>
<tr><td>stuff</td><td>stuff</td></tr>
</table>
<button data-bind="click: close">X</button>
</div>
Upvotes: 1