How add custom binding to DropDownList - kendo-ui

I have binding enterPress
// Custom keypress on ENTER event binding for input elements.
kendo.data.binders.enterPress = kendo.data.Binder.extend({
init: function (element, bindings, options) {
kendo.data.Binder.fn.init.call(this, element, bindings, options);
var binding = this.bindings.enterPress;
$(element).bind("keypress", function (e) {
if (e.which == 13) {
binding.get();
}
});
},
refresh: function () { }
});
If I use it to DropDownList I have error:
Uncaught Error: The enterPress binding is not supported by the
DropDownList widget
How to make enterpress for DropDownList ?

Check my reply to your other question:
The kendo.data.binders.widget namespace should be used when creating
widget bindings. Widgets are created for elements that have their role
data attribute set.

You can capture the keydown event of all DropDownList controls using the following code:
kendo.ui.ComboBox.fn._keydown = function(e) {
if (e.which == 13) {
alert("key pressed!");
}
};

Related

Populate a Kendo dialog with partial view

I have a kendo dialog which I want to populate with a partial view but it's sort of not working.
I want to populate the dialog with the click of a button, so here's my code so far
<div id="dialog"></div>
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var dialog = $("#dialog");
console.log("objId", dataItem.OBJECTID1)
$.ajax({
url: '#Url.Action("SavePartial", "SettlementContract")',
data: {
id: dataItem.OBJECTID1
},
success: function (result) {
if (result != null) {
dialog.html(result);
dialog.data("kendoDialog").open();
}
}
});
}
I tried removing the if condition inside the success, just in case but it's not working either. It returns the partial view, but not inside the kendo dialog, the dialog doesn't even open. What am I doing wrong?
We do this in our application and this is how we have set it up (I updated it to use your controller/actions/ids) - this is using the ASP.NET Core MVC wrappers:
#(Html.Kendo().Window()
.Name("dialog")
.Content("loading...")
.Draggable()
.Actions(actions => actions.Maximize().Close())
.Resizable()
.Modal(true)
.Visible(false)
.Events(e => e.Refresh("onDialogWindowRefresh"))
)
<script>
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
let win = $("#dialog").data("kendoWindow");
win.refresh({
url: "/SettlementContract/SavePartial/",
data: {
id: dataItem.OBJECTID1
}
});
}
function onDialogWindowRefresh(e) {
e.sender.center().open();
}
</script>

MVVM-KendoNumericTextBox restore previous value without triggering 'change' twice

I'm using Kendo MVVM and I have a kendo numerictextbox bound to a kendo observable.
All I want is: when the user changes value, a confirm should pop saying something like 'are you sure?' if yes -> no problem, go on.
if no -> NOTHING should happen!
In theory it sounds simple as that... but I found 3 major issues:
1) numerictextbox only got 2 events: spin and change... so any idea of using keypress/focus/or any other event is discarded.
2) So tried using the change event... but I can't preventDefault! Another try was to save previous value and restore it back in case of 'no answer' but this brings me to trigger event change TWICE!
3) Any other model field who is 'observing' the numerictextbox will change before I even answer the confirm box... And I absolutely don't want this!
P.S. I also got a dropdownlist and a datepicker that must work in the same way!
Help please!
Provided a fast example: http://dojo.telerik.com/EyItE
Here you can see how the numericbox2 (who is observing numericbox1 and is computed) changes itself before the user answer yes/no (problem 3)
and keypress/focus/preventDefault doesn't work.
here is an answer about binding events not supported by default:
Kendo MVVM and binding or extending custom events
For preventDefault (or "reverting" the value). I tried to store the previous value as you suggested and it is does not fire twice:
var viewModel = kendo.observable({
myItem: {
// fields, etc
myNumericBox: 10,
myNumericBox2: function () {
return viewModel.get("myItem.myNumericBox")*2;
},
tmp: 10
},
onChange: function (e) {
if ( confirm("are you sure?")) {
viewModel.set("myItem.tmp", viewModel.get("myItem.myNumericBox"));
}
else {
viewModel.set("myItem.myNumericBox", viewModel.get("myItem.tmp"));
}
},
tryf: function () {
alert("hello!"); // doesn't trigger
},
tryk: function() {
alert("hello2!"); // doesn't trigger
}
});
I solved with a custom binding that ask you a confirm between html widget change -> model update.
kendo.data.binders.widget.valueConfirm = kendo.data.Binder.extend({
init: function (widget, bindings, options) { // start
kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
this.widget = widget;
this._change = $.proxy(this.change, this);
this.widget.bind("change", this._change); // observe
},
refresh: function () { // when model change
if (!this._initChange) {
var widget = this.widget;
var value = this.bindings.valueConfirm.get(); // value of the model
if (widget.ns == ".kendoDropDownList") { // for the dropdown i have to use select
widget.select(function (d) {
return d.id == value.id;
});
}
else widget.value(value); // update widget
}
},
change: function () { // when html item change
var widget = this.widget;
if (widget.ns == ".kendoDropDownList") var value = widget.dataItem(); // for dropdown i need dataitem
else var value = widget.value();
var old = this.bindings.valueConfirm.get();
this._initChange = true;
// I want to bypass the confirm if the value is not valid (for example after 1st load with blank values).
if (old == null || old == 'undefined' || old == 'NaN') this.bindings.valueConfirm.set(value); // Update the View-Model
else {
if (confirm("Are you sure?")) {
this.bindings.valueConfirm.set(value); // Update the View-Model
}
else {
this._initChange = false;
this.refresh(); // Reset old value
}
}
this._initChange = false;
},
destroy: function () { // dunno if this is useful
this.widget.unbind("change", this._change);
}
});

