Kendo DropDown returning Value instead of Text - asp.net-mvc

I use the dropdown list as an EditorTemplate for a column in the grid:
#model Guid?
#(Html.Kendo().DropDownListFor(m => m)
.DataValueField("Id")
.DataTextField("Name")
.DataSource(dataSource =>
{
dataSource.Read(read => read.Action(MVC.Controller.ActionNames.ActionName_Read, MVC.Controller.Name))
.ServerFiltering(true);
})
.ValuePrimitive(true)
)
My Controller:
public virtual ActionResult ActionName_Read()
{
var applicationID = AppSettings.Id.Guid;
var return = _db.table.Where(w => w.ID == appID).Select(s => new { s.Name, Id = s.Guid});
return Json(return, JsonRequestBehavior.AllowGet);
}
My Column:
columns.Bound(c => c.Name).Filterable(f => f.UI("$.proxy(filterFunction, {field: Name})").Operators(o => o.ForString(e => e.Clear().IsEqualTo("Is equal to").IsNotEqualTo("Is not equal to")))).EditorTemplateName("EditorTemplateName");
I added .ValuePrimitive(true) and that returns the ID, but if I remove that, it returns [object object].
I have the Name and the ID return from the action, but only the name field gets populated, and it gets populated by the ID.

You can use the .ValueTemplate() property.
here is one example https://demos.telerik.com/aspnet-mvc/dropdownlist/template
.ValueTemplate("#:yourObject.Name#")

I looped into the change event of my DropDownList in the EditorTemplate and did the following:
function selectRow(name, event) {
var rowUid = $("#Name").closest("tr").attr("data-uid");
var rowItem = $("#" + name).data("kendoGrid").dataSource.getByUid(rowUid);
var currentName = event.sender._focused[0].textContent;
var currentDataSource = event.sender.dataSource._data;
for (var i = 0; i < currentDataSource.length; i++) {
if (currentDataSource[i].Name=== currentName) {
rowItem.set("Id", currentDataSource[i].Id);
rowItem.set("Name", currentDataSource[i].Name);
}
}
}

Related

How to set default value of bunch of KendoUI DropDownLists when binding to IEnumerable and using ASP.NET MVC

I am having this model (containing IEnumerable of ints) and I want to create KendoUI DropDownList for each of the elements in this IEnumerable:
public class PlayersInGameViewModel
{
public PlayersInGameViewModel()
{
this.FirstTeamPlayers = Enumerable.Range(1, 8).Select(x => 0).ToList();
}
public IList<int> FirstTeamPlayers { get; set; }
}
In my controller I have an action to provide the data for drop downs (it isn't important but I am sharing it for the sake of completeness):
public ActionResult PlayersRead()
{
var result =
this.players.All()
.Select(x => new { Name = x.FirstName + " " + x.LastName, Value = x.Id })
.OrderBy(x => x.Name)
.ToList();
result.Insert(0, new { Name = "-----------", Value = 0 });
return this.Json(result, JsonRequestBehavior.AllowGet);
}
And this is the part of my view where I am creating the DropDownLists:
#for (var i = 0; i < 8; i++)
{
#(Html.Kendo().DropDownListFor(x => x.FirstTeamPlayers[i])
.DataTextField("Name")
.DataValueField("Value")
.Filter("contains")
.MinLength(1)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("PlayersRead", "PlayersInGames");
})
.ServerFiltering(false);
})
)
<br />
}
The problem is that when I set a for one of the elements in FirstTeamPlayers I want them to be populated when loading the DropDown widget:
[HttpGet]
public ActionResult Edit(int id)
{
var viewModel = this.Mapper.Map<PlayersInGameViewModel>(this.games.GetById(id));
viewModel.FirstTeamPlayers[2] = 3;
return this.View(viewModel);
}
Here is the result as HTML:
<input data-val="true" data-val-number="The field Int32 must be a number." data-val-required="The Int32 field is required." id="FirstTeamPlayers_2_" name="FirstTeamPlayers[2]" type="text" value="3" />
<script>
jQuery(function(){jQuery("#FirstTeamPlayers_2_").kendoDropDownList({"dataSource":{"transport":{"read":{"url":"/Administration/PlayersInGames/PlayersRead"},"prefix":""},"schema":{"errors":"Errors"}},"dataTextField":"Name","filter":"contains","minLength":1,"valuePrimitive":true,"dataValueField":"Value"});});
</script>
As you can see everything seems to be correctly generated and value="3" is present in the HTML but the widget in the browser is showing the default value for all dropdowns:
There are no JavaScript errors on the console.
What am I missing? Why does KendoUI doesn't respect the given value?
EDIT:
Also all the values are loaded correctly:
Currently I am using a workaround: setting the value through the .SelectedIndex(Model.FirstTeamPlayers[i]) method in the Kendo().DropDownListFor() helper.
Here is my working view:
#for (var i = 0; i < 8; i++)
{
#(Html.Kendo().DropDownListFor(x => x.FirstTeamPlayers[i])
.DataTextField("Name")
.DataValueField("Value")
.Filter("contains")
.SelectedIndex(Model.FirstTeamPlayers[i])
.MinLength(1)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("PlayersRead", "PlayersInGames");
})
.ServerFiltering(false);
})
)
}

