Kendo Grid - row expand animation - animation

I'm using a kendo grid.
I want to add a slide-down animation - when I click on a row in the grid it expands with animation
(the expansion happens with grid.ExpandRow function - kendo inner).
I think that I need the animation on k-detail-row element.
But I still cant find the proper place/way to do that.
Anyone did that already, and can help me with that.

Unfortunately animations are not supported for table rows. Here is a related question: How to Use slideDown (or show) function on a table row?

I had the same question, and although this is an old post, I figured someone might need it.
Unfortunately Kendo does not support this functionality as yet, however there is a solution.
Kendo uses the jquery toggle() to show and hide the detail row, thus by performing a conditional override on the jQuery you can insert animation.
jQuery(function($) {
var _oldShow = $.fn.show;
var _oldHide = $.fn.hide;
$.fn.show = function(speed, oldCallback) {
return $(this).each(function(index, item) {
var obj = $(item);
_oldShow.apply(obj, [speed, oldCallback]);
if (obj.hasClass("k-detail-row")) {
obj.find(".k-grid.k-widget").each(function () {
var grid = $(this);
grid.slideDown(300);
});
}
});
}
$.fn.hide = function (speed, oldCallback) {
return $(this).each(function () {
var obj = $(this);
if (obj.hasClass("k-detail-row")) {
obj.find(".k-grid.k-widget").each(function () {
$(this).slideUp(300, function () { _oldHide.apply(obj, [speed, oldCallback]); });
});
} else {
_oldHide.apply(obj, [speed, oldCallback]);
}
});
}
});

I ran into this issue today and managed to solve it using the detailExpand function of the grid. You can then use the Kendo Fx slidedown effect to make the detail row slide down. For example:
detailExpand: function (e) {
var detailRow = e.detailRow;
setTimeout(function () {
kendo.fx(detailRow).slideIn("down").duration(375).play();
}, 0);
}
For more information, please check:
Detailexpand documentation
Kendo Fx documentation

Related

Trigger Kendo Grid saveChanges externally and get errors

I've created a script that runs kendoGrid.saveChanges() on $(document).on('submit'). I want to submit only when the grid(s) is able to commit the changes. How can I know if the operation was successful or not?
$(document).on("submit", function (e) {
var grids = $('.k-grid');
if (grids.length > 0)
e.preventDefault();
console.log(`Found ${grids.length} grids`);
var hasErrors= false;
$.each(grids, function () {
var grid = $(this).data('kendoGrid');
if (grid.dataSource.hasChanges()) {
console.log(`Saving changes of ${$(this).attr('id')}`);
// something like this
if(!grid.saveChanges())
hasError=true;
}
});
if(!hasError)
//continue submit
});

Dynamic checkbox toggle to stack / unstack AMCharts 4 XY columnseries / bar chart

I have a checkbox placed separately of my XY columnseries chart. The original chart has each series.stacked = true. This works fine. I have a listener on the checkbox to toggle from the stacked columns to independent columns. It sets (toggles) the same stacked property on each series. Unfortunately nothing updates. I have tried calling invalidateData() on the chart after the property assignment - but that also doesn't work to update the stacking / unstacking function.
$("#chartAssetsTimelineIndividualColumns").change(function () {
chartAssetsTimeline.series.values.forEach(function (series) {
series.stacked = !this.checked;
});
});
this doesn't refer to the input element when you're inside the forEach method as it is scoped to the window object at that point. You'll want to save a reference to it and use that instead, or just use the event object that the change method provides. Also, you should use the each function instead of iterating over the read-only values array.
$('#chartAssetsTimelineIndividualColumns').change(function() {
var that = this;
chartAssetsTimelineIndividualColumns.series.each(function(series) {
series.stacked = !that.checked;
});
});
// or
$('#chartAssetsTimelineIndividualColumns').change(function(e) {
chartAssetsTimelineIndividualColumns.series.each(function(series) {
series.stacked = !e.target.checked;
});
});
// or, preferably, with VanillaJS:
document.getElementById('chartAssetsTimelineIndividualColumns').addEventListener('change', function(e) {
chartAssetsTimelineIndividualColumns.series.each(function(series) {
series.stacked = !e.target.checked;
});
});

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);
}
});

How to Fix Poor Performance on Filter By Text

