Use Enter as Tab with knockout binding and KendoUI dropdown - javascript

I have a page that uses KendoUI controls with knockout binding, and I need to use Enter instead of Tab to navigate through controls.
I managed to make it work great by using the solution posted here by Damien Sawyer and enhancing it with Shift-Enter as suggested by Andre Van Zuydam
ko.bindingHandlers.nextFieldOnEnter = {
init: function (element, valueAccessor, allBindingsAccessor) {
j$(element).on('keydown', 'input, select', function (e) {
var self = j$(this)
, form = j$(element)
, focusable
, next
;
var tabElements = 'input,a,select,button,textarea';
if (e.shiftKey) {
if (e.keyCode === 13) {
focusable = form.find(tabElements).filter(':visible');
prev = focusable.eq(focusable.index(this) - 1);
if (prev.length) {
prev.focus();
} else {
form.submit();
}
}
}
else
if (e.keyCode === 13) {
focusable = form.find(tabElements).filter(':visible');
var nextIndex = focusable.index(this) === focusable.length - 1 ? 0 : focusable.index(this) + 1;
next = focusable.eq(nextIndex);
next.focus();
return false;
}
});
} };
(my code uses j$ instead of $ for jquery because the project uses also mootools and I redefined jquery as j$)
However, I have a problem with kendoUI DropDown lists. The problem it is not or element, so it does not get focus (instead it is a span with special classes and unselecteable="on" attribute).
How should I update the ko binding code to set focus to dropdown on Enter? It works with Tab
Thanks

Doing the best I can without having a Kendo sample I can test this out on, but I think you should be able to achieve this. When Kendo creates a dropdown, as you said it adds a bunch of other elements and isn't given focus the same way as a regular select element. You can find a kendo select, however, by first finding its parent span with the class of k-dropdown.
Try adding k-dropdown to tabElements as a class selector:
var tabElements = 'input,a,select,button,textarea,.k-dropdown';
Then, adjust the part where you give focus by adding a condition to check for Kendo dropdown. So instead of just this:
prev.focus();
Try something like this:
if (prev.hasClass('k-dropdown')) {
prev.children('select').first().data("kendoDropDownList").focus();
} else {
prev.focus();
}

Related

Kendo toolbar button not firing click event after being enabled

This is my logic, here I am trying to disable the save changes button and prevent click event on it if the user enters a duplicate value and enable it again if the user changes the values but after enabling it the update / save event does not occur am I doing something wrong? This is my code
function OnChange(data) {
//data.preventDefault();
$(".k-grid-save-changes")
.attr("role", "button")
.removeClass("k-state-disabled")
//.addClass("k-grid-save-changes")
.click(function () {
return true;
});
//console.log("data", data.items["0"].ProviderTypeName);
var name = data.items["0"].ProviderTypeName;
var Id = data.items["0"].Id;
var grid = $("#grid").data("kendoGrid");
//console.log("Grid ", grid);
grid.tbody.find('>tr').each(
function () {
$(this).css('background', 'white');
var dataItem = grid.dataItem(this);
//console.log(dataItem.ProviderTypeName)
if (dataItem.ProviderTypeName == name && dataItem.Id != Id) {
$(this).css('background', 'red');
$(".k-grid-save-changes")
//.removeClass("k-grid-save-changes")
.addClass("k-state-disabled")
//.removeAttr("role")
.click(function () {
return false;
});
}
});
}
This is where is call the on change event
.Events(events => events.RequestStart("OnRequestStart").Change("OnChange").RequestEnd("OnRequestEnd").Error("onError"))
If I remove the "return false;" it is working as expected but this allows duplicated values to be saved. So I have used this.
If I understand correctly in your code you do exactly what you mention as a problem. At every change you disable the save functionality with the return false. You don't enable it again at any point.
If you add an event handler to the button then you have to undo it at a later point. Since though I don't believe that the validation should occur at the change event but at the button click I would suggest to use the grid Save event where you could iterate dataSource.data() of your grid (much better) do your check and if anything happens return false.
One other way to go since you probably want the css effect with the background is to keep your code and discard the click event. Just set a flag that you could use in the save event. Something like this:
if(// your control){
$(this).css('background', 'red');
duplicatedValue = true;
}else{
.removeClass("k-grid-save-changes");
duplicatedValue = false;
}
And in the save event
function onSave(){
if(duplicatedValue){
return false;
}
}

