Persist State In Kendo MVC Grid With Custom Command Columns? - kendo-grid

Having issues persisting state in mvc grid when using custom command columns. Here is the grid's wrapper
#(Html.Kendo().Grid < Weighmaster_Web.Data.Entity.Destination > ()
.Name("grid")
.Columns(columns => {
columns.Bound(c => c.Description);
columns.Bound(c => c.CODE);
columns.Command(c => {
if (bUpdate) c.Custom("Edit").Click("editItem");
if (bDelete) c.Custom("Delete").Click("deleteItem");
}).Width(175);
})
.Scrollable()
.Groupable()
.Sortable()
.ToolBar(toolbar => {
if (bCreate) {
toolbar.Create().HtmlAttributes(new {
id = "addDestination"
}).Text("Add Destination");
}
})
.ToolBar(t => t.Excel())
.Excel(excel => excel
.FileName("Destinations.xlsx")
.Filterable(true)
.AllPages(true)
.ProxyURL(Url.Action("Excel_Export_Save", "MaterialTransaction"))
)
.Filterable(filterable => filterable.Extra(false))
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error_handler"))
.Read(read => read.Action("DestinationIndex", "Destination").Type(HttpVerbs.Post))
.Model(model => model.Id(p => p.Id))
.PageSize(20)
.Create(update => update.Action("DestinationSave", "Destination").Type(HttpVerbs.Post)))
)
Here i define a click event handler in the wrapper for both edit and delete buttons. i am using custom commands so that i may define custom edit template.
When you look at the actual jquery for this wrapper , i can see the event handler defined.
Then when you leave the page , this code is ran to save the grid's state in a cookie :
$(window).unload(function () {
var grid = $("#grid").data("kendoGrid");
var dataSource = grid.dataSource;
var state = {
columns: grid.columns,
page: dataSource.page(),
pageSize: dataSource.pageSize(),
sort: dataSource.sort(),
filter: dataSource.filter(),
group: dataSource.group()
};
$.cookie(username + "DestinationGridState", JSON.stringify(state), { expires: 365 });
})
The grid's state is read from cookie in $(document).ready like this :
$(document).ready(function () {
var grid = $("#grid").data("kendoGrid");
var toolbar = $("#grid").find(".k-grid-toolbar").html();
var state = $.cookie(username + "DestinationGridState");
if (state) {
state = JSON.parse(state);
var options = grid.options;
options.columns = state.columns;
options.dataSource.page = state.page;
options.dataSource.pageSize = state.pageSize;
options.dataSource.sort = state.sort;
options.dataSource.filter = state.filter;
options.dataSource.group = state.group;
if (grid) {
grid.destroy();
//grid.wrapper.html("");
}
$("#grid").empty().kendoGrid(options).find(".k-grid-toolbar").html(toolbar);
}
});
After the grid's state is read from the cookie, no click event handler is defined for the custom edit command button. So , i guess my question is; How do i correctly save the state of the grid so that my custom command buttons will retain their event handlers?

As mentioned in the kendo documentation:
JSON.stringify() cannot serialize function references (e.g. event
handlers), so if stringification is used for the retrieved Grid state,
all configuration fields, which represent function references, will be
lost.
I once had the same issue, when I was trying to save the filters values in session. I was doing just like you, but then I realized that I didn't need to restore the columns state. If you remove the row options.columns = state.columns;
the custom command will work just as expected.
Hope it helps.

I had a similar problem. After loading the settings my custom delete button stopped working. This was the solution that I came up with:
Save the original grid options. After parsing the saved settings, restore the original values, in this case the column where my delete buttons was placed.
Hope this helps.
$("#Grid").on("click",
".loadsetting",
function(e) {
var grid = $("#Grid").data("kendoGrid");
var originalOptions = grid.options; // Save original options
e.preventDefault();
var options = localStorage["msettings"];
if (options) {
var parsedOptions = JSON.parse(options);
parsedOptions.toolbar = [
{
template: $("#toolbarTemplate").html()
}
];
// Restore values
parsedOptions.columns[30] = originalOptions.columns[30];
grid.setOptions(parsedOptions);
}
});

Related

Mapping from JSON Get Request. Undefined

