Hi,
I'm using an EditorTemplate to enable the user to select a person
@model Int64
@(Html.Kendo().ComboBox()
.Name("RepIRN")
.Filter("contains")
.Placeholder("Select a rep...")
.DataTextField("Text")
.DataValueField("Value")
.HtmlAttributes(new { style = "width:100%;" })
.Filter("contains")
.AutoBind(false)
.MinLength(3)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsers", "AutoComplete");
})
.ServerFiltering(true);
})
)
The model that I'm displaying is
public class JobObjectModel
{
public long IRN { get; set; }
public string Rep { get; set; }
[UIHint("RepEditor")]
public long RepIRN { get; set; }
public string JobStatus { get; set; }
public string Promised { get; set; }
}
The combobox works fine except I can't figure out how I populate it with the rep value and rep name when the page loads the model.Everything else seems to work, if the user selects a value it is sent back to the controller fine etc.
I just can't figure out how I load the value (and text) when the page loads.
Below is how I populate the combobox
public JsonResult GetUsers(string text)
{
var sortedPeople = Database.GetPeople(text);
List<SelectListItem> items = new List<SelectListItem>();
foreach (var person in sortedPeople)
{
items .Add(new SelectListItem() { Text = person.FullName, Value = person.IRN.Value.ToString() });
}
return Json(items , JsonRequestBehavior.AllowGet);
}
12 Answers, 1 is accepted
Sorry, I posted the above before I finished.
This is the relevant section of the view
<div class="form-group row">
@Html.LabelFor(model => model.RepIRN, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.RepIRN, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.RepIRN, "", new { @class = "text-danger" })
</div>
</div>
Any help would be appreciated.
Your code seems to be correct. I assume that you are using the ComboBox in Grid`s Editor template, please correct me if I am wrong.
If this is the case, I would suggest you to take a look of the Sample project linked here where the custom editor in Grid is demonstrated.
I have modified the sample project in order to have a ComboBox in the Editor template, you will find it attached. You could find the Editor Template in Views -> Home -> EditorTemplates -> Person.cshtml. The configuration of the ComboBox is similar to the provided one. May I ask you to modify the project in order to replicate the problem the way it is at your end? This will help us to inspect the issue and advise you further. Please, note that the dependencies are deleted in order to meet the size limits.
Regards,
Neli
Progress Telerik
Hi,
No, not using a grid at all.
I've attached a sample - its simply a view to edit a single customer.
The path is Home/CustomerPage?id=3
When the id is passed in, all the inputs correctly load the values from the view except for the auto complete combo box. Hopefully you can see in the sample what I mean.
Stefan
First I would like to apologize for misunderstanding the issue.
I did not manage to run the provided project successfully, but using it I have prepared one, where I managed to replicate the issue.
You could use the value option in order to set the value to the ComboBox widget.
.Value(Model.ToString())
Attached you will find the modified sample project. I have deleted the dependencies due to the size limits.
I hope this helps.
Regards,
Neli
Progress Telerik
Hi,
The solution doesn't work, it fixes the sample only because it was a very simple case. I've updated the sample to be a little more complicated to show you what I mean.
Update the HomeController to the below code. Now you have 1000 people and use the server filter to only return 15 matches. If you navigate to page Home/CustomerPage?id=3 it will work - but only because the control does a GetCustomers call with a blank string and that returns the 1st 15 people. If you use Home/CustomerPage?id=100 for example - it will once again be blank.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestingGround.Models;
namespace TestingGround.Controllers
{
public class HomeController : Controller
{
static Dictionary<int, string> people = new Dictionary<int, string>();
static HomeController()
{
for (int i = 0; i < 1000; ++i)
{
people[i] = RandomString(random.Next(20) + 1);
}
}
public ActionResult CustomerPage(int id = 0)
{
if (id > 0)
{
var test = new TestModel();
test.Address = id.ToString() + " Address";
test.CustomerID = id;
test.CustomerName = people[id];
test.JobID = id;
return View(test);
}
return View();
}
[HttpPost]
public ActionResult CustomerPage(TestModel model)
{
return View(model);
}
public JsonResult GetCustomers(string text)
{
var queryPeople = from person in people
where person.Value.Contains(text.ToUpper())
select person;
List<SelectListItem> items = new List<SelectListItem>();
foreach (var person in queryPeople)
{
items.Add(new SelectListItem() { Value = person.Key.ToString(), Text = person.Value });
if (items.Count > 15)
break;
}
return Json(items, JsonRequestBehavior.AllowGet);
}
private static Random random = new Random();
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
}
}
Using the provided code, the DropDownList for CustomerID displays the text of the item in case the entered id in the url is lower or equal to 15 and shows the id in case value higher than 15 is entered. Here is a screencast showing the behavior on my end. The reason for this is that GetCustomers method returns always the first 15 items. This way the DropDownlist widget is not aware of the items with Id (value) higher than 15, so it could not show the text corresponding to those values. If the value of the CustomerID is part of the filtered values it will be displayed correctly.
Another approach, that might be suitable in case you need to set text to the DropDownList that is not present in the items data is to use the text method. For example, you could use the editor template for the CustomerName field and set the Text depending on the data from the model
.Text(Model.ToString())
Regards,
Neli
Progress Telerik
Nope, so that will show the text but the value isn't bound to the model. So if you press save, the id isn't populated which it needs to be.... If I wanted to try and do it this way, I would use an autocomplete textbox. But I specifically store id's not the string, so the control needs to be bound to the id, but display the string.
I've gotten a little closer to solving it..
In the view, I pass through the customer name
<div class="form-group">
@Html.LabelFor(model => model.CustomerID, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.CustomerID, new { htmlAttributes = new { @class = "form-control" }, @CustomerName = Model.CustomerName } )
@Html.ValidationMessageFor(model => model.CustomerID, "", new { @class = "text-danger" })
</div>
</div>
and set the text in the editor
@(Html.Kendo().ComboBox()
.Name("CustomerID")
.Filter("contains")
.Placeholder("Select a customer...")
.DataTextField("Text")
.DataValueField("Value")
.HtmlAttributes(new { style = "width:100%;" })
.Filter("contains")
.Value(Model.ToString())
.MinLength(1)
.Text(ViewData["CustomerName"].ToString())
.AutoBind(false)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCustomers", "Home");
})
.ServerFiltering(true);
})
Everything basically works other than when the user clicks to drop down the combo box, the first call to the server passes in a blank string?
Stefan
On initial load there is no value entered for filtering, for this reason the value sent to the server is empty string. Once the user enters a value in the ComboBox input it will be sent to the server instead of the blank string. This is the default behavior of the widget. In case you need to send additional data, you could use the data method.
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCustomers", "Home").Data("additionalData");
})
.ServerFiltering(true);
}
<script>
function
additionalData(params) {
var
filter =
''
if
(params.filter.filters[0]) {
filter = params.filter.filters[0].value
}
return
{
additional:
"some value"
,
text: filter
}
}
</script>
public
JsonResult GetCustomers(
string
text,
string
additional)
{
...
}
Regards,
Neli
Progress Telerik
Ok, so I think I've got a working solution now, but I couldn't get your additional data to work as described. The additional parameter method was never called. However I did the following
function additionalData(params) {
var filter = ''
if (params.filter.filters[0]) {
filter = params.filter.filters[0].value;
} else {
filter = $("#RepIRN").data("kendoComboBox").value()
}
return {
text: filter
}
}
which passes in the value parameter if the filter is blank.
So in summary what fixed my solution for anyone else is.
Step 1) In the View pass the text to the editor via an extra parameter - in this case @CustomerName
@Html.EditorFor(model => model.CustomerID, new { htmlAttributes = new { @class = "form-control" }, @CustomerName = Model.CustomerName } )
Step2: Setup the combo box, so initially the value is set to the model and the text to the parameter you passed in and also use the additional data function to pass the value to the server filter if the filter string is empty...
@(Html.Kendo().ComboBox()
.Name("RepIRN")
.Filter("contains")
.Placeholder("Select a rep...")
.DataTextField("Text")
.DataValueField("Value")
.HtmlAttributes(new { style = "width:100%;" })
.Value(Model.ToString())
.MinLength(1)
.Text(ViewData["RepName"].ToString())
.AutoBind(false)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsers", "AutoComplete").Data("additionalData"); ;
})
.ServerFiltering(true);
}
)
)
<script>
function additionalData(params) {
var filter = ''
if (params.filter.filters[0]) {
filter = params.filter.filters[0].value;
} else {
filter = $("#RepIRN").data("kendoComboBox").value()
}
return {
text: filter
}
}
</script>
Step 3: On the server filtering I check to see if a number has been sent to the filter and if so, I only return that person. Otherwise filter as normal. Obviously if the people have numbers in their name this could be an issue, but it has the added benefit for me if the user wants to enter the user code to select the person they can do that now as well.
Hopefully that helps people as this was driving me up the wall for ages.
Thank you very much for providing the steps for resolving the issue, as they could help somebody else.
Regarding sending additional data to the controller, I have modified the sample project in order to use the data method. Currently, the 'additionalData' function returns the filter value (string text) and another hardcoded string (additional: "some value"). Here is a screencast video of the behavior on my end. Attached you will find the modified sample project.
Regards,
Neli
Progress Telerik
Yes, it was my mistake for the additional data not working as you described.
My problem was I left the original method (that takes one parameter) in the controller and I thought the correct one would be called. I later discovered that if I removed the wrong method the additional data worked exactly as you described. I've updated my project already. Thanks