Kendo Custom Widget Filter - kendo-ui

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" } } ];

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>

How to customize kendo multi select dropdown group header

I'm trying to customize my kendo multiselect control's group header. I have checked the documentation below,
https://demos.telerik.com/kendo-ui/multiselect/grouping
no matter how I change the groupTemplat, the group always display in top right. Please check my code below,
var checkInputs = function (elements) {
elements.each(function () {
var element = $(this);
var input = element.children("input");
input.prop("checked", element.hasClass("k-state-selected"));
});
};
function initData() {
$scope.dataOptions = {
dataSource: getDataSource(),
dataTextField: "value",
itemTemplate: "<input type='checkbox'/> #:data.value# ",
groupedTemplate: "<input type='checkbox'/> #:data#",
autoClose: false,
dataBound: function () {
var items = this.ul.find("li");
setTimeout(function () {
checkInputs(items);
});
},
change: function () {
var items = this.ul.find("li");
checkInputs(items);
}
}
}
I want to implement the multi-select dropdown like the Location option in this website.
When I checked the group, then all of the items in this group should be selected.

How to set Row data using rowid and column name in jQgrid

I've added a custom icon using below code in jqgrid Actions column. When the cutom icon is clicked, a pop up is opened with Textarea, Save and Close buttons. When I click Save button I wanted to save the text entered in textarea to a hidden field column in jQgrid. I tried 'setRowData' and 'setCell' properties but nothing works. Am I missing something here?
afterInsertRow: function (rowid, rowdata, rowelem) {
$(this).triggerHandler("afterInsertRow.jqGrid", [rowid, rowdata, rowelem]);
//...//
//Start: Code for Notes Icon in Actions column
var iCol = getColumnIndexByName(grid, 'actions');
$(this).find(">tbody>tr#" + rowid + ">td:nth-child(" + (iCol + 1) + ")")
.each(function () {
$("<div>", {
title: "Custom",
mouseover: function () {
$(this).addClass('ui-state-hover');
},
mouseout: function () {
$(this).removeClass('ui-state-hover');
},
click: function (eve) {
$("#change_dialog").dialog({
buttons: {
'Save': function () {
var selRow = $(eve.target).closest("tr.jqgrow").attr("id");
var txtNotes = $("#mytext").val();
$("#gridJQ").setRowData(selRow, { 'notesHidden': txtNotes });
$("#gridJQ").jqGrid('setCell', selRow, 'notesHidden', txtNotes);
$("#gridJQ").jqGrid('setRowData', selRow, 'notesHidden', txtNotes);
$(this).dialog("close");
},
'Close':function() {
$(this).dialog("close");
}
}
});
return false;
}
}
).css({ "margin-right": "5px", float: "left", cursor: "pointer" })
.addClass("ui-pg-div ui-inline-custom")
.append('<span class="ui-icon ui-icon-document"></span>')
.prependTo($(this).children("div"));
});
Instead of using this code to get the row
var selRow = $(eve.target).closest("tr.jqgrow").attr("id");
Try something a more direct such as
var selRow = $("#gridJQ").jqGrid('getGridParam', 'selrow');
Or even just var selRow = rowid.
Does that help at all?

MVVM binding to a Kendo Grid is VERY slow?

I am trying to bind a ViewModel to a Kendo DataSource which in turn is given to a Kendo Grid. Nothing too fancy at this point.
It sort of works but is VERY slow! I have an alert informing me that I have received my json data (700 rows) within 2 seconds but it then takes around 15 seconds to update the viewmodel.
What am I doing wrong?
Thanks
$(document).ready(function () {
// create the viewmodel we use as the source for the list
var viewModel = kendo.observable({
items: [],
total: function () {
return this.get("items").length;
}
});
var dataSource2 = new kendo.data.DataSource({
data: viewModel,
pageSize: 50
});
// create the grid
$("#grid").kendoGrid({
dataSource: dataSource2,
height: 500,
scrollable: {
virtual: true
},
columns: [
{ field: "ID_ORDER", title: "ID", width: 80 },
{ field: "CREATION_DATE", title: "Creation Date" },
{ field: "STATUS", title: "STATUS", width: 80 },
** more columns (around 10) **
]
});
// pass this on to initialise
APPS.View.Orders.Initialise(viewModel);
});
Then in my typescript I am handling the Initialise call where the viewModel is passed in:
module APP.View.Orders {
export var _Scope: string = "Orders";
var _viewModelOrders: any;
export var Initialise = function (viewModelOrders: any) {
_viewModelOrders = viewModelOrders;
var orderdetails = {
userid: APP.Core.userID,
context: "DEAL"
};
// retrieve all orders
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
alert("item count (1): " + mydata.length);
jQuery.each(mydata, function () {
var newItem = this;
_viewModelOrders.items.push(newItem);
});
alert("item count (2): " + _viewModelOrders.items.length);
}
catch (e) {
alert(e.message);
}
});
}
}
Try building the item array and then assign it into the model.
Something like:
// retrieve all orders
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
alert("item count (1): " + mydata.length);
var items = [];
jQuery.each(mydata, function () {
items.push(this);
});
_viewModelOrders.items = items;
alert("item count (2): " + _viewModelOrders.items.length);
}
catch (e) {
alert(e.message);
}
});
You can suspend the observable temporarily by doing the following:
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
var simpleArray = viewModel.items(); // get a reference to the underlying array instance of the observable
jQuery.each(mydata, function () {
items.push(this);
});
viewModel.items.valueHasMutated(); // let the observable know it's underlying data has been updated
}
catch (e) {
alert(e.message);
}
}
Doing the above technique dramatically improves loading times. I have testing this loading a few thousand rows in a reasonable time.
To explain further, this is due to the line:
_viewModelOrders.items.push(newItem);
Each time you push an item into the array, it triggers a change event, which the Grid sees and updates itself. So if you push 700 items in, you are really causing the grid to update the DOM 700 times.
It would be much better to aggregate all the items into an array, then assign the array to the DataSource, with something like:
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
datasource2.data(mydata);