Durandal dialog Call back Function

In my view model I have a grid, if user click on Edit button on the row it will popup a dialog with row values, if user click on Edit button will close the dialog then I need to reload the grid. My model look like below, I my case
I am not able to call load function after dialog call back (** getting Error - self is undefined**). it is possible to pass this to dialog?
var ctor = function () {
var self = this;
self.load = function () {
Load grid Functions
}
self.editRow = function (row) {
dialog.show(new editWindow(), row).then(function (response) {
if (response == null) {
return;
}
self.load();
});
}
Return ctor;
got answer by adding self with call back
var ctor = function () {
var self = this;
self.load = function () {
Load grid Functions
}
self.editRow = function (row) {
dialog.show(new editWindow(), row).then(function (response) {
if (response == null) {
return;
}
self.load();
},self);
}
Return ctor;

Kendo Custom Widget Filter

I am trying to build a custom widget that I can use as a custom filter in the Kendo grid. What I would like to do is have multiple input boxes that get concatenated back into a single string. The control below replaces the current inputbox but I am having trouble binding the value from my custom widget back to the filter. Is there something I am missing?
(function () {
var ui = window.kendo.ui,
Widget = ui.Widget;
var CustomFilter = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
var e = $(element);
e.wrap("<span></span>");
e.parent().append('<input type="text" style="width:3em;" />');
e.parent().append('<input type="text" style="width:3em;" />');
e.parent().on('keyup', 'input', function () {
//Set Value?
});
e.hide();
},
options: {
name: "CustomFilter"
}
});
ui.plugin(CustomFilter);
}());
var columns = [{ 'field': 'FieldName', title: 'FieldName', filterable: { ui: "customfilter" } } ];

Bootstrap typeahead suggestions replaced when navigation

I'm using Bootstrap Typeahead to suggest som search results. The results are returned from a ajax ressource, and since this resource creates a delay, I'm experiencing a unfortunate effect.
Example:
If typing a 4 letter word, the suggestions will appear after 2 letters, I can then go through the results with the keys up/down, but suddenly the suggestions will reload because the last request has finished.
Is there any way to "cancel" any remaining, if user is currently using the keys up/down to go through the suggestions?
('#query').typeahead({
items: 4,
source: function (query,process) {
map = {};
$.getJSON('/app_dev.php/ajax/autosuggest/'+query, function (data) {
vehicles = [];
$.each(data, function(i,vehicle){
map[vehicle.full] = vehicle;
vehicles.push(vehicle.full);
});
process(vehicles);
});
},
updater: function (item) {
// do something here when item is selected
},
highlighter: function (item) {
return item;
},
matcher: function (item) {
return true;
}
});
I think the following will satisfy your needs (its hard to reproduce exactly) :
There is no easy way to abort a delayed response, but you could extend typeahead as I figured out here (without modifying bootstrap.js)
The concept is to catch keydown, detect if the event is KEY_UP or KEY_DOWN, set a flag is_browsing, and then abort process if is_browsing is true (that is, if the user has hitted KEY_UP or KEY_DOWN and no other keys afterwards).
Extending typeahead :
// save the original function object
var _superTypeahead = $.fn.typeahead;
// add is_browsing as a new flag
$.extend( _superTypeahead.defaults, {
is_browsing: false
});
// create a new constructor
var Typeahead = function(element, options) {
_superTypeahead.Constructor.apply( this, arguments )
}
// extend prototype and add a _super function
Typeahead.prototype = $.extend({}, _superTypeahead.Constructor.prototype, {
constructor: Typeahead
, _super: function() {
var args = $.makeArray(arguments)
// call bootstrap core
_superTypeahead.Constructor.prototype[args.shift()].apply(this, args)
}
//override typeahead original keydown
, keydown: function (e) {
this._super('keydown', e)
this.options.is_browsing = ($.inArray(e.keyCode, [40,38])>-1)
}
//override process, abort if user is browsing
, process: function (items) {
if (this.options.is_browsing) return
this._super('process', items)
}
});
// override the old initialization with the new constructor
$.fn.typeahead = $.extend(function(option) {
var args = $.makeArray(arguments),
option = args.shift()
// this is executed everytime element.modal() is called
return this.each(function() {
var $this = $(this)
var data = $this.data('typeahead'),
options = $.extend({}, _superTypeahead.defaults, $this.data(), typeof option == 'object' && option)
if (!data) {
$this.data('typeahead', (data = new Typeahead(this, options)))
}
if (typeof option == 'string') {
data[option].apply( data, args )
}
});
}, $.fn.typeahead);
This typeahead-extension could be placed anywhere, eg in a <script type="text/javascript"> -section
Testing the extension :
<input type="text" id="test" name="test" placeholder="type some text" data-provide="typeahead">
<script type="text/javascript">
$(document).ready(function() {
var url='typeahead.php';
$("#test").typeahead({
items : 10,
source: function (query, process) {
return $.get(url, { query: query }, function (data) {
return process(data.options);
});
}
});
});
</script>
A "serverside" PHP script that returns a lot of randomized options with forced delay, typeahead.php :
<?
header('Content-type: application/json');
$JSON='';
sleep(3); //delay execution in 3 secs
for ($count=0;$count<30000;$count++) {
if ($JSON!='') $JSON.=',';
//create random strings
$s=str_shuffle("abcdefghijklmnopq");
$JSON.='"'.$s.'"';
}
$JSON='{ "options": ['.$JSON.'] }';
echo $JSON;
?>
It really seems to work for me. But I cannot be sure that it will work in your case. Let me now if you have success or not.

Resources