Ajax from telerik mvc treeviewitem - asp.net-mvc-3

I am trying to work with telerik MVC TreeView. i have three levels in the treeview. On clicking on the 3rd level tree view item, i need to load a view without page refresh.
I tried to use item.Url. But the entire page refreshes and treeview disappears.
I have a treeview in "Menu" partial view and it is called by _layout.cshtml
#(Html.Telerik().TreeView()
.Name("TreeView")
.ShowLines(false)
.BindTo(Model, mappings =>
{
mappings.For<AdminTool.Web.Models.ProjectModel>(binding => binding
.ItemDataBound((item, project) =>
{
item.Text = project.Name;
})
.Children(project => project.ApiModels));
mappings.For<AdminTool.Web.Models.ApiModel>(binding => binding
.ItemDataBound((item, api) =>
{
item.Text = api.Name;
item.Value = api.Id;
})
.Children(api => api.ApiMethods));
mappings.For<AdminTool.Web.Models.ApiMethodModel>(binding => binding
.ItemDataBound((item, apimethod) =>
{
item.Text = apimethod.Name;
item.Url = Url.Action("ApiMethodById", "ApiMethod", new { id= apimethod.Id });
}));
})
)
Thanks in advance!

I would recommend using jQuery for this. What you would do it the following:
1) Have whatever location you want this to load to be placed inside a tag with some id on it (e.g. 'myDiv')
2) Write a jQuery function that on the click of you third level item (e.g. apiMethodID) to run a function that will call the controller action that you're looking for, and to post that to myDiv. You might want to try something like the following:
$(document).ready(function()){
$('#apiMethodID').click(function(){
var value = $('#apiMethodID').val();
var url = "/ApiMethod/ApiMethodById";
$.get(url, { apiMethodId: value }, function(data){
$('#myDiv').html(data);
});
})
}
$.get here will actually call your controller method. You should be able to debug that fact to make sure that it works.
3) Make sure that the controller action that you going to returns a PartialView, otherwise you're going to re-render the whole page inside of that div.
Let me know if that works.

Related

KendoUI for jQuery - Chart dataBound event does not work

Here's a simplified example of my data:
[{"Name": "Bob", "Count":3}, {"Name": "Steve", "Count":5}]
What I want is a chart title of: Total FOO: 8. So the title must be based on the data. The data is AJAX and this is an ASP.NET MVC application.
In my CSHTML I have:
.DataSource(ds => ds.Read(read => read.Action("MeMethodName", "MyControllerName")))
.Events(events => events.DataBound("setChartTitle('chartName', 'Total FOO')"))
Here's the crazy hack I had to do:
function setChartTitle(name, title) {
let chart = $("#" + name).data("kendoChart");
if (chart) {
let ds = chart.dataSource;
let total = 0;
for (let i = 0; i < ds.data().length; i++) {
total += ds.data()[i].Count;
}
chart.options.title.text = title + ": " + total;
chart.refresh();
} else if (arguments.length < 3) {
// Data source was not found and this was initiated through Kendo. Wait and try again but only once
setTimeout(function () {
sumEntityCount(name, title, "stop");
}, 500);
}
}
This is really bad.
Accessing the kendoChart returns undefined, yet the chart itself called this. This is why I need to check if (chart) above.
This leads to a hacky ELSE block I added where I can call this again with a 500 ms delay. This alone is a bug as 500ms is a random number and may not be enough. I can't ship like this.
To prevent recursion I call the same function with a different parameter.
If the values are found, then I can't just set the chart options. I need to call refresh which redraws everything.
Questions:
Why is the kendoChart data undefined initially? Why has Telerik called dataBound when there's nothing there?!
Isn't there a dataBinding event? I don't want to do this after the fact nor do I want to refresh the whole thing.
The chart itself is passed in when you declare a basic function without calling it:
.events(events => events.Render("someFunction"))
Then declare your function:
function someFunction(sender) {
// sender.chart is what I want
}
But you cannot pass any arguments here. Which means I can't use it.
The hack is to do the following:
.Events(events => events.Render("function(sender) { someFunction(sender, 'param1', 'param2', 'param3'); }"))
This gives it an actual function instead of calling a function. Kendo passes in the sender as expected and you can pass it along with new parameters to your JavaScript.
I also switched to using Render instead of DataBound.

How to mark Kendo Grid's cell as edited?