Kendo Grid Filter functionality with Server Operation True

I have a kendo Grid which pulls loads of data. To increase the performance i have set the ServerOperation(true), which hits the database for each pagination click to load only 20 records each time it hits.
But, kendo Grid Filter is not working when ServerOperation(true).
Here is the code.If we make ServerOperation false, the grid retrieves all the data at once which will hit the performance. Please suggest any solution to have the filter with ServerOperation true.
#(Html.Kendo().Grid<ViewModel>().Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.Id).Hidden();
columns.Bound(p => p.Number).Filterable(filterable => filterable.UI("NumberFilter")).Width("150px").Locked(true);
})
.Filterable().Sortable()
.Resizable(resizing => resizing.Columns(true))
.Reorderable(reordering => reordering.Columns(true))
.Pageable().Scrollable(scr => scr.Height(580))
.DataSource(dataSource => dataSource.Ajax().PageSize(20)
.Read(read => read.Action("LoadTransaction", ControllerName.).Data("geton"))
))
public ActionResult LoadTransaction(int clientid, string id)
{
PagingInfo gvpi = UiControls.GetGridViewPagingInfo(Request.Form);
gvpi.FilterColumns.Add(new PagingColumn() { Name = "ClientId", Value = clientId.ToString(), IsFullTextFilter = true });
gvpi.FilterColumns.Add(new PagingColumn() { Name = "Id", Value = Id, IsFullTextFilter = true });
gvpi.PageSize = 20;
var pagedResult = _contextservice.GetAllByPage(gvpi);
return UiControls.GetGridViewDataAsJson(pagedResult.GridData, pagedResult.RecordCount);
}
function geton()
{
var clientId = $('#ClientId').val();
var Id = $('#Id').val();
return { clientId: clientId, Id: divisionId }
}
Thanks,
Namitha

Populating a Kendo Grid when searching

