Populate an iggrid combo box column on demand inside Editor dialog - javascript
I am attempting to load an editor dialog that contains a combo box. The combo box should be populated onload. the problem is that the combobox datasource doesn't get loaded the same time as the grid and when the data is finally fully populated from service the data is not intialized and displays an empty drop down list. I want to update the combobox columnSettings datasource when my data is returned from service.
I tried populating the combo box on the editRowStarted event? This worked but not for the initial display of the combo box.
<script>
var userDirectoryViewModel = #Html.Raw(Json.Encode(#Model));
</script>
<script id="dialogTemplate" type="text/html">
<div class="row-edit-dialog-container-head"><strong>${Name}</strong></div>
<div class="row-edit-dialog-container-cols">
<div style="float: left;">
<table>
<colgroup>
<col style="width: 30%;" />
<col style="width: 70%;" />
</colgroup>
<tbody data-render-tmpl="true"></tbody>
</table>
<button>Select</button>
</div>
#*<div style="width: 160px; float: right;">
<img width="100" height="90" src="${ImageUrl}" alt="${Name}" title="${Name}" style="float:right;" />
</div>*#
</div>
</script>
<script id="editorsTemplate" type="text/html">
<tr>
<td style="text-align:right;color:#777;"><strong>${headerText}</strong></td>
<td><input data-editor-for-${key}="true" /></td>
</tr>
</script>
<script type="text/javascript">
var mappingTypeList = [
{ Name: "GrantAdministratorRole", Number: "0" }, { Name: "GrantSupervisorRole", Number: "1" }, { Name: "MapToUserGroup", Number: "2" },
{ Name: "MapToTeam", Number: "3" }
];
//load on demand.
var mapToTeamList = [];
var mapToUserGroupList = [];
//Formatting for igGrid cells to display igCombo text as opposed to igCombo value
function formatMappingTypeCombo(val) {
var i, mappingType;
for (i = 0; i < mappingTypeList.length; i++) {
mappingType = mappingTypeList[i];
if (mappingType.Number == val) {
val = mappingType.Name;
}
}
return val;
}
function formatMapToUserGroupCombo(val) {
var i, userGroup;
for (i = 0; i < mapToUserGroupList.length; i++) {
userGroup = mapToUserGroupList[i];
if (userGroup.UserGroupID == val) {
val = userGroup.Name;
}
}
return val;
}
function formatMapToTeamCombo(val) {
var i, team;
for (i = 0; i < mapToTeamList.length; i++) {
team = mapToTeamList[i];
if (team.Number == val) {
val = team.Name;
}
}
return val;
}
function populateUserDirectoryMappings() {
console.log("calling populateUserDirectoryMappings()");
$.ajax({
type: "GET",
url: '/userdirectory/GetUserDirectoryMappings',
dataType: "json",
success: function (childData) {
mapToUserGroupList = childData.UserGroups;
mapToTeamList = childData.Teams;
return childData;
},
error:function() {
alert("error");
}
}).done(function(data) {
mapToUserGroupList = data.UserGroups;
});
}
function getUserGroups() {
var data = populateUserDirectoryMappings();
return data.UserGroups;
}
$( function () {
$("#groupMappingTable")
.igGrid({
dataSource: userDirectoryViewModel.GroupMappings,
primaryKey: "UserDirectoryGroupID",
width: "85%",
autoCommit: true,
autoGenerateColumns: false,
localSchemaTransform: false,
columns: [
{ headerText: "UserDirectoryGroupID", key: "UserDirectoryGroupID", dataType: "number", hidden: true },
{ headerText: "UserDirectoryID", key: "UserDirectoryID", dataType: "number", hidden: true },
{ headerText: "OrganizationID", key: "OrganizationID", dataType: "number", hidden: true },
{ headerText: "ExternalGroup", key: "Name", dataType: "string" },
{ headerText: "MappingType", key: "MappingType",formatter: formatMappingTypeCombo,width: "20%" },
{ headerText: "MapToUserGroup", key: "MapToUserGroup",formatter: formatMapToUserGroupCombo,width: "20%" },
{ headerText: "MapToTeam", key: "MapToTeam",formatter: formatMapToTeamCombo,width: "20%" }
],
rendered: function (evt, ui) {
},
features: [
{
name: "Updating",
enableAddRow: true,
enableDeleteRow: true,
editMode: "dialog",
columnSettings: [
{
columnKey: "OrganizationID",
readOnly: true
},
{
columnKey: "MappingType",
required:true,
editorType:"combo",
editorOptions: {
mode:"dropdown",
dataSource:mappingTypeList,
textKey:"Name",
valueKey:"Number"
}
},
{
columnKey: "MapToUserGroup",
required:false,
editorType:"combo",
editorOptions: {
mode:"dropdown",
id: 'mapToUserGroupComboID',
dataSource: mapToUserGroupList,
textKey:"Name",
valueKey:"UserGroupID"
}
},
{
columnKey: "UserDirectoryID",
readOnly: true
},
{
columnKey: "UserDirectoryGroupID",
readOnly: true
}
],
rowEditDialogOptions: {
width: "530px",
height: "410px",
dialogTemplateSelector: "#dialogTemplate",
editorsTemplateSelector: "#editorsTemplate",
showReadonlyEditors: false
},
rowAdding: function (evt, ui) {
ui.values["OrganizationID"] = userDirectoryViewModel.OrganizationID;
ui.values["UserDirectoryID"] = userDirectoryViewModel.UserDirectoryID;
},
rowAdded: function (evt, ui) {
console.log("row added event");
var ds = $("#groupMappingTable").igGrid("option", "dataSource");
},
editRowStarted: function(evt, ui) {
},
editRowEnded: function (evt, ui) {
//alert(ui.rowId);
}
}
]
});
});
</script>
I found the answer here api documentation
and I was then able to call into the grid and get the columnSettings object upon successfully retrieving the combo box data from the server.
function populateUserDirectoryMappings() {
console.log("calling populateUserDirectoryMappings()");
$.ajax({
type: "GET",
url: '/userdirectory/GetUserDirectoryMappings',
dataType: "json",
success: function(childData) {
mapToUserGroupList = childData.UserGroups;
mapToTeamList = childData.Teams;
return childData;
},
error: function() {
alert("error");
}
}).done(function(data) {
console.log("done");
console.log(data);
mapToUserGroupList = data.UserGroups;
var grid = $('#groupMappingTable').data('igGridUpdating');
var updating = grid.options.columnSettings;
console.log(updating);
console.log("map to user group list");
console.log(mapToUserGroupList);
$.each(updating, function(index, data) {
console.log("column");
console.log(data);
if (data.columnKey == "MapToUserGroup") {
data.editorOptions.dataSource = mapToUserGroupList;
}
});
});
}
Related
Kendo grid loosing selected row
I'm using Kendo UI for my grid everything works find with that. I can select one or many rows using scroll and shift. The problem is that if I select row 3 and then some event refresh the grid and after that I want to select row 4 too Kendo is selecting all the above rows, in this case from row 1-4. So my question is how can I solve this issue? Desired result in the demo: Select Germany, refresh grid, then select until Belgium. The demo is going to select from row 1 to Belgium. Here is a demo <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Kendo UI Snippet</title> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.common.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.rtl.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.silver.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.mobile.all.min.css"/> <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="http://kendo.cdn.telerik.com/2016.3.1028/js/kendo.all.min.js"></script> </head> <body> <button id="refresh">Refresh</button> <div id="grid"></div> <script> $(function () { var selectedOrders = []; var idField = "OrderID"; $('#refresh').click(() => { $("#grid").getKendoGrid().dataSource.read(); }) $("#grid").kendoGrid({ dataSource: { type: "odata", transport: { read: "http://demos.kendoui.com/service/Northwind.svc/Orders" }, schema: { model: { id: "OrderID", fields: { OrderID: { type: "number" }, Freight: { type: "number" }, ShipName: { type: "string" }, OrderDate: { type: "date" }, ShipCity: { type: "string" } } } }, pageSize: 10, serverPaging: true, serverFiltering: true, serverSorting: true }, height: 400, selectable: "multiple", pageable: { buttonCount: 5 }, sortable: true, filterable: true, navigatable: true, columns: [ { field: "ShipCountry", title: "Ship Country", width: 300 }, { field: "Freight", width: 300 }, { field: "OrderDate", title: "Order Date", format: "{0:dd/MM/yyyy}" } ], change: function (e, args) { var grid = e.sender; var items = grid.items(); items.each(function (idx, row) { var idValue = grid.dataItem(row).get(idField); if (row.className.indexOf("k-state-selected") >= 0) { selectedOrders[idValue] = true; } else if (selectedOrders[idValue]) { delete selectedOrders[idValue]; } }); }, dataBound: function (e) { var grid = e.sender; var items = grid.items(); var itemsToSelect = []; items.each(function (idx, row) { var dataItem = grid.dataItem(row); if (selectedOrders[dataItem[idField]]) { itemsToSelect.push(row); } }); e.sender.select(itemsToSelect); } }); }); </script> </body> </html>
This problem is so similar to the problem I had which I wrote about here, Kendo Grid Persist Row Example. In the example I wrote, I used persistSelection which is recommended. This behaviour is happening because after the refresh event the grid no longer knows which row was focused previously. So on dataBound, we need to set that focus back. Here's a snippet that might help you. <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Kendo UI Snippet</title> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.common.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.rtl.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.silver.min.css"/> <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.3.1028/styles/kendo.mobile.all.min.css"/> <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="http://kendo.cdn.telerik.com/2016.3.1028/js/kendo.all.min.js"></script> </head> <body> <button id="refresh">Refresh</button> <div id="grid"></div> <script> $(function() { var selectedOrders = []; var idField = "OrderID"; $('#refresh').click(() => { $("#grid").getKendoGrid().dataSource.read(); }); $("#grid").kendoGrid({ dataSource: { type: "odata", transport: { read: "http://demos.kendoui.com/service/Northwind.svc/Orders" }, schema: { model: { id: "OrderID", fields: { OrderID: { type: "number" }, Freight: { type: "number" }, ShipName: { type: "string" }, OrderDate: { type: "date" }, ShipCity: { type: "string" } } } }, pageSize: 10, serverPaging: true, serverFiltering: true, serverSorting: true }, height: 400, selectable: "multiple", pageable: { buttonCount: 5 }, sortable: true, filterable: true, navigatable: true, columns: [ { field: "ShipCountry", title: "Ship Country", width: 300 }, { field: "Freight", width: 300 }, { field: "OrderDate", title: "Order Date", format: "{0:dd/MM/yyyy}" } ], change: function (e, args) { var grid = e.sender; var items = grid.items(); items.each(function (idx, row) { var idValue = grid.dataItem(row).get(idField); if (row.className.indexOf("k-state-selected") >= 0) { selectedOrders[idValue] = true; } else if (selectedOrders[idValue]) { delete selectedOrders[idValue]; } }); }, dataBound: function (e) { var grid = e.sender; var items = grid.items(); var itemsToSelect = []; items.each(function (idx, row) { var dataItem = grid.dataItem(row); if (selectedOrders[dataItem[idField]]) { itemsToSelect.push(row); } }); if (itemsToSelect.length > 0) { var lastRow = itemsToSelect[itemsToSelect.length - 1]; grid.selectable._lastActive = lastRow; grid.current($(lastRow).find("td:first")); } e.sender.select(itemsToSelect); } }); }); </script> </body> </html>
you can get and persist selected row on a specific page after edit or paging in change and databound events like this: Grid_OnRowSelect = function (e) { this.currentPageNum = grid.dataSource.page(); //Save index of selected row this.selectedIndex = grid.select().index(); } .Events(e => e.DataBound( #<text> function(e) { //جهت نمایش صحیح پیجینگ var grid = $("#Grid").data("kendoGrid"); grid.pager.resize(); //در صورت تغییر صفحه، سطر را انتخاب نکند if(this.currentPageNum == grid.dataSource.page()) { //انتخاب مجدد سطر انتخاب شده قبل از ویرایش var row = grid.table.find("tr:eq(" + this.selectedIndex + ")"); grid.select(row); } } </text>) ) in your case you can set rows in a list and use in databound
Kendo UI Grid : Drag and Drop Hierarchy not working
I want to drag and drop in different Grid with hierarchical data. The Drag and drop is working fine but the row is not dropping in Detail item in destination grid. I have created the sample here. here is the sample for the same.. The following code shows how i built this, but getting some issues in the same. Please help me out what mistake i am doing in this? function convert(array) { var map = {}; for (var i = 0; i < array.length; i++) { var obj = array[i]; obj.items = []; map[obj.DemographicId] = obj; var parent = obj.ParentId || '-'; if (!map[parent]) { map[parent] = { items: [] }; } map[parent].items.push(obj); } return map['-'].items; } var arr = [{"Level":1,"DemographicId":13,"ParentId":null,"Name":"Bewitched General","Description":0.335336528},{"Level":2,"DemographicId":349,"ParentId":13,"Name":"Unacceptable Experience","Description":0.335336528},{"Level":1,"DemographicId":14,"ParentId":null,"Name":"Trained Trust","Description":29.17427794},{"Level":2,"DemographicId":329,"ParentId":14,"Name":"Concerned Rest","Description":0.335336528},{"Level":2,"DemographicId":331,"ParentId":14,"Name":"Tough Sleep","Description":2.012019168},{"Level":3,"DemographicId":346,"ParentId":331,"Name":"Icy Coffee","Description":0.335336528},{"Level":3,"DemographicId":347,"ParentId":331,"Name":"Big Fix","Description":0.335336528},{"Level":3,"DemographicId":348,"ParentId":331,"Name":"Total Worry","Description":0.335336528},{"Level":3,"DemographicId":431,"ParentId":331,"Name":"Fast Discipline","Description":0.335336528},{"Level":3,"DemographicId":586,"ParentId":331,"Name":"Intrepid Sister","Description":0.335336528},{"Level":2,"DemographicId":376,"ParentId":14,"Name":"Hasty Ordinary","Description":0.335336528},{"Level":2,"DemographicId":428,"ParentId":14,"Name":"Unnatural Native","Description":1.006009584},{"Level":3,"DemographicId":442,"ParentId":428,"Name":"Tan Celebration","Description":0.335336528},{"Level":3,"DemographicId":492,"ParentId":428,"Name":"Wise Repair","Description":0.335336528},{"Level":2,"DemographicId":443,"ParentId":14,"Name":"Frightening Historian","Description":3.018028753},{"Level":3,"DemographicId":328,"ParentId":443,"Name":"Improbable Stage","Description":0.335336528},{"Level":3,"DemographicId":517,"ParentId":443,"Name":"Heavenly Debt","Description":0.335336528},{"Level":3,"DemographicId":526,"ParentId":443,"Name":"That Art","Description":2.012019168},{"Level":4,"DemographicId":524,"ParentId":526,"Name":"Vivacious Competition","Description":0.670673056},{"Level":5,"DemographicId":445,"ParentId":524,"Name":"Dependable Potato","Description":0.335336528},{"Level":4,"DemographicId":525,"ParentId":526,"Name":"Watchful Tough","Description":1.006009584},{"Level":5,"DemographicId":432,"ParentId":525,"Name":"Lovable Sing","Description":0.670673056},{"Level":6,"DemographicId":435,"ParentId":432,"Name":"Vengeful Cigarette","Description":0.335336528},{"Level":2,"DemographicId":522,"ParentId":14,"Name":"Insistent Offer","Description":0.335336528},{"Level":2,"DemographicId":590,"ParentId":14,"Name":"Oddball Airline","Description":0.335336528},{"Level":2,"DemographicId":591,"ParentId":14,"Name":"Back Outcome","Description":20.79086474},{"Level":3,"DemographicId":330,"ParentId":591,"Name":"Mushy Active","Description":0.335336528},{"Level":3,"DemographicId":427,"ParentId":591,"Name":"Immaterial Safety","Description":1.341346112},{"Level":4,"DemographicId":437,"ParentId":427,"Name":"Same Restaurant","Description":0.335336528},{"Level":4,"DemographicId":438,"ParentId":427,"Name":"Imaginary Brother","Description":0.335336528},{"Level":4,"DemographicId":613,"ParentId":427,"Name":"Bubbly Hole","Description":0.335336528},{"Level":3,"DemographicId":433,"ParentId":591,"Name":"Several Weird","Description":2.682692225},{"Level":4,"DemographicId":426,"ParentId":433,"Name":"Deadly Potato","Description":0.335336528},{"Level":4,"DemographicId":436,"ParentId":433,"Name":"Ornery Race","Description":0.335336528},{"Level":4,"DemographicId":440,"ParentId":433,"Name":"Trusting Native","Description":0.335336528},{"Level":4,"DemographicId":441,"ParentId":433,"Name":"Flowery Tower","Description":0.335336528},{"Level":4,"DemographicId":479,"ParentId":433,"Name":"Downright Fall","Description":0.335336528},{"Level":4,"DemographicId":480,"ParentId":433,"Name":"Unique Career","Description":0.335336528},{"Level":4,"DemographicId":614,"ParentId":433,"Name":"Unknown Thomas","Description":0.335336528},{"Level":3,"DemographicId":592,"ParentId":591,"Name":"Judicious Analyst","Description":0.335336528},{"Level":3,"DemographicId":593,"ParentId":591,"Name":"Hard Major","Description":0.335336528},{"Level":3,"DemographicId":595,"ParentId":591,"Name":"Naughty Temporary","Description":0.335336528},{"Level":3,"DemographicId":596,"ParentId":591,"Name":"Crisp Commission","Description":0.335336528},{"Level":3,"DemographicId":597,"ParentId":591,"Name":"Valid Funny","Description":0.335336528},{"Level":3,"DemographicId":598,"ParentId":591,"Name":"Luminous Log","Description":0.335336528},{"Level":3,"DemographicId":599,"ParentId":591,"Name":"Sour Introduction","Description":0.335336528},{"Level":3,"DemographicId":600,"ParentId":591,"Name":"Elegant Player","Description":0.335336528},{"Level":3,"DemographicId":601,"ParentId":591,"Name":"Wilted Scheme","Description":1.006009584},{"Level":4,"DemographicId":444,"ParentId":601,"Name":"That Research","Description":0.335336528},{"Level":4,"DemographicId":609,"ParentId":601,"Name":"Overcooked Message","Description":0.335336528},{"Level":3,"DemographicId":602,"ParentId":591,"Name":"Good-natured Responsibility","Description":3.688701809},{"Level":4,"DemographicId":478,"ParentId":602,"Name":"Cumbersome Battle","Description":0.335336528},{"Level":4,"DemographicId":515,"ParentId":602,"Name":"Unsightly Contest","Description":2.682692225},{"Level":5,"DemographicId":439,"ParentId":515,"Name":"Mushy Explanation","Description":0.335336528},{"Level":5,"DemographicId":508,"ParentId":515,"Name":"Obvious Pride","Description":0.670673056},{"Level":6,"DemographicId":509,"ParentId":508,"Name":"Negligible Ask","Description":0.335336528},{"Level":5,"DemographicId":514,"ParentId":515,"Name":"Concerned Classic","Description":1.341346112},{"Level":6,"DemographicId":510,"ParentId":514,"Name":"Greedy Double","Description":0.335336528},{"Level":6,"DemographicId":511,"ParentId":514,"Name":"Reflecting Poem","Description":0.335336528},{"Level":6,"DemographicId":512,"ParentId":514,"Name":"Every Finish","Description":0.335336528},{"Level":4,"DemographicId":610,"ParentId":602,"Name":"Zigzag Meet","Description":0.335336528},{"Level":3,"DemographicId":603,"ParentId":591,"Name":"Esteemed Satisfaction","Description":0.335336528},{"Level":3,"DemographicId":604,"ParentId":591,"Name":"Normal Trouble","Description":1.341346112},{"Level":4,"DemographicId":485,"ParentId":604,"Name":"Hot Fish","Description":0.335336528},{"Level":4,"DemographicId":611,"ParentId":604,"Name":"Eager Perception","Description":0.335336528},{"Level":4,"DemographicId":612,"ParentId":604,"Name":"Shocking Aside","Description":0.335336528},{"Level":3,"DemographicId":605,"ParentId":591,"Name":"Terrific King","Description":0.335336528},{"Level":3,"DemographicId":606,"ParentId":591,"Name":"Humiliating Suit","Description":0.335336528},{"Level":3,"DemographicId":607,"ParentId":591,"Name":"Serious Smile","Description":0.335336528},{"Level":3,"DemographicId":608,"ParentId":591,"Name":"Memorable Ship","Description":3.353365281},{"Level":4,"DemographicId":430,"ParentId":608,"Name":"Wan Science","Description":0.335336528},{"Level":4,"DemographicId":434,"ParentId":608,"Name":"Hard Rule","Description":0.335336528},{"Level":4,"DemographicId":473,"ParentId":608,"Name":"Marvelous Radio","Description":0.335336528},{"Level":4,"DemographicId":477,"ParentId":608,"Name":"Visible Personality","Description":0.335336528},{"Level":4,"DemographicId":481,"ParentId":608,"Name":"Scrawny Shine","Description":0.335336528},{"Level":4,"DemographicId":507,"ParentId":608,"Name":"Descriptive Pride","Description":0.335336528},{"Level":4,"DemographicId":516,"ParentId":608,"Name":"Pleased Private","Description":0.335336528},{"Level":4,"DemographicId":548,"ParentId":608,"Name":"Frizzy District","Description":0.335336528},{"Level":4,"DemographicId":615,"ParentId":608,"Name":"Juicy Organization","Description":0.335336528},{"Level":3,"DemographicId":616,"ParentId":591,"Name":"Sweaty Equal","Description":0.335336528},{"Level":3,"DemographicId":621,"ParentId":591,"Name":"Sweltering Cigarette","Description":0.335336528},{"Level":3,"DemographicId":623,"ParentId":591,"Name":"Buoyant Rule","Description":0.335336528},{"Level":3,"DemographicId":625,"ParentId":591,"Name":"Whimsical Remote","Description":0.335336528},{"Level":3,"DemographicId":633,"ParentId":591,"Name":"Notable Feed","Description":0.335336528},{"Level":3,"DemographicId":635,"ParentId":591,"Name":"Puzzled Pin","Description":1.006009584},{"Level":4,"DemographicId":594,"ParentId":635,"Name":"Plump Member","Description":0.335336528},{"Level":4,"DemographicId":636,"ParentId":635,"Name":"Colorless Service","Description":0.335336528},{"Level":2,"DemographicId":618,"ParentId":14,"Name":"Extroverted Excuse","Description":0.335336528},{"Level":2,"DemographicId":622,"ParentId":14,"Name":"Definite Sector","Description":0.335336528},{"Level":2,"DemographicId":631,"ParentId":14,"Name":"Dear Blue","Description":0.335336528},{"Level":1,"DemographicId":15,"ParentId":null,"Name":"Weird Rush","Description":3.688701809},{"Level":2,"DemographicId":461,"ParentId":15,"Name":"Vigilant Mine","Description":0.335336528},{"Level":2,"DemographicId":527,"ParentId":15,"Name":"Darling Cousin","Description":2.682692225},{"Level":3,"DemographicId":504,"ParentId":527,"Name":"Courteous Knife","Description":0.335336528},{"Level":3,"DemographicId":528,"ParentId":527,"Name":"Constant Window","Description":2.012019168},{"Level":4,"DemographicId":6,"ParentId":528,"Name":"Serene Personal","Description":0.335336528},{"Level":4,"DemographicId":518,"ParentId":528,"Name":"Cooperative Marketing","Description":0.335336528},{"Level":4,"DemographicId":530,"ParentId":528,"Name":"Likely Car","Description":0.335336528},{"Level":4,"DemographicId":531,"ParentId":528,"Name":"Worst Lip","Description":0.335336528},{"Level":4,"DemographicId":550,"ParentId":528,"Name":"Quintessential Evening","Description":0.335336528},{"Level":2,"DemographicId":529,"ParentId":15,"Name":"Knowing Debt","Description":0.335336528},{"Level":2,"DemographicId":587,"ParentId":15,"Name":"Harmless Weight","Description":0.335336528},{"Level":1,"DemographicId":16,"ParentId":null,"Name":"Tidy Mouse","Description":2.012019168},{"Level":2,"DemographicId":5,"ParentId":16,"Name":"Useless Chemistry","Description":0.335336528},{"Level":2,"DemographicId":254,"ParentId":16,"Name":"Several Expert","Description":0.335336528},{"Level":2,"DemographicId":486,"ParentId":16,"Name":"Young String","Description":0.335336528},{"Level":2,"DemographicId":519,"ParentId":16,"Name":"Ideal Army","Description":1.006009584},{"Level":3,"DemographicId":520,"ParentId":519,"Name":"Tart Text","Description":0.335336528},{"Level":3,"DemographicId":521,"ParentId":519,"Name":"Tiny Church","Description":0.335336528}] var myData = convert(arr) var dataSource1 = new kendo.data.DataSource({ data: myData }); $(document).ready(function () { var originalGrid = $("#originalGrid").kendoGrid({ dataSource: dataSource1, sortable: false, pageable: false, detailInit: detailInit1, dataBound: function () { //this.expandRow(this.tbody.find("tr.k-master-row").last()); }, columns: [ { field: "Name", title: "Name", width: "80px" }, { field: "Description", title: "Amount", width: "30px", aggregates: ["sum"], groupFooterTemplate: "Sum: #= sum # " } ] }); }); function detailInit1(e) { $("<div/>").appendTo(e.detailCell).kendoGrid({ dataSource: { data: e.data.items //data is the current position item, items is its child items }, scrollable: false, sortable: false, pageable: false, detailInit: detailInit1, columns: [ { field: "Name", title: "Name", width: "80px" }, { field: "Description", title: "Amount", width: "30px", aggregates: ["sum"], groupFooterTemplate: "Sum: #= sum # " } ] }); } $(document).ready(function () { var dataSource2 = new kendo.data.DataSource({ data: [] }); var grid2 = $("#grid2").kendoGrid({ dataSource: dataSource2, width: 400, sortable: false, pageable: false, detailInit: detailInit11, schema: { model: { id: "DemographicId" } }, columns: [ { field: "Name", title: "Name", width: "40px" }, { field: "Description", title: "Amount", width: "110px", aggregates: ["sum"], groupFooterTemplate: "Sum: #= sum # " } ] }); function detailInit11(e) { $("<div/>").appendTo(e.detailCell).kendoGrid({ dataSource: { data: e.data.items }, scrollable: false, sortable: false, pageable: false, detailInit: detailInit11, columns: [ { field: "Name", title: "Name", width: "110px" }, { field: "Description", title: "Amount", width: "110px", aggregates: ["sum"], groupFooterTemplate: "Sum: #= sum # " } ] }); } $(originalGrid).kendoDraggable({ filter: "tr", hint: function (e) { var item = $('<div class="k-grid k-widget" style="background-color: DarkOrange; color: black;"><table><tbody><tr>' + e.html() + '</tr></tbody></table></div>'); return item; }, group: "gridGroup1", }); var currentDataItem = null; function getItemByUid(uid, currentUid, data) { for (let index = 0; index < data.length; index++) { const element = data[index]; if (element.uid == currentUid) { currentDataItem = element; return false; } else { if (element.items) { getItemByUid(element.uid, currentUid, element.items); } } } } grid2.kendoDropTarget({ drop: function (e) { var uid = e.draggable.currentTarget.data("uid"); var dataItem = getItemByUid(uid, uid, dataSource1.data()); dataSource2.add(currentDataItem); }, group: "gridGroup1", }); }); <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Kendo UI Snippet</title> <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.common.min.css"/> <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.rtl.min.css"/> <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.silver.min.css"/> <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.mobile.all.min.css"/> <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="https://kendo.cdn.telerik.com/2018.1.221/js/kendo.all.min.js"></script> </head> <body> <div> <div style="width:50%;float:left" class="dragGrid"> <div id="originalGrid"></div> </div> <div style="width:50%;float:right" > <div id="grid2"></div> </div> </div> </body> </html>
You need to handle the drop target for the detail grids as well. Use the - almost - same code for kendoDropTarget to your detail grid: gridDetail.kendoDropTarget({ drop: function (e) { var uid = e.draggable.currentTarget.data("uid"); var dataItem = getItemByUid(uid, uid, dataSource1.data()); $(e.dropTarget).data("kendoGrid").dataSource.add(currentDataItem); }, group: "gridGroup1", }); Demo
javascript function not call in document.ready
I have two functions that make two combobox with jqwidgets libraries. two functions are mostly like each other. I call them in $(document).ready(function (), but first function is work well and the second not even call. I put the codes those in one function, but the second part never run. function f1() { var url2 = "/autosuggest/JsonOrigins.aspx"; var source2 = { datatype: "json", datafields: [{ name: 'id' }, { name: 'name' }], url: url2, async: false }; var dataAdapter2 = new $.jqx.dataAdapter(source2); // Create a jqxComboBox $("#originsjqxWidget").jqxComboBox({ source: dataAdapter2, multiSelect: true, displayMember: "name", valueMember: "id", width: 145 }); $("#arrow").jqxButton({}); $("#arrow").click(function () { $("#originsjqxWidget").jqxComboBox({ showArrow: false }); }); $("#originsjqxWidget").on('change', function (event) { var items = $("#originsjqxWidget").jqxComboBox('getSelectedItems'); var selectedItems = "Selected Items: "; $.each(items, function (index) { selectedItems += this.label; if (items.length - 1 != index) { selectedItems += ", "; } }); $("#log").text(selectedItems); }); }; function f2() { var url = "/autosuggest/JsonTag.aspx"; var source = { datatype: "json", datafields: [{ name: 'id' }, { name: 'name' }], url: url, async: false }; var dataAdapter = new $.jqx.dataAdapter(source); $("#categoriesjqxWidget").jqxComboBox({ source: dataAdapter, multiSelect: true, displayMember: "name", valueMember: "id", width: 145 }); $("#arrow").jqxButton({}); $("#arrow").click(function () { $("#jqxComboBox").jqxComboBox({ showArrow: false }); }); $("#categoriesjqxWidget").on('change', function (event) { var items = $("#categoriesjqxWidget").jqxComboBox('getSelectedItems'); var selectedItems = "Selected Items: "; $.each(items, function (index) { selectedItems += this.label; if (items.length - 1 != index) { selectedItems += ", "; } }); $("#log").text(selectedItems); }); } $(document).ready(function () { f1(); f2(); });
Remove the ; after your first function.
try this var source2 = { datatype: "json"; datafields: [{ name: 'id' }, { name: 'name' }], url: url2, async: false };
I think you have an extra ; at the end of function f1 function f1(){ ... if (items.length - 1 != index) { selectedItems += ", "; } }); $("#log").text(selectedItems); }); };
Kendo Grid equivalent of onEditComplete
Is there an event equivalent to onEditComplete for Kendo Grid where the event fires only after the content of the cell has been edited? Documentation mentions "edit" event, but this fires as soon as the cell goes into edit mode (So this is equivalent to onBeginEdit). The closest event with the desired behavior I found was the "save" event, but this event only fires when the content of the cell has been changed. I want an event that fires as soon as the cell goes out of the edit mode. The grid's editmode is set to incell.
Use the Save event (fired when the focus is moved outside of the cell being edited and before the cell is closed) http://www.kendoui.com/forums/kendo-ui-web/grid/is-there-an-event-that-first-after-a-user-edits-a-cell-but-before-they-save-in-a-grid-with-batch-edit-and-incell-editing-.aspx.
So due to the comment i've removed my previous answer - using the blur event on the input boxes (or other elements) seems to work : On the grid.edit event, use jquery to bind to the textbox (or any other inline edit control)'s blur event which is fired when focus is lost. Append this to the grid definition...and obviously replace the alert with your code. edit: function (e) { alert('Edit Fired'); $('input.k-input.k-textbox').blur(function () { alert('blur event called'); }); }, I've tested this by modifying the sample inline edit code here My full local source of the edit - see only the edit event on the grid def: <div id="example" class="k-content"> <div id="grid"></div> <script> $(document).ready(function () { var crudServiceBaseUrl = "http://demos.kendoui.com/service", dataSource = new kendo.data.DataSource({ transport: { read: { url: crudServiceBaseUrl + "/Products", dataType: "jsonp" }, update: { url: crudServiceBaseUrl + "/Products/Update", dataType: "jsonp" }, destroy: { url: crudServiceBaseUrl + "/Products/Destroy", dataType: "jsonp" }, create: { url: crudServiceBaseUrl + "/Products/Create", dataType: "jsonp" }, parameterMap: function (options, operation) { if (operation !== "read" && options.models) { return { models: kendo.stringify(options.models) }; } } }, batch: true, pageSize: 20, schema: { model: { id: "ProductID", fields: { ProductID: { editable: false, nullable: true }, ProductName: { validation: { required: true } }, UnitPrice: { type: "number", validation: { required: true, min: 1 } }, Discontinued: { type: "boolean" }, UnitsInStock: { type: "number", validation: { min: 0, required: true } } } } } }); $("#grid").kendoGrid({ dataSource: dataSource, pageable: true, height: 430, toolbar: ["create"], // added in hook to here to bind to edit element events. // blur is fired when an element loses focus edit: function (e) { alert('Edit Fired'); $('input.k-input.k-textbox').blur(function (e) { alert('blur event called'); }); }, columns: [ "ProductName", { field: "UnitPrice", title: "Unit Price", format: "{0:c}", width: "100px" }, { field: "UnitsInStock", title: "Units In Stock", width: "100px" }, { field: "Discontinued", width: "100px" }, { command: ["edit", "destroy"], title: " ", width: "172px" }], editable: "inline" }); }); </script> </div>
Why are you not using the "blur" event? http://www.kendoui.com/forums/ui/window/possible-to-close-window-when-it-loses-focus-.aspx $("#window").blur(function(){ if ($(document.activeElement).closest(".k-window").length == 0) { $("#window").data("kendoWindow").close(); } }); http://api.jquery.com/blur/
Have you tried the Change Event "change Fired when the user selects a table row or cell in the grid." Example - get the selected data item(s) when using cell selection <div id="grid"></div> <script> function grid_change(e) { var selectedCells = this.select(); var selectedDataItems = []; for (var i = 0; i < selectedCells.length; i++) { var dataItem = this.dataItem(selectedCells[i].parentNode); if ($.inArray(dataItem, selectedDataItems) < 0) { selectedDataItems.push(dataItem); } } // selectedDataItems contains all selected data items } $("#grid").kendoGrid({ columns: [ { field: "name" }, { field: "age" } ], dataSource: [ { name: "Jane Doe", age: 30 }, { name: "John Doe", age: 33 } ], selectable: "multiple, cell" }); var grid = $("#grid").data("kendoGrid"); grid.bind("change", grid_change); </script>
Rally Tag Cloud
I found some code on GitHub (https://github.com/RallyCommunity/TagCloud) for displaying a TagCloud in Rally. Conceptually it looks great but I cannot seem to get it to work and wondered if there were any Rally JavaScript experts out there who could take a quick look. I modified it slightly as the URL for the Analytics was incorrect (according to the docs) and the API's were hard coded to depreciated versions so I updated those. I'm not a JavaScript expert. When I run this it doesn't find any Tags against stories. When I run this in Chrome debugging mode I can take the URL and execute it in my browser but it also does not come back with any Tags. It comes back with a full result response from Analytics, but has no tags and I know there are tags against stories in the selected project. Any ideas from anyone? <!DOCTYPE html> <html> <head> <title>TagCloud</title> <script type="text/javascript" src="/apps/2.0p/sdk.js"></script> <script type="text/javascript"> Rally.onReady(function() { Ext.define('CustomApp', { extend: 'Rally.app.App', componentCls: 'app', layout: 'border', items: [ { title: 'Tag Cloud', xtype: 'panel', itemId: 'cloud', region: 'west', width: '30%', collapsible: true, bodyStyle: 'padding:15px', listeners: { 'afterRender': function(el) { setTimeout(function() { el.setLoading(); }, 500);}} // needs a little delay }, { title: '<<< Select a tag from the Tag Cloud', xtype: 'panel', itemId: 'grid', region: 'center', width: '70%', collapsible: false } ], tagMap : [], maxFont : 24, // largest desired font size minFont : 8, // and smallest _renderTag : function renderHandler(tagLabel) { tagLabel.getEl().on('click',this._tagSelected, this); }, // does the actual building of the cloud from 'tagMap' _buildCloud: function(app, response) { //title: '<<< Select a tag from the Tag Cloud - Building', var i, tag; for (i=0;i<response.Results.length;i++) { tag = response.Results[i]; if(typeof app.tagMap[tag.ObjectID] !== "undefined") { app.tagMap[tag.ObjectID].Name = tag._refObjectName; } } if(response.StartIndex+response.PageSize < response.TotalResultCount) { app._queryForTagNames(response.StartIndex+response.PageSize, app, app._buildCloud); } else { if(app.tagMap.length === 0) { tag = new Ext.form.Label({ id: 'tagNone', text: ' No tagged Stories found ' }); app.down('#cloud').add(tag); } else { var minFrequency = Number.MAX_VALUE; var maxFrequency = Number.MIN_VALUE; var tuples = []; for (var x in app.tagMap) { if (app.tagMap.hasOwnProperty(x)) { tuples.push([x, app.tagMap[x]]); if(app.tagMap[x].count > maxFrequency) { maxFrequency = app.tagMap[x].count; } if(app.tagMap[x].count < minFrequency) { minFrequency = app.tagMap[x].count; } } } tuples.sort(function(a,b) { a = a[1]; b = b[1]; return a.Name > b.Name ? 1 : a.Name < b.Name ? -1 : 0 ;}); for (i = 0; i < tuples.length; i++) { var ftsize = ((tuples[i][1].count-minFrequency)*(app.maxFont-app.minFont) / (maxFrequency-minFrequency)) + app.minFont; tag = new Ext.form.Label({ id: 'tag'+tuples[i][0], text: ' ' + tuples[i][1].Name + ' ', overCls: 'link', style:"font-size: "+ftsize+"pt;", listeners: { scope: app, render: app._renderTag } }); app.down('#cloud').add(tag); } } app.getComponent('cloud').setLoading(false); } }, // collects the _queryForTags responses and calls _queryForTagNames when it has them all _buildTagMap: function(app, response) { for (var i=0;i<response.Results.length;i++) { var ent = response.Results[i]; for (var j=0; j < ent.Tags.length; j++) { var tag = ent.Tags[j]; var mapent = app.tagMap[tag]; if(typeof mapent === "undefined") { mapent = { count: 1 }; } else { mapent.count++; } app.tagMap[tag] = mapent; } } if(response.StartIndex+response.PageSize < response.TotalResultCount) { app._queryForTags(response.StartIndex+response.PageSize, app, app._buildTagMap); } else { app._queryForTagNames(0, app, app._buildCloud); } }, // get a list of the tags from the Lookback API, iterating if necessary (see _buildTagMap) _queryForTags: function(start, app, callback) { var params = { find: "{'Tags':{'$exists':true}, '__At':'current', '_Type':'HierarchicalRequirement', '_ProjectHierarchy':"+ this.getContext().getProject().ObjectID +" }", fields: "['Tags']", pagesize: 20000, start: start }; Ext.Ajax.request({ url: 'https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/'+ this.context.getWorkspace().ObjectID + '/artifact/snapshot/query.js', method: 'GET', params: params, withCredentials: true, success: function(response){ var text = response.responseText; var json = Ext.JSON.decode(text); callback(app, json); } }); }, // once all the tags have been collected, get a list of the tag names from the WSAPI, iterating if necessary (see _buildCloud) _queryForTagNames: function(start, app, callback) { Ext.Ajax.request({ url: 'https://rally1.rallydev.com/slm/webservice/1.41/tag.js', method: 'GET', params: { fetch: "ObjectID", pagesize: 200, "start": start}, withCredentials: true, success: function(response){ callback(app, Ext.JSON.decode(response.responseText).QueryResult); } }); }, _queryForStories: function(tagOid) { Ext.create('Rally.data.WsapiDataStore', { model: 'UserStory', autoLoad: true, fetch: ['Rank', 'FormattedID', 'Name', 'ScheduleState'], filters: [{ property:'Tags', operator: '=', value: "tag/" + tagOid }], sorters: [{ property: 'Rank', direction: 'ASC' }], listeners: { load: this._onDataLoaded, scope: this } }); }, _tagSelected: function(app, elem) { this.getComponent('grid').setLoading(); this._queryForStories(elem.id.substring(3)); // cheesy, id is "tag"+tagOid, we need the oid this.tagName = elem.innerText; }, _onDataLoaded: function(store, data) { var records = [], rankIndex = 1; Ext.Array.each(data, function(record) { records.push({ Ranking: rankIndex, FormattedID: record.get('FormattedID'), Name: record.get('Name'), State: record.get('ScheduleState') }); rankIndex++; }); var customStore = Ext.create('Rally.data.custom.Store', { data: records, pageSize: 25 }); if(!this.grid) { this.grid = this.down('#grid').add({ xtype: 'rallygrid', store: customStore, columnCfgs: [ { text: 'Ranking', dataIndex: 'Ranking' }, { text: 'ID', dataIndex: 'FormattedID' }, { text: 'Name', dataIndex: 'Name', flex: 1 }, { text: 'State', dataIndex: 'State' } ] }); } else { this.grid.reconfigure(customStore); } this.getComponent('grid').setTitle('Stories tagged: ' + this.tagName); this.getComponent('grid').setLoading(false); }, launch: function() { this._queryForTags(0, this, this._buildTagMap); } }); Rally.launchApp('CustomApp', { name: 'TagCloud' }); }); </script> <style type="text/css"> .app { } .link { color: #066792; cursor: pointer; } </style> </head> <body></body> </html>
The code was out-of-date with respect to the most-recent LBAPI changes - specifically the use of _Type vs _TypeHierarchy and of course, the url, as you'd already discovered. Please pick up the changes and give it a whirl.