I'm dynamically editing some fields using JavaScript. But the problem is Kendo's dataSource doesn't recognize them as changed cells.
Grid's edit mode is InCell.
This is my current JavaScript code:
tablesGrid.tbody.find("input[type='checkbox']").each(function () {
$(this).on('change', function () {
var isChecked = $(this).prop('checked');
var dataItem = tablesGrid.dataItem($(this).closest('tr'));
var currentTr = $(this).closest('tr');
var i = $('td:visible', currentTr).index($(this).closest('td'));
var head = tablesGrid.thead.find('th:visible')[i];
var headName = $(head).prop('dataset').field;
tablesGrid.editCell($(this).closest('td'));
dataItem[headName] = isChecked;
tablesGrid.refresh();
});
});
And if you're wondering about this code, I should note that I'm using client template to show checkboxes. But I don't want the user to double click the cell for editing, once to put it in the edit mode, and another one to change the checkbox. I'm not sure if I'm using the right solution, but the JS code works for sure. If I click in the cell and put it in the edit mode, I'll see the change.
#(Html.Kendo().Grid<grid>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(x => x.field)
.ClientTemplate("<input type='checkbox' class='checkbox-inline' #=field? checked='checked':''# />")
.EditorTemplateName("Checkbox");
Well, the best solution I came up with is to put the cell in edit mode when mouse enters that cell! So instead of the entire JS code in the question, I simply use this.
tablesGrid.bind('dataBound', function () {
tablesGrid.tbody.find('td').each(function () {
$(this).mouseenter(function () {
tablesGrid.editCell(this);
});
});
});
Please let me know if you have any better or more efficient way to use editable
checkboxes inside a Grid.

Reloading/refreshing Kendo Grid

