we are implementing an MVC solution using Telerik controls and
we have some problems refreshing the list of a Telerik ComboBox. Pratically we need to refresh the list of available values of a ComboBox every time the value selected in another ComboBox is changed. Below is our scenario:
Main ComboBox has a list of string values and we added an event;
Detail ComboBox has a list of values that depends on what is chosed from Main ComboBox;
When the event on Main ComboBox is fired the javascript calls an action in Controller;
The controller refresh the content of List02 (the datasource binded in ComboBox02)
Actually it runs all correctly but the Detail ComboBox does not refresh. What is wrong or missed?
Many Thanks for help
Main ComboBox:
<%=Html.Kendo().DropDownListFor(ourModel => ourModel.ModelPK)
.HtmlAttributes(new { #class="textboxDetails" })
.Name("combo01")
.BindTo((IEnumerable<ModelObject>)ViewData["List01"])
.DataTextField("descriptionText")
.DataValueField("valueID")
.Value(ourModel.ModelPK.ToString())
.Events(e =>
{
e.Select("onSelect");
})
%>
Detail Combobox:
<%=Html.Kendo().DropDownListFor(ourModel => ourModel.secPK)
.HtmlAttributes(new { #class="textboxDetails" })
.Name("combo02")
.BindTo((IEnumerable<ModelObject>)ViewData["List02"])
.DataTextField("descriptionText")
.DataValueField("valueID")
.Value(ourModel.Model02PK.ToString())
%>
Javascript on aspx page:
function onSelect(e) {
var dataItem = this.dataItem(e.item);
var itemPK = dataItem.valueID;
$.ajax({
type: 'POST',
url: '/controller01/action01',
data: "{'sentPK':'" + sentPK + "'}",
contentType: 'application/json; charset=utf-8',
success: function (result) {
},
error: function (err, result) {
alert("Error" + err.responseText);
}
});
}
Controller action:
[AcceptVerbs(HttpVerbs.Post)]
public void action01(model01 editModel, int sentPK)
{
//View data loads correctly
}
I do not think updating second combobox with ViewData will work in scenario:
.BindTo((IEnumerable)ViewData["List01"])
For the very first time when the page is rendered the value stored in ViewData object is used to fill the combobox but then onSelect all you are doing is, making an AJAX call to server. Server updates the ViewData object but as the combo box is already loaded with initial data, it will not be refreshed with new data.
You will have to refresh the second combobox on selection change event for first combo box.
Option 1:
Add following lines in your onSelect() success:
var combobox = $("#combo02").data("kendoComboBox");
combobox.dataSource.data(result);
Option 2:
Bind datasource of second combobox with server:
#(Html.Kendo().ComboBox()
.Name("products")
.HtmlAttributes(new { style = "width:300px" })
.Placeholder("Select product...")
.DataTextField("ProductName")
.DataValueField("ProductID")
.Filter(FilterType.Contains)
.DataSource(source => {
source.Read(read =>
{
read.Action("GetCascadeProducts", "ComboBox")
.Data("filterProducts");
})
.ServerFiltering(true);
})
.Enable(false)
.AutoBind(false)
.CascadeFrom("categories")
)
For a working example, refer this link.
Related
I am trying to use the multiselect plugin I found on here:
How to use Checkbox inside Select Option
The question above is for a <select> with hard coded <options>.
The <select> I am using generates <options> using jQuery and PHP with this function:
function initializeSelect($select, uri, adapt){
$.getJSON( uri, function( data ) {
$select.empty().append($('<option>'));
$.each(data, function(index, item) {
var model = adapt(item);
var $option = $('<option>');
$option.get(0).selected = model.selected;
$option.attr('value', model.value)
.text(model.text)
.appendTo($select);
});
});
};
initializeSelect($('#salesrep'), 'process/getSalesReps.php', function (item) {
return {
value: item.final_sales_rep,
text: item.final_sales_rep
}
});
I have used the above function several times in different projects, as it successfully creates all of the options brought in by the PHP process. Unless requested, I will not show the code for the process. Just know I am indeed retrieving a group of names and displaying them in the dropdown.
Right beneath the function above is where I call the multiselect feature:
$('select[multiple]').multiselect();
$('#salesrep').multiselect({
columns: 1,
placeholder: 'Select Reps'
});
The HTML for the select is as follows:
<select class="form-control" name="salesrep[]" multiple id="salesrep"></select>
Using all of the above, the output looks like this:
Upon inspecting the element, I can see all of the sales reps names. This tells me that the initializeSelect function is working properly.
Therefore I think the issue must have something to do with the multiselect.
Ajax calls are asynchronous. You call multiselect() before the ajax call has had time to complete and therefore the option list is still empty at the point you call the multiselect() function.
Either move the $('#salesrep').multiselect({.. bit to inside the getJSON method or call the multiselect refresh function after the option list has been populated as I am doing here. (Untested.)
function initializeSelect($select, uri, adapt){
$.getJSON( uri, function( data ) {
$select.empty().append($('<option>'));
$.each(data, function(index, item) {
var model = adapt(item);
var $option = $('<option>');
$option.get(0).selected = model.selected;
$option.attr('value', model.value)
.text(model.text)
.appendTo($select);
});
//now that the ajax has completed you can refresh the multiselect:
$select.multiselect('refresh');
});
};
initializeSelect($('#salesrep'), 'process/getSalesReps.php', function (item) {
return {
value: item.final_sales_rep,
text: item.final_sales_rep
}
});
$('select[multiple]').multiselect();
$('#salesrep').multiselect({
columns: 1,
placeholder: 'Select Reps'
});
In certain cases, usually after values have been cached from an initial search, I cannot get the mdb_autocomplete drop down to close on a single click. I often have to double click on my selection to get it to close. I am dynamically populating the values in the drop down via an Ajax call to a service method via and controller action method that searches the active directory for the first 30 name values. No call back occurs until a user enters at least 3 values into the mdb_autocomplete selection box. The callback and population of the drop down is working very well, but the click event following the selection of a value often will not close the dropdown. Additionally, we are being forced to use mdb boostrap over the normal bootstrap library. I have included the view, service, and typescript code that is being used to generate and populate the drop down.
View:
<div class="form-group">
<label class="font-weight-bold" for="RequestorSearchInput">Requestor</label>
<input type="text" id="RequestorSearchInput" name="RequestorSearchInput" class="form-control mdb-autocomplete" />
<span id="loading_data_icon"></span>
</div>
Service Method:
public List<string> GetRequestor(string aRequestor)
{
IEnumerable<Dictionary<string, string>> requestorNames;
using (ActiveDirectoryService service = new ActiveDirectoryService(<LDAP Domain Name>))
{
string[] propertiesToLoad = new string[] { "displayName" };
//requestorNames = service.SearchByPartialUsername(aRequestor, propertiesToLoad).Take(30).Union(service.SearchBySurname(aRequestor, propertiesToLoad).Take(30));
requestorNames = service.SearchBySurname(aRequestor, propertiesToLoad).Take(30);
}
return requestorNames.SelectMany(x => x.Values).Where(y => y.IndexOf(",", StringComparison.Ordinal) >= 0).Distinct().ToList();
}
TypeScript:
private handleRequestorSearch() {
let options: string[] = new Array();
// #ts-ignore
let searchval = $("#RequestorSearchInput").val().length;
if (searchval >= 3) {
$.ajax({
url: main.getControllerHREF("GetRequestor", "Search"),
method: "POST",
data: {
requestor: $("#RequestorSearchInput").val()
},
async: false,
dataType: "json",
success: function (names) {
$.each(names, function () {
options.push(this);
});
// #ts-ignore
$("#RequestorSearchInput").mdb_autocomplete({
data: options
}).select(function () {
$("#RequestorSearchInput").focus;
});
}
});
}
}
I have a JavaScript method that opens up a kendo-window, this window contains a kendo-grid which has a datasource that I want to get from my controller. In order to get the data to fill this grid I need to pass on an ID. The JavaScript method that opens up this window contains the necessary data, however I do not know how to get this data in my kendo-grid. I need to get my ID to the (read => read.Action("Read_Action", "ControlerName", new { linenum = ??? }) part where I want to replace the question marks with my ID.
JavaScript:
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
console.log(dataItem.LineNum);
var wnd = $("#Details").data("kendoWindow");
wnd.center().open();
}
Kendo-window:
#{Html.Kendo().Window().Name("Details")
.Title("Location Details")
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(800)
.Height(600)
.Content(
Html.Kendo().Grid<TelerikMvcApp1.Models.BinLocationItemModel>()
.Name("LocItemGrid")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(m => m.BinLocationItemId))
.Read(read => read.Action("Read_Action", "ControlerName", new { linenum = ??? })))
.ToHtmlString()).Render();
}
You can only do this using a controller to open your window content as a partial view.
Set up your controller which will render the partial view and add the id to ViewBag to retrieve in kendo window,
public ActionResult GetKendoWindow(){
ViewBag.Id = 123;
return PartialView("_PartialView"); // Html file name
}
Your "_PartialView" file will now contain the grid only with Id assigned from ViewBag.Id
Html.Kendo().Grid<TelerikMvcApp1.Models.BinLocationItemModel>()
.Name("LocItemGrid")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => model.Id(m => m.BinLocationItemId))
.Read(read => read.Action("Read_Action", "ControlerName", new { linenum = ViewBag.Id }))
Your kendo().window() method will change to this (without the content as it'll load from the Partial View)
#{Html.Kendo().Window().Name("Details")
.Title("Location Details")
.Visible(false)
.Modal(true)
.Draggable(true)
.Width(800)
.Height(600)
.LoadContentFrom("GetKendoWindow", "Controller")
.ToHtmlString()).Render();
}
If your ID is coming from the parent page (the page you're opening the window from), you will need to pass the ID up to the controller, your .LoadContentFrom("GetKendoWindow", "Controller") would then become .LoadContentFrom("GetKendoWindow?ID=123", "Controller").
And your controller declaration would become public ActionResult GetKendoWindow(int ID)
Edit:
As you retrieve the value from JavaScript event, you would preferably want to open your window using JavaScript for simplicity, in your event put the following
$("#Details").kendoWindow({
width: "620px",
height: "620px",
title: "Window Title",
content: {
url: "GetKendoWindow",
type: "GET",
data: {ID : dataItem.ID}
}
});
Remove your Kendo().Window() Razor function completely, and leave an empty div with id Details, and open the window using $("#Details").data("kendoWindow").center().open()
Complete code for simplicity:
<div id="Details"></div>
<script>
// Your event function where you retrieve the dataItem
$("#Details").kendoWindow({
width: "620px",
height: "620px",
title: "Window Title",
content: {
url: "GetKendoWindow",
type: "GET",
data: {ID : dataItem.ID}
}
});
$("#Details").data("kendoWindow").center().open()
//End the event function
</script>
Then add your controller method from above.
public ActionResult GetKendoWindow(int ID){
ViewBag.Id = ID;
return PartialView("_PartialView"); // Html file name
}
You could use Kendo DataSource additional data like this:
$("#grid").data("kendo-grid").dataSource.read({additional:"data"});
This is working on grid demo page: http://demos.telerik.com/kendo-ui/grid/remote-data-binding. It adds param to the request.
You could probably set the function returning additional data in dataSource - see the docs: http://docs.telerik.com/aspnet-mvc/helpers/grid/faq#how-do-i-send-values-to-my-action-method-when-binding-the-grid?
EDIT 1
You can achieve this simply by setting the grid's additional request data:
$("#grid").data("kendo-grid").dataSource.transport.options.read.data = { additional: "data"};
So you open the window with kendo grid. Select the grid with typical $(...).data("kendoGrid"). An then set the dataSource.transport.options.read.data to your line id.
I'm trying to update a select box based on another..
In my active admin resource, I did the following just for some test data:
controller do
def getcols
list = new Hash
list = {"OPTION1" => "OPTION1", "OPTION2" => "OPTION2"}
list.to_json
end
end
In active_admin.js I have the following
$('#worksheet_type').change(function() {
$.post("/admin/getmanifestcols/", { ws_type: $(this).val() }, function(data) {
populateDropdown($("#column_0"), data);
});
});
function populateDropdown(select, data) {
select.html('');
alert('hi');
$.each(data, function(id, option) {
select.append($('<option></option>').val(option.value).html(option.name));
});
}
The above is working in the sense that when my primary select box is changed, the jquery is called and I even get the alert box of 'hi' to be called. However, it's not replacing the contents of the select box with my test OPTION1 and OPTION2 data.
I think I'm passing in the JSON wrong or something, or it's not being read.
What am i missing?
It looks to me as if you're not properly iterating over the map.
What about:
$.each(data, function(value, name) {
select.append($('<option></option>').val(value).html(name));
});
?
The client will choose an item from a dropDown list, this newly selected value will then be used to find assets linked to that selected item, these assets will then be loaded into the listBox.
This sounds simple enough, and I'm aware I could use a partial View but it seems overkill for just updating one component on a form.
Any
I've done this in MVC 1.0 myself. I used an onchange on the first drop down which called an action using the value selected. That action returned a JSON result. The jQuery script which called that action then used the JSON to fill the second drop down list.
Is that enough explanation, or would you like help writing the javascript, the action, or both?
Inside your view:
<%= this.Select("DDLName").Attr("onchange", "NameOfJavascriptFunction();") %>
<%= this.MultiSelect("ListBoxName") %>
The javascript will look like this:
function NameOfJavascriptFunction() {
var ddlValue = $("DDLName").val();
jQuery.ajax({
type: 'GET',
datatype: 'json',
url: '/Controller/Action/' + dValue,
success: updateMultiSelect
});
}
function updateMultiSelect(data, status) {
$("#ListBoxName").html("");
for(var d in data) {
$("<option value=\"" + data[d].Value + "\">" + data[d].Name + "</option>">).appendTo("#ListBoxName");
}
}
Finally, the action is something like this (put this in the controller and action from the first javascript):
public ActionResult Action(int id) //use string if the value of your ddl is not an integer
{
var data = new List<object>();
var result = new JsonResult();
this.SomeLogic.ReturnAnEnumerable(id).ToList().ForEach(foo => data.Add(new { Value = foo.ValueProperty, Name = foo.NameProperty }));
result.Data = data;
return result;
}
Feel free to ask follow up questions if you need any more explanation.