I am using KendoUI cascading Drop-downs and it seems to be working fine for most part but it seems to have a little problem. However, I think it is a problem with my implementation NOT with the tool because on their Demo page here it seems to work fine. Also, I tried to follow the code exactly as it as to make sure that I do get the same behavior. Now, I am seeing following behavior:
I select an option in parent drop down and then click on the child drop down then it calls the conroller action correctly
It continues to do that as far as results for child dropdown are empty
Once it gets some value to bind child drop-down with, it stops making any call to the controller despite of what I choose in parent drop-down or child-dropdown.
I am not sure why it happens. Following is my code snippet:
Controller code
[HttpGet]
public ActionResult FindAlignmentsByTeamId(int teamId)
{
var teams = Client.GetAlignmentsByTeamId(teamId);
return Json(teams, JsonRequestBehavior.AllowGet);
}
.cshtml code
#* Perent Dropbox *#
<tr>
<td>EmployeeID</td>
<td><b>#Model.EmployeeId</b></td>
</tr>
<tr>
<td>Team</td>
<td>
#(Html.Kendo().DropDownList()
.Name("Team")
.DataTextField("TeamName")
.DataValueField("TeamId")
.DataSource(source => source.Read(read => read.Action("GetAllTeams", "Employee")))
)
</td>
</tr>
#* Child DropBox *#
#(Html.Kendo().DropDownList()
.Name("Alignment")
.DataTextField("AlignmentName")
.DataValueField("AlignmentId")
.DataSource(source => source.Read(read => read.Action("FindAlignmentsByTeamId", "Employee").Data("FilterAlignment"))
.ServerFiltering(true)
)
.CascadeFrom("teamId")
.AutoBind(false)
)
<script type="text/javascript">
function FilterAlignment() {
return {
teamId: $("#Team").val()
}
};
</script>
I am not sure what happens after it is bound successfully with a value for the first time so that it has a reason to believe that now it does not have to be checking on any OnChange() events anymore? Any ideas?
The id of your parent DropDownList is "Team", not "teamId". You need to update your child DropDownList to cascade from the correct id:
#(Html.Kendo().DropDownList()
.Name("Alignment")
.DataTextField("AlignmentName")
.DataValueField("AlignmentId"
.DataSource(source => source.Read(read => read.Action("FindAlignmentsByTeamId", "Employee").Data("FilterAlignment"))
.ServerFiltering(true)
)
.CascadeFrom("Team")
.AutoBind(false)
)
Related
I am trying out the .net Core ViewComponents instead of partial views. Here is my scenario.
I have a View that contains a few kendo listbox controls. When an item in any of the listbox is clicked, I need to invoke a webcomponent with the selected item id in the listbox. I also need to keep the ViewComponents hidden until the user clicks on a listbox item. Each listbox has it's own ViewComponent because the control in the viewcomponent is different for each listbox. So, I will have to hide some viewcomponents and show only the relevant component for the listbox. I have no clue how to pass the item id in any listbox when selected, to the Invoke method.
Here is my main view (non essential code removed)
<div style="height:25%; width:100%; background-color:antiquewhite;">
<b>Sections:</b>
#(Html.Kendo().ListBox()
.Name( "SectionListBox" )
.Selectable( ListBoxSelectable.Single )
.DataTextField( "Name" )
.DataValueField( "id" )
//.DataSource( ds => ds.Read( r => r.Action( "GetAllPageSectionsAsync", "Home" ) ) )
.Events( e => e.Change( "onSectionSelected" ) )
.HtmlAttributes( new { style = "width:95%;height:85%;" } )
)
</div>
<div style="height:25%; width:100%; background-color:cornsilk;">
<b>Fields:</b>
#(Html.Kendo().ListBox()
.Name( "FieldListBox" )
.Selectable( ListBoxSelectable.Single )
.DataTextField( "Name" )
.DataValueField( "id" )
//.DataSource( ds => ds.Read( r => r.Action( "GetAllFieldsAsync", "Home" ) ) )
.HtmlAttributes( new { style = "width:95%;height:85%;" } )
)
</div>
<div class="col-md-8" style="height:100%">
<div class="col-md-12" style="height:100%;">
<div id="AttrGridDiv" class="col-md-5" style="height:40%;">
<label>Attributes</label>
#await Component.InvokeAsync( "PageAttributes", new { pageId = 123 } )
</div>
</div>
</div>
and here is my component view:
#model IEnumerable<aaaaaaaa>
#(Html.Kendo().Grid<dynamic>()
.Name( "Attributes" )
.Selectable()
.Sortable()
.Scrollable()
.Events( e => e.Change( "onAttributeGridSelected" ) )
.HtmlAttributes( new { style = "width:100%;" } )
//.DataSource( ds => ds
//.Ajax()
//.Read( r => r.Action( "GetPages", "Home" ).Type( HttpVerbs.Post ) ) )
)
and here is my View Component:
[ViewComponent(Name ="PageAttributes")]
public class PageAttibutesViewComponent : ViewComponent
{
private IRulesEngineService reService;
public PageAttibutesViewComponent( IRulesEngineService _reService)
{
reService = _reService;
}
public async Task<IViewComponentResult> InvokeAsync(int pageId)
{
var pageAttribs = await reService.GetAllPageAttributesAsync( pageId );
return View( pageAttribs );
}
}
I have only shown one of the components. I have a few similar components that I need to invoke based on which listbox is selected the components will render different controls.
So, again, my questions are:
How to invoke the component from the view Conditionally?
How to pass the selected id from the chosen listbox to the invoke
method?
ViewComponents are processed by Razor (or any alternative view engine that supports the feature). What you try to achieve happens in the browser, but you need some server-side processing as well.
As I see it, you must (1) capture the ListBox change (Javascript), then (2) post it back to the controller (again Javscript) which (3) will process the request, change the model depending on what was submitted (C#), and finally (4) return the view with changed model, so that you the view can figure out how (what param value) to invoke the ViewComponent in question (C#, Razor). You may also decide to return a different view, but that is somewhat uncommon. Not so very straightforward, but this is web. Long ago, in web forms check boxes and drop downs had property PostBack (or simillar), which, when checked, did basically the same.
In effect, the post back to the controller, the changed view model, and finally the view, rendered with the changed model result in change of ViewComponent's invocation.
There are three types of ViewComponent invocations in Core 2.0. You can read about them here: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components#invoking-a-view-component.
I am trying to use an MVC form to modify some information in my database. I want to be able to select a few items from a table using a series check boxes. It should update the database boolean values when I hit a link at the bottom of my form.
So far, I have tried a few solutions from other threads, but since I am new to MVCs, they are rather confusing.
This is what I have right now for my HTML:
#foreach (var item in Model)
{
<tr>
#if (!item.IsCurated)
{
<td>
#Html.CheckBoxFor(modelItem => item.isChecked, new { #checked = true })
</td>
{
</tr>
#Html.ActionLink("Update", "updateDatabase", Model)
The "updateDatabase" method calls
public void updateDatabase()
{
db.SaveChanges();
}
I believe the changes to the database are being saved, but that the check boxes are not actually assigning any changed values.
I have following HTML code under Requisition.cshtml
foreach (var item in Model.RequisitionWorks)
{
<tr>
<td><div class="radio"><label name="#string.Format("Option_{0}", item.OptionNumber)">#item.OptionNumber</label></div></td>
<td>
<div class="radio">
<label>#Html.RadioButton(string.Format("Option_{0}", #item.OptionNumber),
"0", #item.IsOptionChecked("0"), new { #class = "OptionClass", id = string.Format("Option_None_{0}", #item.ToothNumber) }) #MyModelEntities.Properties.Resource.None
</label>
</div>
</td>
And I generate lots of radiobuttons...
So I would like to bind some jQuery event at the moment of rendering that code.
$("#Option_None_" + optionNumber).change(function () {
});
I need it because I generate id of html tag on fly.
Is it possible to do?
Why not apply using the class of the option instead of an id?
$(document).ready(function(){
$(".OptionClass").change(function () {
});
});
You can do this by using the .on jquery method (http://api.jquery.com/on/). To accomplish this you would select your containing div and then set the onchange for the inputs within it.
$('div.radio').on('change', 'input', function() {});
Edit: it's a lot easier to do what you want to if you give the radio buttons a common class and use the above method. Generally it's not necessary use something unique like the id to attach the same event handler to each one.
I have two Kendo DropDownLists, I want to disable second DDL when the value of the first DDL is loaded and bounded to the value of my viewmodel.
So I have such code:
#(Html.Kendo().DropDownList()
.Name("FormGroupId")
.HtmlAttributes(new { style = "width:250px" })
.OptionLabel("Select form group...")
.Template("#= data.Name # - #= data.Version #")
.DataTextField("Name")
.DataValueField("Id")
.Events(events =>
{
events.Change("onFormGroupChanged");
events.Select("onFormGroupSelected");
events.Cascade("onFormGroupCascaded");
})
.DataSource(source =>
{
source.Read(read => { read.Route(RouteConfig.GetFormGroupNames.Name); });
})
)
and
#(Html.Kendo().DropDownList()
.Name("Schema")
.HtmlAttributes(new { style = "width:250px" })
.OptionLabel("Select schema...")
.DataTextField("SchemaName")
.DataValueField("SchemaId")
.DataSource(source =>
{
source.Read(read =>
{
read.Route(RouteConfig.FilterFormSchemas.Name).Data("filterSchemas");
})
.ServerFiltering(true);
})
.Enable(false)
.AutoBind(false)
.CascadeFrom("FormGroupId")
)
I subscribe to the Cascade event on first DDL and try to disable second DDL from there, but it doesn't work.
JS:
function onFormGroupCascaded(e) {
$("#Schema").data("kendoDropDownList").enable(false);
}
You are already doing that.
Add events to first drop-down list:
.Events(e =>
{
e.Change("change").Select("select").Open("open").Close("close").DataBound("dataBound");
})
Using JavaScript, handle the change event
<script>
function change() {
// get a reference to the dropdown list
var dropdownlist = $("#dropdownlist").data("kendoDropDownList");
// disable the dropdown list
dropdownlist.enable(false);
};
</script>
Looks like you are already doing this. What kind of error are you getting?
This is an old question, but binding to the CascadeFrom event will not prevent the drop down from being enabled. This is due to code in the Kendo library re-enabling it later in the execution order.
Instead, bind to the DataBound event to disable the drop down. This event occurs later in the execution stack and disables the input after the Kendo code enables it.
This code works in angular directive configuration
dataBound: function (e) {
this.enable(false);
}
Let's say I have a view with Kendo treeview bounded to remote data source.
#(Html.Kendo().TreeView()
.Name("schemas")
.DataTextField("name")
.DataSource(dataSource => dataSource.Read(read => read.Action("Schemas", "Forms")))
.Events(events => events
.Select("onSelected")))
So the treeview just makes a call to the Schemas action in my FormsController
Also on the same page I have a form, which is simply the textbox and a button to submit the form
#using (Html.BeginForm("Load", "Forms", FormMethod.Post))
{
<div id="rootNode">
#Html.TextBox("rootElementName")
#Html.Button("next")
</div>
}
So I am just wondering what is the best way to handle user input and pass it to the the Load action of the FormsController? The user should select one of the options in the treeview and enter the value into textbox.
Or should I create some sort of viewmodel for my view with all my nodes inside + two additional fields for the textbox input and selected node?
I would take out the form elements, leaving:
<div id="rootNode">
#Html.TextBox("rootElementName")
#Html.Button("next")
</div>
The following js, this will pick up the tree item id on select.
The second function will call your Form controller action with the parameters.
<script>
var selectedNodeid;
//get the tree selected item id
function onSelected(e) {
var data = $('#schemas).data('kendoTreeView').dataItem(e.node);
selectedNodeid = data.id;
}
//button on click event
$(document).ready(function () {
$("#next")
.bind("click", function () {
//get parameters then pa
var id = selectedNodeid;
var rootElementName = $('#rootElementName).val()
$.ajax({
url: "Form/Load",
data:{id:id,rootElementName:rootElementName},
success: function () { }
});
}
})
</script>
I haven't tested this but it should be close.
I look forward to someone adding a better approach.