A while back I found some code that allows you to filter the contents of a SELECT by typing in a text element. It works well however, over time the performance degrades pretty badly. I'm not sure if it is the filter code or the way in which I am activating it.
The SELECT shows up in a modal dialog (bootstrap) so I have the following code:
$('#myModal').on('shown', function () {
$(".focusable").val("").focus();
var select = $('#myModal').find(".modal-body").find("select");
var text = $('#myModal').find(".modal-body").find("input[type='text']");
select.filterByText(text, true);
});
And here is the filter code:
jQuery.fn.filterByText = function (textbox, selectSingleMatch) {
return this.each(function () {
var select = this;
var options = [];
$(select).find('option').each(function () {
options.push({value:$(this).val(), text:$(this).text(), data:$(this).data("short-name")});
});
$(select).data('options', options);
$(textbox).bind('change keyup', function () {
var options = $(select).empty().data('options');
var search = $.trim($(this).val());
var regex = new RegExp(search, 'gi');
$.each(options, function (i) {
var option = options[i];
if (option.text.match(regex) !== null) {
var copyOption = $('<option>').text(option.text).val(option.value);
copyOption.data("short-name", option.data);
$(select).append(copyOption);
}
});
if (selectSingleMatch === true &&
$(select).children().length === 1) {
$(select).children().get(0).selected = true;
}
});
});
};
Can anyone shed some light on where my performance issue(s) might be and how to solve it?
reading through the comments I would suggest to add the following:
$(textbox).bind('change keyup', function(event) {
console.log(event);
// your code
});
Is the event triggered more than once on a single keyup after some times the dialog is shown?
$('#myModal').on('hidden', function () {
$('#myModal').find(".modal-body").find("input[type='text']").off("change keyup");
});

ckeditor dialog positioning

Dialog windows for CKEditor by default appear in the middle of the page but if the page is an iframe with a big height the dialogs appear way down the page.
Is it possible to configure CKEditor to position the dialogs in a different quadrant of the page? For example top middle?
Yes, the link MDaubs gives will guide you to do what you want.
I've had to do this in the past and the following snippet will demonstrate a solution for your problem:
CKEDITOR.on('dialogDefinition', function(e) {
var dialogName = e.data.name;
var dialogDefinition = e.data.definition;
dialogDefinition.onShow = function() {
this.move(this.getPosition().x,0); // Top center
}
})
You can place this in the config file or the ready function for jQuery.
The solution by zaf works in that it helps to position the dialog, but I've found it to produce a bunch of side effects as to how the dialog functions (failing to display the URL of the image in the image dialog is one example).
It turned out that the original onShow() method that is being overridden returns a meaningful value that we should keep. This could be due to a plugin or something, but here's the code that ultimately worked for me:
CKEDITOR.on('dialogDefinition', function(e) {
var dialogName = e.data.name;
var dialogDefinition = e.data.definition;
var onShow = dialogDefinition.onShow;
dialogDefinition.onShow = function() {
var result = onShow.call(this);
this.move(this.getPosition().x, $(e.editor.container.$).position().top);
return result;
}
});
This may be way you're looking for:
Programatically set the position of CKEditor's dialogs
I just had the same issue as Yehonatan and found this question really fast via Google. But after using the answer provided by zaf I still didn't get a dialog to appear in the proper position when the editor is loaded within an iframe.
In stead of the position() method I used the offset() method to place a dialog right under the toolbar. Together with the response of jonespm I came to this code that seems to work very good, also with existing dialogs.
CKEDITOR.on('dialogDefinition', function(e) {
var dialogName = e.data.name;
var dialogDefinition = e.data.definition;
var onShow = dialogDefinition.onShow;
dialogDefinition.onShow = function() {
this.move(this.getPosition().x, jQuery(this.getParentEditor().container.$).offset().top);
if (typeof onShow !== 'undefined' && typeof onShow.call === 'function')
{
return onShow.call(this);
}
}
});
Hopefully this code can help others with the same issue as me.
Correct syntax is:
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var dialog = dialogDefinition.dialog;
if (dialogName == 'image2') {
dialogDefinition.onShow = CKEDITOR.tools.override(dialogDefinition.onShow, function(original) {
return function() {
original.call(this);
CKEDITOR.tools.setTimeout( function() {
/*do anything: this.move(this.getPosition().x, $(e.editor.container.$).position().top);*/
}, 0);
}
});
}
});

Resources