I am trying to connect to the USDA Food Central database using an API.
let uri = encodeURI(`https://api.nal.usda.gov/fdc/v1/foods/search?api_key=${MY_API_KEY}&query=${search}`)
I want to use the API to map certain fields.
class AddFoodItemList extends Component {
static contextType = AddFoodContext;
render() {
const listItems = this.context.FoodSearch.map((foods) =>
<FoodItem
key={foods.brandOwner}
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
);
return (
<div id="AddFoodItemList">
{listItems}
</div>
);
}
}
export default AddFoodItemList;
The returned JSON is this screenshot attached:
Returned JSON
I am getting an error, TypeError: Cannot read property 'map' of undefined.
Why do you think this is the case? Any sort of help or suggestions are appreciated!
You are attempting to access a property FoodSearch on the value of your AddFoodContext provider. The error tells you that this property is undefined. If the object in your screenshot is the value of your context then you want to access the property foods instead. This is an array whose elements are objects with properties brandOwner and fdcId.
On your first render this data might now be loaded yet, so you should default to an empty array if foods is undefined.
It's honestly been a long time since I've used contexts in class components the way that you are doing it. The style of code is very dated. How about using the useContext hook to access the value?
const AddFoodItemList = () => {
const contextValue = useContext(AddFoodContext);
console.log(contextValue);
const listItems = (contextValue.foods || []).map((foods) => (
<FoodItem
key={foods.fdcId} // brandOwner isn't unique
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
));
return <div id="AddFoodItemList">{listItems}</div>;
};
Here's a complete code to play with - Code Sandbox Link
const MY_API_KEY = "DEMO_KEY"; // can replace with your actual key
const getUri = (search) => `https://api.nal.usda.gov/fdc/v1/foods/search?api_key=${MY_API_KEY}&query=${encodeURIComponent(search)}`;
const AddFoodContext = createContext({});
const FoodItem = ({ brandOwner, fdcId }) => {
return (
<div>
<span>{fdcId}</span> - <span>{brandOwner}</span>
</div>
);
};
const AddFoodItemList = () => {
const contextValue = useContext(AddFoodContext);
console.log(contextValue);
const listItems = (contextValue.foods || []).map((foods) => (
<FoodItem
key={foods.fdcId} // brandOwner isn't unique
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
));
return <div id="AddFoodItemList">{listItems}</div>;
};
export default () => {
const [data, setData] = useState({});
useEffect(() => {
fetch(getUri("cheese"))
.then((res) => res.json())
.then(setData)
.catch(console.error);
}, []);
return (
<AddFoodContext.Provider value={data}>
<AddFoodItemList />
</AddFoodContext.Provider>
);
};

Monthpicker in Kendo UI for MVC works but sets current month when changing focus from grid cell

I have set up a "monthpicker" in a cell of a Kendo grid. The picker works fine and the column shows MMMM yyyy (e.g. April 2019)
However, when I move focus from the cell it doesn't set the cell as dirty and reverts back to current month and year.
Editor template (called Month.cshtml)
#model DateTime?
#{string[] formats = { "MMMM yyyy" }; }
#(Html.Kendo().DatePickerFor(m => m)
.Name("monthpicker")
.Start(CalendarView.Year)
.Depth(CalendarView.Year)
.Format("MMMM yyyy")
.DateInput()
.Culture("en-US")
.ParseFormats(formats)
.HtmlAttributes(new { style = "width: 100%", title = "monthpicker" })
)
Model:
[Display(Name = "Month", ResourceType = typeof(Resources.Resources))]
[UIHint("Month")]
public DateTime Month { get; set; }
View
#(Html.Kendo().Grid<GrindrodDataCapture.Models.MonthlyOceanPlan>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.Month).Format("{0:MMMM yyyy}");
//etc
})
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Pageable()
.Sortable(sortable =>
{
sortable.SortMode(GridSortMode.SingleColumn);
})
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error_handler"))
.Sort(p => { p.Add("Month").Descending(); })
.Model(model => model.Id(p => p.ID))
.Read(read => read.Action("MonthlyOceanPlans_Read", "MonthlyOceanPlanGrid"))
.Create(create => create.Action("MonthlyOceanPlans_Create", "MonthlyOceanPlanGrid"))
.Update(update => update.Action("MonthlyOceanPlans_Update", "MonthlyOceanPlanGrid"))
.Destroy(destroy => destroy.Action("MonthlyOceanPlans_Destroy", "MonthlyOceanPlanGrid"))
)
I got a support response from Telerik which fixed it :)
"Hi Evan,
I noticed that the name of the date picker editor does not match the name of the field it edits. The editor is bound to its corresponding field of the model using the name setting. Currently the binder will try to bind the editor to the monthpicker field of the model. However, the actual field in the model is called Month.
Furthermore, when using a WidgetFor helper, you can omit the name configuration as the name is automatically set to the name of the field.
Could you pleas remove the Name configuration of the editor and let me know if the editor binds as expected?"