Need to detect whether jQuery is triggered in normal or multiselect combobox

I have some jQuery code that allows me to select multiple entries in a multiselect combobox without the need to press the Ctrl key.
This works, but interferes with a normal select box, which can now not be changed with the mouse.
The original jQuery code is:
(function ($) {
$(document).ready(function () {
$("option").mousedown(function(e) {
this.selected = ! this.selected;
e.preventDefault();
return false;
});
});
})(jQuery);
Of course, the $("option") selector applies to the normal select box as well, which is why it fails.
I tried to detect whether the event is triggered by a select box with the "multiple" attribute, but couldn't figure out how. The following doesn't work for various reasons, one of them being that the event is triggered by the option, not the select:
(function ($) {
$(document).ready(function () {
$("option").mousedown(function(e) {
if($(this).attr('multiple','multiple')) {
this.selected = ! this.selected;
e.preventDefault();
return false;
}
else {
return true;
}
});
});
})(jQuery);
Any ideas of how this could be done?
Ah, I don't want to include the ID of the multiselect, because the same code is also used by another multiselect in my real-world case.
Here is a fiddle:
https://jsfiddle.net/mheumann/3zn76mex/
Give all the multiselect elements to which you want to apply this behavior a new CSS class -- perhaps custom-multiselect.
Then you can use a compound selector like .custom-multiselect option in the code you have...
(function ($) {
$(document).ready(function () {
$(".custom-multiselect option").mousedown(function(e) {
this.selected = ! this.selected;
e.preventDefault();
return false;
});
});
})(jQuery);
You can target the options of every multi-select using this selector: $('select[multiple] option').
This selector targets every <option> that occurs within a <select> with the multiple attribute present.

Prevent bootstrap function from toggling dropdown

I converted a bootstrap navbar into a toolbar and modified a dropdown (dropup actually) to contain 2 datepicker elements:
The problem is that when I select a date, the dropdown collapses. My solution (I'm open to others) is to create a function that opens the dropdown by adding class 'open' and adding that function into the datepicker close() function.
function leaveOpen(){
$("#dropdownMenu2").trigger('focus').attr('aria-expanded', 'true');
$("#rangeDropdown").addClass('open');
}(jQuery);
This function works properly, but there is another bootstrap function that toggles the 'open' class right back off:
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
...
var relatedTarget = { relatedTarget: this }
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
...
$this
.trigger('focus')
.attr('aria-expanded', 'true')
$parent
.toggleClass('open')
.trigger('shown.bs.dropdown', relatedTarget)
}
I'm a bit overwhelmed by this JavaScript. What can I add to leaveOpen() to prevent the 'open' class from toggling within 'Dropdown.prototype.toggle = function (e)'?
Check it out: https://jsfiddle.net/hoffmanc/y6sho3nv/9/
There are two prevention mechanisms required AFAIK:
1) Stop the dropdown from being hidden upon clicking the datepicker text field:
$('.datepicker').on('click', function (e) {
e.stopPropagation();
});
ref: https://stackoverflow.com/a/8178945/338303
2) Stop the dropdown from being hidden upon clicking a date in the calendar itself:
$('.dropdown').on('hide.bs.dropdown', function (e) {
if($('.datepicker-dropdown').length > 0) {
return false;
}
});
ref: https://stackoverflow.com/a/19797577/338303

Call back from styled radio buttons

