I am using the Kendo UI Autocomplete Box in a ASP.Net MVC Application.
(KENDO UI for ASP.NET MVC Q1 2016)
The part of the .cshtml code looks like this:
<div class="row">
<div class="col-md-10">
<div class="form-group">
#Html.Label(Strings.ManagerTimeEffortFormPartial_LabelLookupCustomer, new { #class = "k-label" })
#Html.TextBox("CustomerId", "", new { style = "display: none;" })
#(Html.Kendo().AutoComplete()
.Name("CustomerName")
.DataTextField("DisplayName")
.Filter(FilterType.Contains)
.MinLength(3)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("SearchCustomers", "Customer")
.Data("onSearchManagerEffortCustomerName");
})
.ServerFiltering(true);
})
.HtmlAttributes(new { #class = "k-textbox-fullwidth" })
.Events(e =>
{
e.Select("onSelectManagerEffortCustomer");
})
)
</div>
</div>
</div>
The element needs to be prefilled with a value. I am doing this after the ui was loaded:
$(function () {
var customerValue = $("#Project_CustomerName").val();
var customerNameAutoComplete = $("#CustomerName").data("kendoAutoComplete");
$("#CustomerName").val(customerValue);
customerNameAutoComplete.search(customerValue);
customerNameAutoComplete.select(customerNameAutoComplete.ul.children().eq(0));
customerNameAutoComplete.close();
});
Calling the "Close" method should close the suggestions (from what I understood in the documentation) but it does not work (the suggestions are still open). If I scroll the window in the ui or click somewhere else it closes immediately, but setting focus programmatically to another element or triggering a click-event via code doesn't help. I could hide/change the DOM-elements one by one, but I don't think this is a good solution, there are too many attributes changing when the item is selected with a mouse click.
Everything else in the code works fine (binding source, selecting the element and so on - I did not post the JS-Code for these parts here). I also tried to play with the "suggest" method without any luck. Any idea or a hint in the right direction?
This is how the autocomplete looks like after calling the "Close" method (still open):
Screenshot of Autocomplete Box with open suggestions
Sorry for this... again I got caught by the asynchronous loading trap...
of course I need to wait for the data bound event until i should select the item...
<div class="row">
<div class="col-md-10">
<div class="form-group">
#Html.Label(Strings.ManagerTimeEffortFormPartial_LabelLookupCustomer, new { #class = "k-label" })
#Html.TextBox("CustomerId", "", new { style = "display: none;" })
#(Html.Kendo().AutoComplete()
.Name("CustomerName")
.DataTextField("DisplayName")
.Filter(FilterType.Contains)
.MinLength(3)
.Suggest(false)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("SearchCustomers", "Customer")
.Data("onSearchManagerEffortCustomerName");
})
.ServerFiltering(true);
})
.HtmlAttributes(new { #class = "k-textbox-fullwidth" })
.Events(e =>
{
e.Select("onSelectManagerEffortCustomer");
e.DataBound("OnCustomerDataBound");
})
)
</div>
</div>
</div>
<script>
function OnCustomerDataBound() {
var customerNameAutoComplete = $("#CustomerName").data("kendoAutoComplete");
var select = customerNameAutoComplete.ul.children().eq(0);
customerNameAutoComplete.select(select);
customerNameAutoComplete.close();
}
$(function () {
var customerValue = $("#Project_CustomerName").val();
var customerId = $("#Project_CustomerId").val();
var consProjectId = $("#Project_ConsultingProjectId").val();
var customerNameAutoComplete = $("#CustomerName").data("kendoAutoComplete");
$("#CustomerName").val(customerValue);
$("#CustomerId").val(customerId);
customerNameAutoComplete.search(customerValue);
customerNameAutoComplete.trigger("change");
RefreshDropDownList("ManagerEffortCustomerProjects");
});
Now it works perfectly fine! Although it is kind of embarrassing, i will not delete this post. Maybe someone else will need some help to step off the hose...
Related
I have a View made up of 3 Partial Views:
Partial View #1 is listing RadioButtons. When I click a button I would like to send the resulting selection to the controller in order to update the Partial View #2 (which is a Telerik grid). Then the selection in PV #2 will update Partial View #3 (another Telerik grid).
I am currently doing a Window.location to send selected values to the Controller which causes the Controller and ViewModel to be reloaded and lose state. Other than losing the state, the flow works as I would like.
Is there a way to do this in Ajax to where I do not have to reload the Controller?
I will spare you the Partial Views #2 & #3 of the Telerik grids. If I can get the answer to how to get the radio button to call the Controller without a postback, I can apply the same to those Partial Views.
View:
#model MyProject.ViewModel.MaterialsListVM
#{
ViewBag.Title = "Materials List";
}
<div>
<div class="row">
<div class="col-sm-2">
#Html.Partial("MaterialTypeFilter")
</div>
<div class="col-lg-10">
#Html.Partial("MaterialsGrid")
</div>
</div>
<div class="row"> </div>
<div class="row">
<div class="col-sm-2"> </div>
<div class="col-lg-10">
#Html.Partial("ProjectMaterialsGrid")
</div>
</div>
</div>
Partial View #1:
#model MyProject.ViewModel.MaterialsListVM
<div class="container">
<h5> #Html.Label("Material Type: ", new { style = "font-weight:bold;" })</h5>
#if (Model != null)
{
for (int i = 0; i < Model.Material_Type.MaterialTypeList.Count; i++)
{
<span class="btn-group-sm">
#Html.RadioButton("MatType", new { Model.Material_Type.MaterialTypeList[i].Name }, Model.Material_Type.MaterialTypeList[i].Selected, new { #onclick = "CallChangefunc(this.value)" })
#Html.Label(Model.Material_Type.MaterialTypeList[i].Name)
</span><br />
}
}
</div>
<script>
function CallChangefunc(value) {
var selected = value.replace("{ Name = ", "");
selected = selected.replace("}", "");
window.location = '#Url.Action("Index", "MaterialsList")' + '?selectedMatType=' + selected;
//alert("val is:" + selected);
}
Update
I changed the JavaScript to this Ajax call and that called my Controller HttpPost Index() function:
$(document).ready(function () {
$(':radio[name="MatType"]').change(function (e) {
$.ajax({
type: 'POST',
url: '/MaterialsList/Index',
data: { selectedMatType: $(':radio[name="MatType"]:checked').val()},
dataType: "json",
success: function (data) {
alert('did it');
}
});
});
})
Unfortunately the Controller is still being reloaded and I'm losing the state of the data selected into the Partial View #3 Telerik grid...
...any help would be much appreciated...
Update #2
This solution sucks but I don't know what else to do...
The goal is to retain the state of the datasource for a Telerik grid in Partial View #3. The datasource is a ViewModel with a List of class objects.
Added Partial View #2 code and ActionResult from Controller. There is no HttpPost Index function. Every radio button change fires the ActionResult Index. Every select event in Telerik grid fires ActionResult Index.
Pertinent Controller code:
public ActionResult Index(string selectedMatType, string selectedMaterials, string projectMaterialsList)
{
if (projectMaterialsList != null)
{
materialsListVM.ProjectMaterialsList = JsonConvert.DeserializeObject<List<ProjectMaterialsListVM.ProjectMaterial>>(projectMaterialsList);
}
if (selectedMatType != null)
{
materialsListVM.SelectMaterialType(selectedMatType);
materialsListVM.GetMaterials();
}
if (selectedMaterials != null)
{
string[] materialIds = selectedMaterials.Split(',');
foreach (string id in materialIds)
{
MoveToProjectMaterialsList(id, selectedMatType);
}
}
ViewBag.ProjectMaterialsList = materialsListVM.ProjectMaterialsList;
ViewBag.SelectedMatType = selectedMatType;
return View(materialsListVM);
}
Partial View #2 code:
#model MyProject.ViewModel.MaterialsListVM
<div>
#if (ViewBag.SelectedMatType == "Cap Weld")
{
#(Html.Kendo().Grid(Model.CapWeld_Materials)
.Name("grid")
.Columns(columns =>
{
columns.Select().Width(40);
columns.Bound(c => c.MaterialId).Hidden();
columns.Bound(c => c.MaterialTypeName);
columns.Bound(c => c.PcsPartNum);
columns.Bound(c => c.ClientPartNum);
columns.Bound(c => c.Type).Filterable(ftb => ftb.Multi(true));
columns.Bound(c => c.OuterDiameter).Filterable(ftb => ftb.Multi(true));
columns.Bound(c => c.WallThickness).Filterable(ftb => ftb.Multi(true));
columns.Bound(c => c.Specification).Filterable(ftb => ftb.Multi(true));
columns.Bound(c => c.Grade).Filterable(ftb => ftb.Multi(true));
})
.Events(ev => ev.Change("onChange"))
.Pageable()
.Sortable()
.Scrollable()
.TableHtmlAttributes(new { width = "100%" })
//.HtmlAttributes(new { style="height:500px"})
.PersistSelection(true)
.Filterable()
.DataSource(datasource => datasource
.Ajax()
.ServerOperation(false)
.Model(m => m.Id(d => d.MaterialId))
)
);
}
</div>
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var val = jss.Serialize(ViewBag.ProjectMaterialsList);
}
<script>
function onChange(arg) {
var selectedMatType = '#(ViewBag.SelectedMatType)';
var projectMaterialsList = '#Html.Raw(val)';
//var obj = $.parseJSON(val);
var grid = $('#grid').data('kendoGrid');
var selectedMaterials = grid.selectedKeyNames().join(", ");
// alert(selectedMaterials);
#*$.ajax({
type: "POST",
data: { selectedMatType: selectedMatType, selectedMaterials: selectedMaterials, projectMaterialsList: projectMaterialsList },
dataType: "json",
url: #Url.Action("Index", "MaterialsList")
});*#
window.location = '#Url.Action("Index", "MaterialsList")' + '?selectedMatType=' + selectedMatType + '&selectedMaterials=' + selectedMaterials
+ '&projectMaterialsList=' + projectMaterialsList;
}
</script>
I have implemented the cascading feature of kendo drop down. While trying to save the information, I am not able to get the value of the combo in my viewmodel. If I comment the name attribute, I do get the value however I need the name attribute for the cascading feature to work. I was trying a workaround using jquery to set the model value but getting errors. Could somebody tell me how to fix this issue.
Sales Organisation Combo
<div class="form-group">
#Html.LabelFor(model => model.Company, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
<div class="editor-field">
#(Html.Kendo().ComboBoxFor(model => model.CountryCode)
.Name("SalesOrganisation")
.HtmlAttributes(new { style = "width:100%" })
.DataTextField("CompanyCodeCompany")
.DataValueField("CountryCode")
.Filter("contains")
.MinLength(3)
.DataSource(dataSource => dataSource
.Read(read => read.Action("RequestHeader_SalesOrganisation", "Request").Type(HttpVerbs.Post))
.ServerFiltering(true)
)
)
</div>
#Html.ValidationMessageFor(model => model.Company, "", new { #class = "text-danger" })
</div>
</div>
Sales Office combo
<div class="form-group">
#Html.LabelFor(model => model.SalesOffice, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
<div class="editor-field">
#(Html.Kendo().ComboBoxFor(model => model.SalesOfficeID)
// .Name("SalesOffice")
.HtmlAttributes(new { style = "width:100%" })
.DataTextField("SalesOffice")
.DataValueField("SalesOfficeID")
.AutoBind(false)
.Value("")
.DataSource(dataSource => dataSource
.Read(read =>
{
read.Action("RequestHeader_SalesOffice", "Request")
.Type(HttpVerbs.Post)
.Data("GetFilterOption");
}).ServerFiltering(true)
).CascadeFrom("SalesOrganisation").Filter("contains")
)
</div>
#Html.ValidationMessageFor(model => model.SalesOffice, "", new { #class = "text-danger" })
</div>
</div>
Javascript for cascading feature to work
function GetFilterOption() {
return {
id: $('#SalesOrganisation').val()
}
}
Javascript - Trying to set the model which doesnt work
function GetFilterOption() {
var countryCode = $('#SalesOrganisation').val();
var model = $('#SalesOrganisation').data('kendoComboBox');
model.value = countryCode;
return id = countryCode;
}
When you use .ComboBoxFor(), you should not use .Name().
When you use .ComboBoxFor(m => m.FieldName) then the id/name attribute will be set to "FieldName" by kendo's implementation of the Razor helper and matches the name of your model field.
If you then use .Name("SomeOtherFieldName"), you change the id/name attribute to "SomeOtherFieldName" and it no longer matches the field name of your model, which is why you no longer get the value.
What you want to do is not use .Name() and set up the .CascadeFrom() appropriately, i.e.
#(Html.Kendo().ComboBoxFor(model => model.CountryCode)
....
#(Html.Kendo().ComboBoxFor(model => model.SalesOfficeID)
.CascadeFrom("CountryCode")
function GetFilterOption() {
return {
id: $('#CountryCode').val()
}
}
I am using first time Kendo ui so I have very limited knowledge about it. What should I do to change treeview items color for some conditions.
<div>
#(
Html.Kendo().TreeView()
.Name("treeview")
.TemplateId("treeviewTemp")
.HtmlAttributes(new { #class = "rightlist"})
.BindTo((IEnumerable<NavigationViewModel>)ViewBag.Tree, (NavigationBindingFactory<TreeViewItem> mappings) =>
{
mappings.For<NavigationViewModel>(binding => binding.ItemDataBound((item, node) =>
{
item.Text = node.Description;
}).Children(node => node.Children));
mappings.For<NavigationViewModel>(binding => binding.ItemDataBound((item, subCategory) =>
{ item.Text = subCategory.Description; }));
})
)
</div>
And this is the templete. Template works for color change but tree items comes as "undefined". Is it also possible to add some conditions in script?
<script id="treeviewTemp" type="text/kendo-ui-template">
<div>
<span style="color: Green">#: item.Text #</span>
</div>
</script>
I would like to bind data to a kendoui multiselect at runtime.
for example suppose that I want to bind it as a cascade of a drobdownlist.
any idea?
<p>
<label for="categories">Catergories:</label>
#(Html.Kendo().DropDownList()
.Name("categories")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Select category...")
.DataTextField("CategoryName")
.DataValueField("CategoryId")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadeCategories", "CoreParam");
});
})
.Events(e =>e.Select("select"))
)
</p>
<p>
<label for="parameters">Parameters:</label>
#(Html.Kendo().MultiSelect()
.Name("parameters")
.HtmlAttributes(new { style = "width:400px" })
.DataTextField("ParamDesc")
.DataValueField("ParamCode")
.Placeholder("Select products...")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadeParams", "CoreParam")
.Data("filterParams");
})
.ServerFiltering(true);
})
.AutoBind(false)
)
</p>
<script type="text/javascript">
function filterParams() {
return {
categories: $("#categories").val()
};
}
function select(e) {
var dropdownlist = $("#categories").data("kendoDropDownList");
dropdownlist.select(e.item.index());
var multiselect = $("#parameters").data("kendoMultiSelect");
multiselect.dataSource.read();
};
</script>
You could create a custom MVVM binder which will get the text of the dropdownlist and will set a property of the ViewModel. This property can be bound to the hidden field. Check out the link below for more information.
I am attempting to append a partial view to the end of my 'currently displayed page' when a selection from a dropdown menu is chosen.
This is the dropdown from my view:
<div>
#Html.DropDownListFor(x => x.DropDownInfo, Model.Info, "DefaultSelection")
#Html.ValidationMessageFor(model => model.Courses)
</div>
I am in most need here in my Jquery. What do I need to do to append the PartialView that is returned by my controller (pasted below)? My current Jquery:
$(document).ready(function() {
$("#DropDownInfo").change(function() {
var strSelected = "";
$("#DropDownInfo option:selected").each(function() {
strSelected += $(this)[0].value;
});
var url = "/Controller/PreFillMethod/?MethodString=" + strSelected;
$.post(url, function(data) {
//*****
// Assuming everything else is correct,
// what do I do here to have my partial view returned
// at the end of the currently displayed page?
//*****
});
});
});
This is the part of my controller that replies with a PartialView (I want the string from the dropdown selection to be passed into this controller to ultimately be used to fill in a field in the PartialView's form) :
public PartialViewResult PreFillCourse(string selectedFromDropDown)
{
ViewBag.selectedString = selectedFromDropDown;
MyViewModel preFill = new MyViewModel
{
Title = selectedFromDropDown, // I am using this to pre-fill a field in a form
};
return PartialView("_PartialViewForm", preFill);
}
The Partial View (in the case that it matters):
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>CourseTemplates</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I am open to suggestions if I am approaching the situation entirely incorrectly.
My goal is to have a user select a 'template' from the drop-down menu and have that template's data autopopulate into a form below the drop-down.
My Jquery is very rough - I am using this post as a guide
you should have a div in your view
<div id ="divToAppend">
</div>
then append the partial view to your div
$(document).ready(function() {
$("#DropDownInfo").change(function() {
var strSelected = "";
$("#DropDownInfo option:selected").each(function() {
strSelected += $(this)[0].value;
});
var url = "/Controller/PreFillMethod/?MethodString=" + strSelected;
$.post(url, function(data) {
$('#divToAppend').html(data);
//*****
// Assuming everything else is correct,
// what do I do here to have my partial view returned
// at the end of the currently displayed page?
//*****
});
});
});