Telerik UI Grid pass ID to Kendo Context Menu

I've got a simple context menu that I need to be able wire into a Grid. This context menu needs to allow a user to navigate based on the ID of the grid record it's associated to.
I'm currently trying to pass an HTML Data object, but it doesn't seem to be working as expected.
Does anyone know how to extrapolate the ID?
Here is a self contained example of what I'm trying to achieve.
#model IList<EmployeeModel>
<script>
$(document).ready(function () {
setTimeout(function () {
var menu = $("#adminContextMenu"),
original = menu.clone(true);
original.find(".k-state-active").removeClass("k-state-active");
var initMenu = function () {
menu = $("#adminContextMenu").kendoContextMenu({
orientation: 'vertical',
alignToAnchor: true,
filter: ".adminContextMenu",
showOn: "click",
animation: {
open: {
effects: "fadeIn"
},
duration: 250
},
select: function (e) {
console.log(e);
}
});
};
initMenu();
}, 0);
});
</script>
<ul id="adminContextMenu">
<li>Super Long Context Option One</li>
<li class="k-separator"></li>
<li>Alpha</li>
<li>Bravo</li>
<li>Charlie</li>
</ul>
<div id="clientsDb">
#(Html.Kendo().Grid(Model)
.Name("employeeGrid")
.Columns(columns =>
{
columns.Bound(user => user.FullName);
columns.Bound(user => user.UserGUID)
.Width(40)
.ClientTemplate("<span><img src='" + #Web_Helpers.StratosphereImageUrl("#Pencil_Icon ") + "' Title='Administration' Class='adminContextMenu' Data-Guid='#= UserGUID #' /></span>")
.Title(" ");
})
.HtmlAttributes(new {style = "height: 380px;"})
.Scrollable()
.Groupable()
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax().ServerOperation(false))
)
</div>
Providing your ClientTemplate has a Data attribute
.ClientTemplate("<span><img src='img/settings.png' Title='Administration' Class='adminContextMenu' Data-Guid='#= UserGUID #' /></span>")
You can get that inside the select method of the kendoContextMenu
select: function (e) {
console.log(e.target.dataset.guid);
}

how to get data from JSON without using script?

i want to get data from json file without using script code!
iam using MVC4 and want to put the code in the .cshtml file, how can i do this?
( Iam using kendo function)
example:
#{
ViewBag.Title = "Home Page";
}
<div class="chart-wrapper">
#(Html.Kendo().Chart()
.Name("chart")
.Title(title => title
.Text("Share of Internet Population Growth, 2007 - 2012")
.Position(ChartTitlePosition.Bottom))
.Legend(legend => legend
.Visible(false)
)
.DataSource(dataSource=>dataSource.Read(read=>read.Url("~/")))
.Events(e => e.SeriesClick("onSeriesHover"))
.Series(series => {
series.Pie(new dynamic[] {
new {category="Asia",value=53.8,color="#9de219"},
new {category="Europe",value=16.1,color="#90cc38"},
new {category="LatinAmerica",value=11.3,color="#068c35"},
new {category="Africa",value=9.6,color="#006634"},
new {category="MiddleEast",value=5.2,color="#004d38"},
new {category="NorthAmerica",value=3.6,color="#033939"}
})
.Labels(labels => labels
.Template("#= category #: #= value#%")
.Background("transparent")
.Visible(true)
.Color("Red")
)
.StartAngle(150);
})
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0}%")
)
)
<script>
function onSeriesClick(e) {
alert(kendo.format("Series click :: {0} ({1}): {2}",
e.series.name, e.category, e.value));
}
</script>
</div>
i have use
.DataSource(dataSource=>dataSource.Read(read=>read.Url("~/")))
but not working
Try like this,
Example
View
#(Html.Kendo().Chart<Model.DashboardPieChartModel>()
.Name("PieChartPopup")
.Events(events => events.DataBound("onDataBound"))
.Legend(legend => legend
.Visible(false)
)
.DataSource(ds =>
{
ds.Read(read => read.Action("Read_PieChart", "Dashboard"));
}
)
.Series(series =>
{
series.Pie(
model => model.Percentage,
model => model.Service, null, null
).Labels(labels => labels
.Visible(true)
.Template("${ category } - ${ value }%")
).Overlay(ChartPieSeriesOverlay.None);
})
.Tooltip(tooltip => tooltip
.Visible(true)
.Template("${ category } - ${ value }%")
)
)
Controller
public JsonResult Read_PieChart()
{
//Whatever you do here
return Json(return your data);
}
Read this link: http://demos.kendoui.com/dataviz/pie-charts/remote-data.html