How to reload or refresh a Kendo Grid using Javascript?
It is often required to reload or refresh a grid after sometime or after a user action.
You can use
$('#GridName').data('kendoGrid').dataSource.read(); <!-- first reload data source -->
$('#GridName').data('kendoGrid').refresh(); <!-- refresh current UI -->
I never do refresh.
$('#GridName').data('kendoGrid').dataSource.read();
alone works for me all the time.
In a recent project, I had to update the Kendo UI Grid based on some calls, that were happening on some dropdown selects. Here is what I ended up using:
$.ajax({
url: '/api/....',
data: { myIDSArray: javascriptArrayOfIDs },
traditional: true,
success: function(result) {
searchResults = result;
}
}).done(function() {
var dataSource = new kendo.data.DataSource({ data: searchResults });
var grid = $('#myKendoGrid').data("kendoGrid");
dataSource.read();
grid.setDataSource(dataSource);
});
Hopefully this will save you some time.
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
Not a single one of these answers gets the fact that read returns a promise, which means you can wait for the data to load before calling refresh.
$('#GridId').data('kendoGrid').dataSource.read().then(function() {
$('#GridId').data('kendoGrid').refresh();
});
This is unnecessary if your data grab is instant/synchronous, but more than likely it's coming from an endpoint that won't return immediately.
If you do not want to have a reference to the grid in the handler, you can use this code:
$(".k-pager-refresh").trigger('click');
This will refresh the grid, if there is a refresh button.
The button can be enabled like so:
[MVC GRID DECLARATION].Pageable(p=> p.Refresh(true))
Actually, they are different:
$('#GridName').data('kendoGrid').dataSource.read() refreshes the uid attributes of the table row
$('#GridName').data('kendoGrid').refresh() leaves the same uid
What you have to do is just add an event
.Events(events => events.Sync("KendoGridRefresh"))
in your kendoGrid binding code.No need to write the refresh code in ajax result.
#(Html.Kendo().Grid<Models.DocumentDetail>().Name("document")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Model(model => model.Id(m => m.Id))
.Events(events => events.Sync("KendoGridRefresh"))
)
.Columns(columns =>
{
columns.Bound(c => c.Id).Hidden();
columns.Bound(c => c.UserName).Title(#Resources.Resource.lblAddedBy);
}).Events(e => e.DataBound("onRowBound"))
.ToolBar(toolbar => toolbar.Create().Text(#Resources.Resource.lblNewDocument))
.Sortable()
.HtmlAttributes(new { style = "height:260px" })
)
And you can add the following Global function in any of your .js file. so, you can call it for all the kendo grids in your project to refresh the kendoGrid.
function KendoGridRefresh() {
var grid = $('#document').data('kendoGrid');
grid.dataSource.read();
}
In my case I had a custom url to go to each time; though the schema of the result would remain the same.
I used the following:
var searchResults = null;
$.ajax({
url: http://myhost/context/resource,
dataType: "json",
success: function (result, textStatus, jqXHR) {
//massage results and store in searchResults
searchResults = massageData(result);
}
}).done(function() {
//Kendo grid stuff
var dataSource = new kendo.data.DataSource({ data: searchResults });
var grid = $('#doc-list-grid').data('kendoGrid');
dataSource.read();
grid.setDataSource(dataSource);
});
I used Jquery .ajax to get data. In order to reload the data into current grid, I need to do the following:
.success (function (result){
$("#grid").data("kendoGrid").dataSource.data(result.data);
})
You can use the below lines
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
For a auto refresh feature have a look here
By using following code it automatically called grid's read method and again fill grid
$('#GridName').data('kendoGrid').dataSource.read();
An alternative way to reload the grid is
$("#GridName").getKendoGrid().dataSource.read();
You can always use $('#GridName').data('kendoGrid').dataSource.read();. You don't really need to .refresh(); after that, .dataSource.read(); will do the trick.
Now if you want to refresh your grid in a more angular way, you can do:
<div kendo-grid="vm.grid" id="grid" options="vm.gridOptions"></div>
vm.grid.dataSource.read();`
OR
vm.gridOptions.dataSource.read();
And don't forget to declare your datasource as kendo.data.DataSource type
I want to go back to page 1 when I refresh the grid. Just calling the read() function will keep you on the current page, even if the new results don't have that many pages. Calling .page(1) on the datasource will refresh the datasource AND return to page 1 but fails on grids that aren't pageable. This function handles both:
function refreshGrid(selector) {
var grid = $(selector);
if (grid.length === 0)
return;
grid = grid.data('kendoGrid');
if (grid.getOptions().pageable) {
grid.dataSource.page(1);
}
else {
grid.dataSource.read();
}
}
In order to do a complete refresh, where the grid will be re-rendered alongwith new read request, you can do the following:
Grid.setOptions({
property: true/false
});
Where property can be any property e.g. sortable
You may try:
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
Just write below code
$('.k-i-refresh').click();
$("#theidofthegrid").data("kendoGrid").dataSource.data([ ]);
If you are desiring the grid to be automatically refreshed on a timed basis, you can use the following example which has the interval set at 30 seconds:
<script type="text/javascript" language="javascript">
$(document).ready(function () {
setInterval(function () {
var grid = $("#GridName").data("kendoGrid");
grid.dataSource.read();
}, 30000);
});
</script>
You can also refresh your grid with sending new parameters to Read action and setting pages to what you like :
var ds = $("#gridName").data("kendoGrid").dataSource;
ds.options.page = 1;
var parameters = {
id: 1
name: 'test'
}
ds.read(parameters);
In this example read action of the grid is being called by 2 parameters value and after getting result the paging of the grid is in page 1.
The default/updated configuration/data of the widgets is set to automatically bind to an associated DataSource.
$('#GridId').data('kendoGrid').dataSource.read();
$('#GridId').data('kendoGrid').refresh();
The easiest way out to refresh is using the refresh() function.
Which goes like:
$('#gridName').data('kendoGrid').refresh();
while you can also refresh the data source using this command:
$('#gridName').data('kendoGrid').dataSource.read();
The latter actually reloads the data source of the grid. The use of both can be done according to your need and requirement.
I see that a lot of answers here suggest calling both dataSource.read and grid.refresh, however, internally the grid listens for dataSource changes and upon a change it will refresh itself. In other words executing both dataSource.read and grid.refresh will result in refreshing the grid twice, which is unnecessary. Calling just dataSource.read is enough.
common js function for refresh kendo grid
function refreshKendoGrid(id) {
var grid = $("#" + id).data("kendoGrid");
if (grid) {
grid.dataSource.read();
}
}
My solution is:
var gridObj = $('#GridName').data('kendoGrid');
gridObj.dataSource.read();
gridObj.refresh();
Works also for other object functions
$("#grd").data("kendoGrid").dataSource.read();
$('#GridName').data('kendoGrid').dataSource.read(); //first you have to read the datasource data
$('#GridName').data('kendoGrid').refresh(); // after that you can refresh

Kendo UI MVC Grid row selecting

I need to execute a History push state to some Action on Grid click...
I looked the API, and I think the Events Change its the right place to do that...
So, thats the code i´d like to put in there
"window.History.pushState(null, null," + "'" + Url.Action("Edit", "MyController") + "/' + Id);"
I used that on a similar JS Grid and works fine, but I dont know how to do that with Kendo UI MVC Wrapper...
I intend to use that directly on Grid definition, so I dont have to create any JS method... Something like that :
.Events(events => events.Change(x => "window.History.pushState..."))
Is that possible? How get the ID and declare Url.Action there?
Thanks
The docs for the "change" event have an example of how to get the data item for the selected row(s).
The MVC helper expects the string name of a JS function to be passed to events.Change() but I think you can define a function there too.
So something like:
#{
var url = Url.Action("Edit", "MyController");
}
...
.Events(events => events.Change(x => #"function (changeEvent) {
var selectedRows = this.select();
var dataItem;
var numSelectedRows = selectedRows.length;
for (var i = 0; i < numSelectedRows ; i++) {
dataItem = this.dataItem(selectedRows[i]);
selectedDataItems.push(dataItem);
window.History.pushState(null, null, """ + url + #"/"" + dataItem.Id);
}
}"))
I don't have a Kendo MVC project open in front of me to verify the syntax, but that should be pretty close, or at least get you pointed in the right direction.

how to load a partial view on button click in mvc3

I have a DDL, on its change I load a partial view _GetX. Right now I am using it like this
#Html.DropDownListFor(model => model.XId, Model.XList, "Select", new { GetUrl = Url.Action("GetX", "Route") })
I need to load this partial view on clicking a button. How do I do this?
Assuming your GetX controller action already returns the partial view:
$(function() {
$('#someButton').click(function() {
// get the DDL. It would be better to add an id to it
var ddl = $('#XId');
// get the url from the ddl
var url = ddl.attr('GetUrl');
// get the selected value of the ddl to send it to the action as well
var selectedValue = ddl.val();
// send an AJAX request to the controller action passing the currently
// selected value of the DDL and store the results into
// some content placeholder
$('#somePlaceholder').load(url, { value: selectedValue });
return false;
});
});

Resources