I need to populate Kendo grid from search button. I write personal ID and I should get other information in the grid, but after writing the ID in the textbox and clicking search, I get
"Server was unable to process request. ---> Procedure or function
'PROS_CRA_PUBLIC_GET_DOCUMENT_LIST_BY_PN' expects parameter '#PN',
which was not supplied."
Controller
public ActionResult Search(string personalID, [DataSourceRequest]DataSourceRequest request)
{
var serviceclient = new PersonalInfoServiceClient();
DataSourceResult result = null;
try
{
var items = serviceclient.GetRegistryInfoForPerson(personalID);
result = items.ToDataSourceResult(request);
}
catch
{
throw;
}
finally
{
serviceclient.Close();
}
return Json(result, JsonRequestBehavior.AllowGet);
}
View (part of it)
<div id ="search">
#using (Html.BeginForm("Search", "Main")){
<p> personal number: <input type="text" name="Searchtext" id="SearchString" /> <input type="submit" value="search" name="btnSearch" id="btnSearch" /></p>
}
<div id="civil">
#(Html.Kendo().Grid<PersonalIDCheckerMvCKendo.Models.PersInfo>()
.Name("Grid")
.AutoBind(false)
.Columns(columns =>
{
//columns// })
.Groupable()
.Sortable()
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(c=> c.personalID))
.Read(read => read.Action("Search", "Main").Data("test"))
)
)
</div>
<script>
$("#btnSearch").on('click', function test() {
console.log("click");
var searchText = $("#SearchString").val();
if (searchText == "") {
alert("You must enter a search value");
return;
}
$.ajax({
url: '#Url.Action("Search","Main")',
data: { personalID: searchText},
type: 'POST',
dataType: "json",
success: function(result) {
var grid = $('#Grid').getKendoGrid();
grid.dataSource.data(result);
grid.refresh();
}
});
});
</script>
Model
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using DataAnnotationsExtensions;
namespace PersonalIDCheckerMvCKendo.Models
{
[DataContract(IsReference=true)]
public class PersInfo
{
[DataMember]
[DisplayName("Personal#")]
public string personalID
{
get
{
return _PersonalID;
}
set
{
if (_PersonalID != value)
{
_PersonalID = value;
}
}
}
private string _PersonalID;
[DataMember]
[DisplayName("Name")]
public string FirstName
{
get
{
return _FirstName;
}
set
{
if (_FirstName != value)
{
_FirstName = value;
}
}
}
private string _FirstName;
[DataMember]
[DisplayName("Lastname")]
public string LastName
{
get
{
return _LastName;
}
set
{
if (_LastName != value)
{
_LastName = value;
}
}
}
private string _LastName;
//etc
thanks
You are not passing the personalID.
Add a javascript function that will be responsible for passing the data needed by the controller function, for example
function additionalData() {
return {
personalID: '#Model.personalID'
};
}
then change the DataSource of your grid to make use of the javascript function
.DataSource(dataSource => dataSource.Ajax().ServerOperation(false)
.Read(read => read.Action("Search", "Main")
.Data("additionalData"))
)
also make sure that the
[DataSourceRequest]DataSourceRequest request
parameter is placed first in your controller function, for example
public ActionResult Search([DataSourceRequest]DataSourceRequest request
, string personalID)
also make sure that you are binding the columns of the grid with the properties of the object returned (In your case PersonalIDCheckerMvCKendo.Models.PersInfo). For example
.Columns(columns =>
{
columns.Bound(pi => pi.Name);
columns.Bound(pi => pi.Surname);
// Some other columns.
})
*Update
To assist you I added one of my working grid examples. Here is my grid
#(Html.Kendo().Grid<ClientSearchResult>()
.Name("Grid")
.HtmlAttributes(new {style = "height:400px; cursor:pointer"})
.DataSource(dataSource => dataSource.Ajax().ServerOperation(false)
.Read(read => read.Action("RefreshGrid", "Client")
.Data("additionalData"))
.PageSize(20)
)
.Columns(columns =>
{
columns.Bound(c => c.ClientId);
columns.Bound(c => c.Name);
columns.Bound(c => c.PolicyNumber);
columns.Bound(c => c.ClaimNumber);
columns.Bound(c => c.Status);
columns.Bound(c => c.IsCompany);
})
.Pageable(page => page.Enabled(true).PageSizes(new[] {10, 20, 30, 40}))
.Sortable(sorting => sorting.SortMode(GridSortMode.SingleColumn))
.Scrollable()
.Selectable(selectable => selectable.Mode(GridSelectionMode.Single))
.Events(events => events.Change("grid_selected"))
)
My javascript function
function additionalData() {
return {
cellNumber: '#Model.CellNumber',
name: '#Model.Name',
policyNumber: '#Model.PolicyNumber',
claimNumber: '#Model.ClaimNumber',
brokerCode: '#Model.BrokerCode',
brokerName: '#Model.BrokerName'
};
}
and my controller function
public ActionResult RefreshGrid([DataSourceRequest] DataSourceRequest request
, string cellNumber, string name
, string policyNumber, string claimNumber
, string brokerCode, string brokerName)
{
if (cellNumber == string.Empty && name == string.Empty && policyNumber ==
string.Empty && claimNumber == string.Empty && brokerCode == string.Empty &&
brokerName == string.Empty)
return Json(new List<ClientSearchResult>());
else
{
List<ClientSearchResult> searchResult =
ClientMaintenance.ClientSearch(cellNumber, name, policyNumber, claimNumber,
brokerCode, brokerName).ToList();
var result = searchResult.ToDataSourceResult(request);
return Json(result);
}
}
I fixed it
changed the controller to this:
public ActionResult Search([DataSourceRequest]DataSourceRequest request, string searchString)
{
var serviceclient = new PersonalInfoServiceClient();
DataSourceResult result = null;
if (!String.IsNullOrEmpty(searchString))
{
try
{
var items = serviceclient.GetRegistryInfoForPerson(searchString);
result = items.ToDataSourceResult(request);
}
catch
{
throw;
}
finally
{
serviceclient.Close();
}
}
return Json(result, JsonRequestBehavior.AllowGet);
}
View :
Textbox:
#Html.TextBox("SearchString")
Function:
<script type="text/javascript">
$(document).ready(function(){
$("#btnSearch").click(function (e) {
$.ajax({
url: '#Url.Action("Search","Main")',
type: 'POST',
dataType: "json",
success: function (result) {
$("#Grid").data("kendoGrid").dataSource.read();
$("#Grid").data("kendoGrid").refresh();
e.preventDefault();
}

Kendo Grid: Foreign Key Dropdown does not update grid cell after update

I have a Kendo MVC grid that contains a nullable property (short) that is bound as a foreign key and uses a dropdown list as an editor template. I am also using inline editing.
When the property value is null, the dropdown list selected value does not get set into the grid cell after the update button is clicked. This works fine if incell editing is used. I am looking for a workaround that will solve my problem. I am including a stripped down version of my code below
Everything works if the nullable value is set to a non-null value.
GRID
#(Html.Kendo().Grid<AssetViewModel>()
.Name("DealAssets")
.Columns(c =>
{
c.Bound(x => x.Name);
c.ForeignKey(x => x.AssetTypeID, (IEnumerable<SelectListItem>)ViewBag.AssetTypeList, "Value", "Text");
c.ForeignKey(x => x.SeniorityTypeID, seniorityTypeList, "Value", "Text").EditorTemplateName("GridNullableForeignKey");
c.ForeignKey(x => x.RateBaseID, rateBaseList, "Value", "Text").EditorTemplateName("GridNullableForeignKey"); ;
c.Command(m => { m.Edit(); m.Destroy(); });
})
.ToolBar(toolbar => toolbar.Create().Text("Add New Asset"))
.Editable(x => x.Mode(GridEditMode.InLine))
.DataSource(ds => ds
.Ajax()
.Model(model => model.Id(request => request.ID))
.Read(read => read.Action("ReadAssets", "Deal", new { id = Model.ID }))
.Create(create => create.Action("CreateAsset", "Deal", new { currentDealID = Model.ID }))
.Update(update => update.Action("UpdateAsset", "Deal"))
.Destroy(destroy => destroy.Action("DeleteAsset", "Deal"))
)
)
EDITOR TEMPLATE
#model short?
#{
var controlName = ViewData.TemplateInfo.GetFullHtmlFieldName("");
}
#(
Html.Kendo().DropDownListFor(m => m)
.Name(controlName)
.OptionLabel("- Please select -")
.BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
)
UPDATE ACTION
public ActionResult UpdateAsset([DataSourceRequest] DataSourceRequest request, int ID)
{
var dealAsset = DataContext.DealAssets.SingleOrDefault(o => o.ID == ID);
if (dealAsset != null)
{
if (TryUpdateModel(dealAsset.Asset, new[] {"Name","AssetTypeID","SeniorityTypeID","RateBaseID" }))
{
DataContext.SaveChanges();
}
}
return Json(new[] { new AssetViewModel(dealAsset) }.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
}
Telerik just recently added a new HTML attribute, data_value_primitive, to their selectlist that addresses the issue above. The new attribute should be added in the foreign key editor template and set to true.
Html.Kendo().DropDownListFor(m => m)
.Name(controlName)
.OptionLabel("- Please select -")
.BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
**.HtmlAttributes(new { data_value_primitive = true})**
This last section is a modification to the update method to account for the grid not passing back null properties when doing the ajax call. I think this has more to do with how the TryUpdateModel method works
...
if (TryUpdateModel(dealAsset.Asset, new[] {"Name","AssetTypeID","SeniorityTypeID","RateBaseID" }))
{
// If no property passed back then set it to null
var senorityTypeID = ValueProvider.GetValue("SeniorityTypeID");
if (senorityTypeID == null)
{
dealAsset.Asset.SeniorityTypeID = null;
} else {
dealAsset.Asset.SeniorityTypeID = (short)senorityTypeID.ConvertTo(typeof(short));
}
var rateBaseID = ValueProvider.GetValue("RateBaseID");
if (rateBaseID == null)
{
dealAsset.Asset.RateBaseID = null;
} else {
dealAsset.Asset.RateBaseID = (byte)rateBaseID.ConvertTo(typeof(byte));
}
DataContext.SaveChanges();
}
'''

ASP.NET MVC 3 List<T> to IEnumerable<SelectListItem>

I'm not currently happy with the way that my DropDownListFor() objects are populated. I'm attempting to find as generic way of populating IEnumerable as possible. This is what I have so far.
Helper:
public static List<SelectListItem> ToSelectList(IDictionary<string,string> dictionaryItems, string selectedValue, string noSelection, bool search = false)
{
List<SelectListItem> items = new List<SelectListItem>();
if (search)
{
items.Add(new SelectListItem { Selected = true, Value = "-1", Text = string.Format("-- {0} --", noSelection) });
}
foreach (var item in dictionaryItems)
{
items.Add(new SelectListItem
{
Text = item.Key,
Value = item.Value,
Selected = selectedValue == item.Value ? true : false
});
}
return items
.OrderBy(l => l.Text)
.ToList();
}
Controller:
[HttpGet]
public ActionResult Index()
{
var model = new CreateModel();
var parentOrganisations = _orgs.FindBy(o => o.OwningOrganisationID == Globals.OrganisationID || o.ID == Globals.OrganisationID)
.OrderBy(o => o.OrganisationName);
Dictionary<string, string> items = new Dictionary<string, string>();
foreach (var item in parentOrganisations)
{
items.Add(item.OrganisationName, item.ID.ToString());
}
model.Organisations = SelectLists.ToSelectList(items, "-1", "-- None -- ", true);
return View(model);
}
View:
<div class="control-group">
<label class="control-label">Parent Organisation</label>
<div class="controls">
#Html.DropDownListFor(m => m.ParentOrganisationID, Model.Organisations, new { #class = "input-xlarge"})
<p class="help-block">Select a parent organisation to create a branch</p>
</div>
</div>
There seems to be A LOT of repetitive code in the controller. It takes a generic list, add's the Value and Text to a Dictionary and then uses that as input for a helper which builds up the select list to send as part of the model.
Does anyone have any better ways to achieve this? I hate having bloat in my controller, and when I get several drop downs on a form this is exactly what will happen in this instance.
Thanks,
EDIT - Thanks to Kenneth's helper method, I've now consolidated the whole thing into one call in the controller:
model.Organisations = _orgs.FindBy(o => o.OwningOrganisationID == Globals.OrganisationID || o.ID == Globals.OrganisationID)
.OrderBy(o => o.OrganisationName)
.ToList()
.ToSelectList(org => org.OrganisationName, org => org.ID.ToString(), "-1", "None", true);
You could provide callbacks that obtain the key and the value and then use those. Apart from that you can create it as an extension method:
Extension method:
public static List<SelectListItem> ToSelectList<T>(this List<T> Items, Func<T, string> getKey, Func<T, string> getValue, string selectedValue, string noSelection, bool search = false)
{
List<SelectListItem> items = new List<SelectListItem>();
if (search)
{
items.Add(new SelectListItem { Selected = true, Value = "-1", Text = string.Format("-- {0} --", noSelection) });
}
foreach (var item in Items)
{
items.Add(new SelectListItem
{
Text = getKey(item),
Value = getValue(item),
Selected = selectedValue == getValue(item) ? true : false
});
}
return items
.OrderBy(l => l.Text)
.ToList();
}
Usage:
List<Org>() parentOrganisations = // fetch here
model.Organisations = parentOrganisations.ToSelectList(org => org.ID.ToString(),
org => org.OrganisationName,
"-1",
"-- None -- ",
true);
Note: I typed this in the SO-editor, so you might have some syntax errors (they should be easy to solve though).
You can do in controller only like this: -
List<SelectListItem> dropdownItems = parentOrganisations
.Select(item => new SelectListItem
{
Value = item.ID.ToString(),
Text = item.OrganisationName,
Selected = "-1" == item.ID.ToString() ? true : false
})
.ToList();

Resources