kendo grid export gives Input string was not in a correct format error

When im trying to export kendo resault into pdf i get this error "Input string was not in a correct format."
here is my code :
#(Html.Kendo().Grid((IEnumerable<A.Models.MyViewModel>)ViewBag.myviewmodelbag) //Bind the grid to ViewBag.Products
.Name("List")
.Columns(columns =>
{
columns.Bound(myviewmodelbag => myviewmodelbag.BaseData.Type);
columns.Bound(myviewmodelbag => myviewmodelbag.BaseData.Title);
})
.Pageable() // Enable paging
.Sortable() // Enable sorting
.Groupable()
.Filterable()
.Events(ev => ev.DataBound("onDataBound"))
.ToolBar(toolBar =>
toolBar.Custom()
.Text("Export To PDF")
.HtmlAttributes(new { id = "export" })
.Url(Url.Action("Export", "MyViewModel", new { page = 1, pageSize = "~", filter = "~", sort = "~" }))
)
<script type="text/javascript">
function onDataBound(e) {
var grid = $('#List').data('kendoGrid');
// ask the parameterMap to create the request object for you
var requestObject = (new kendo.data.transports["aspnetmvc-server"]({ prefix: "" }))
.options.parameterMap({
page: grid.dataSource.page(),
sort: grid.dataSource.sort(),
filter: grid.dataSource.filter()
});
// Get the export link as jQuery object
var $exportLink = $('#export');
// Get its 'href' attribute - the URL where it would navigate to
var href = $exportLink.attr('href');
// Update the 'page' parameter with the grid's current page
href = href.replace(/page=([^&]*)/, 'page=' + requestObject.page || '~');
// Update the 'sort' parameter with the grid's current sort descriptor
href = href.replace(/sort=([^&]*)/, 'sort=' + requestObject.sort || '~');
// Update the 'pageSize' parameter with the grid's current pageSize
href = href.replace(/pageSize=([^&]*)/, 'pageSize=' + grid.dataSource._pageSize);
//update filter descriptor with the filters applied
href = href.replace(/filter=([^&]*)/, 'filter=' + (requestObject.filter || '~'));
// Update the 'href' attribute
$exportLink.attr('href', href);
}
</script>
and my controller is like this :
public FileResult Export([DataSourceRequest]DataSourceRequest request)
{
IEnumerable products = db.AA.ToDataSourceResult(request).Data;
now the problem is if i use exatcly as above i get the error but if hardcode the value like this:
.Url(Url.Action("Export", "MyViewModel", new { page = 1, pageSize = "", filter = "", sort = "" }))
it works without error but the controller only get the page an other value will be null.
also i tried to add "grid_Page , ... " to all of parameter but none works
Ok my bad , i fixed it !
since im using server side to populate the grid , the js event part cant be called :
function onDataBound(e) {
var grid = $('#List').data('kendoGrid');
and after i changed to this :
$(document).ready(function () {
var grid = $('#List').data('kendoGrid');
and removed this line :
.Events(ev => ev.DataBound("onDataBound"))
now it works fine.