I am using the jQuery plugin radiosToSlider (http://rubentd.com/radios-to-slider/) and need to make sure that all radio button groups are checked and to give an alert when they are
I can do this if they are just radio buttons by checking the length but because the plugin changes the input buttons I am having difficulties
My fiddle is
http://jsfiddle.net/yFaAj/270/
$(document).ready(function () {
$(".radios").radiosToSlider();
});
$(":radio").change(function () {
var names = {};
$(':radio').each(function () {
names[$(this).attr('name')] = true;
});
var count = 0;
$.each(names, function () {
count++;
});
if ($(':radio:checked').length === count) {
alert("all answered");
}
}).change();
thanks
The problem isn't that the plugin changes your structure (although it does add some ins elements, which I don't agree with), it's that the plugin doesn't fire a change event for the converted radio controls, and setting the checked property interactively doesn't appear to do so either.
Since the plugin author doesn't publish an API for this use case, it's hard to know whether this is by design or oversight, but the source code definitely doesn't fire the event when the slider is clicked:
this.bearer.find('.slider-level').click( function(){
var radioId = $(this).attr('data-radio');
slider.bearer.find('#' + radioId).prop('checked', true);
slider.setSlider();
});
Your options, as I see them:
Contact the API author and ask for a bug fix, or the intended way to support this case
Downside: Time: dependent on the author to respond
Attach your "check" function to the click event of the .slider-level class, as the API does.
Downside: Brittle: future versions of the plugin may attach the behavior to different selectors
Attach your function to the click event of your radio group, and catch click events on the bubble
Downside: Inefficient: It will check for every click in the radio control
Here's a sample implementation of option 3. DEMO.
$(document).ready(function () {
$(".radios").radiosToSlider();
});
var makeIsRadioGroupChecked = function(selector) {
var $radioGroup = $(selector);
return function isRadioGroupChecked() {
return $radioGroup.find(':checked').length > 0;
};
};
var isOptionsChecked = makeIsRadioGroupChecked('#optionsRadioGroup');
var isSizeChecked = makeIsRadioGroupChecked('#sizeRadioGroup');
var areAllGroupsChecked = function() {
return isOptionsChecked() && isSizeChecked();
};
var alertIfAllGroupsChecked = function() {
if (areAllGroupsChecked()) {
alert("all answered");
}
};
$('.radios').on('click', alertIfAllGroupsChecked);

X-Editable: stop propagation on "click to edit"

I have an editable element inside a div which itself is clickable. Whenever I click the x-editable anchor element, the click bubbles up the DOM and triggers a click on the parent div. How can I prevent that? I know it's possible to stop this with jQuery's stopPropagation() but where would I call this method?
Here's the JSFiddle with the problem: http://jsfiddle.net/4RZvV/ . To replicate click on the editable values and you'll see that the containing div will catch a click event. This also happens when I click anywhere on the x-editable popup and I'd like to prevent that as well.
EDIT after lightswitch05 answer
I have multiple dynamic DIVs which should be selectable so I couldn't use a global variable. I added an attribute to the .editable-click anchors which get's changed instead.
editable-active is used to know if the popup is open or not
editable-activateable is used instead to know if that .editable-click anchor should be treated like it is
$(document).on('shown', "a.editable-click[editable-activateable]", function(e, reason) {
return $(this).attr("editable-active", true);
});
$(document).on('hidden', "a.editable-click[editable-activateable]", function(e, reason) {
return $(this).removeAttr("editable-active");
});
The check is pretty much like you've described it
$(document).on("click", ".version", function() {
$this = $(this)
// Check that the xeditable popup is not open
if($this.find("a[editable-active]").length === 0) { // means that editable popup is not open so we can do the stuff
// ... do stuff ...
}
})
For the click on the links, simply catch the click event and stop it:
$("a.editable-click").click(function(e){
e.stopPropagation();
});
The clicks within X-editable are a bit trickier. One way is to save a flag on weather the X-editable window is open or not, and only take action if X-editable is closed
var editableActive = false;
$("a.editable-click").on('shown', function(e, reason) {
editableActive = true;
});
$("a.editable-click").on('hidden', function(e, reason) {
editableActive = false;
});
$("div.version").click(function(e) {
var $this;
$this = $(this);
if(editableActive === false){
if ($this.hasClass("selected")) {
$(this).removeClass("selected");
} else {
$(this).addClass("selected");
}
}
});
Fixed Fiddle
It's not pretty, but we solved this problem with something like:
$('.some-class').click(function(event) {
if(event.target.tagName === "A" || event.target.tagName === "INPUT" || event.target.tagName === "BUTTON"){
return;
}
We're still looking for a solution that doesn't require a specific list of tagNames that are okay to click on.

Categories

Resources