Trigger sort method from an event in Backbone.js

I have a Backbone.js project which uses a comparator function defined in the collection. It sorts items when the page is refreshed, but I am trying to get it to sort when a button is clicked instead of on page refresh. Here is my code:
var Thing = Backbone.Model.extend({
defaults: {
title: 'blank',
rank: ''
}
});
var ThingView = Backbone.View.extend({
className: 'thingClass',
template: _.template('<b><button id="remove">X</button> <b><button id="edit">Edit</button> <%= title %> Rank:<%= rank %></b>'),
editTemplate: _.template('<input class="name" value="<%= name %>" /><button id="save">Save</button>'),
events: {
"click #remove": "deleteItem",
"click #edit": "editItem",
"click #save": "saveItem",
},
deleteItem: function () {
console.log('deleted');
this.model.destroy();
this.remove();
},
editItem: function () {
console.log('editing');
this.$el.html(this.editTemplate(this.model.toJSON()));
},
saveItem: function () {
console.log('saved');
editTitle = $('input.name').val();
console.log(editTitle);
this.model.save({
title: editTitle
});
this.$el.html(this.template(this.model.toJSON()));
},
render: function () {
var attributes = this.model.toJSON();
//console.log (attributes);
this.$el.append(this.template(attributes));
return this;
}
});
var ThingsList = Backbone.Collection.extend({
model: Thing,
localStorage: new Store("store-name"),
comparator: function(thing) {
return thing.get('rank');
},
});
var thingsList = new ThingsList;
var ThingsListView = Backbone.View.extend({
el: $('body'),
events: {
'click #add': 'insertItem',
'click #sort': 'sortItems',
},
initialize: function () {
thingsList.fetch();
thingsList.toJSON();
this.render();
this.collection.on("add", this.renderThing, this);
this.collection.on("reset", this.clearRender, this);
},
insertItem: function (e) {
newTitle = $('#new-item').val();
newRank = $('#rank').val();
newThing = new Thing({
title: newTitle,
rank: newRank
});
this.collection.add(newThing);
newThing.save();
console.log(this.collection.length);
},
sortItems: function (e) {
console.log('clicked sort button');
this.collection.sort();
this.$el.detach('.item');
},
render: function () {
_.each(this.collection.models, function (items) {
this.renderThing(items);
}, this);
},
renderThing: function (items) {
var thingView = new ThingView({
model: items
});
this.$el.append(thingView.render().el);
},
clearRender: function () {
console.log('clear render called')
_.each(this.collection.models, function (items) {
//this.remove();
this.$el.remove(".thingClass")
this.renderThing(items);
}, this);
},
test: function (items) {
console.log('test worked');
},
});
var thingsListView = new ThingsListView({
collection: thingsList
});
Are you sure your collection isn't resorting itself? keep in mind that the order of the models in the collection won't change the order of how they appear on the page if they are already rendered.
I'm guessing that what you are trying to do is resort the items that have already been rendered, to do so you would need re-render your collection. If you are going to do so I would recommend that you cache your views and on a sort detach the associated element from the DOM and reattach them in the correct order.
As an example
var ThingsListView = Backbone.View.extend({
_views: {},
initialize: function () {
this.collection.bind('add', this.add, this);
this.collection.bind('reset', this.render, this); //sort triggers a reset
},
add: function (thing) {
var view = new ThingView({model: thing});
this._views[thing.cid] = view; //use client id of model as key for the views cache
this.$el.append(view.render().el);
},
render: function() {
$('li, this.$el).detach(); //detach so that bound events aren't lost
_.each(this.collection.models, function(thing) {
this.$el.append(this.views[thing.cid].el); //get view from cache
},this);
},
sort: function() {
this.collection.sort();
}
}
})
(a couple of differences from my example code and yours I'm assuming here that the collection view has a 'el' referring to a container 'ul', I also don't show how your triggering the sort (basically something like thingListView.sort();)
Edit: It might not be so obvious from the example code I posted, so I should have mentioned to begin with what #Deeptechtons said that when you sort a collection it triggers a reset event
Edit2: If your not interested in caching your views, then the easiest way to remove your current views would probablly be to add a class to the rendered div
var ThingView = Backbone.View.extend({
className: 'thingClass',
//rest of your thingViewCode
Then in your clearRender method just add $(".thingClass", this.$el).remove(); to the beginning of the method.

Resources