Cascading Telerik combo boxes remember selected value after client side databinding - c#

I have two combo boxes and a grid in my MVC View:
<div id="Products" class="products maintField">
#Html.Label("something", "Product:")
#(Html.Telerik().ComboBox().Name("productList")
.AutoFill(true)
.DataBinding(c => c.Ajax().Select("GetProducts", "Maintenance").Enabled(true).Cache(true))
.Filterable(c => c.FilterMode(AutoCompleteFilterMode.StartsWith).Enabled(true))
.HighlightFirstMatch(true)
.ClientEvents(eb =>
{
eb.OnChange("productChanged");
})
)
</div>
<div id="Layouts" class="layout maintField">
#Html.Label("something", "Layout:")
#(Html.Telerik().ComboBox().Name("layoutList")
.ClientEvents(eb =>
{
eb.OnChange("layoutChanged");
})
)
</div>
<div style="clear: both;"/>
<div class="fields">
#(Html.Telerik().Grid<MaintenanceModel>().Name("fieldList")
.DataBinding(bc =>
{
bc.Ajax().Select("GetProductFields", "Maintenance", new { prodID = 0, layoutID = 0 }).Enabled(true);
})
.ClientEvents(c =>
{
c.OnDataBound("fieldGridBound");
})
.Columns(c =>
{
c.Bound(mm => mm.Field_ID).ClientTemplate("<input id='Field_ID_<#= Field_ID #>' type='checkbox' name='checkedRecords' class=\"checkBoxGroup\" value='<#= Field_ID #>' />")
.Title("<input id='mastercheckbox' type='checkbox' style='display:none;' />")
.HeaderHtmlAttributes(new { style = "text-align: center;" })
.Width(36)
.HtmlAttributes(new { style = "text-align:center" });
c.Bound(fld => fld.Field_Name).Title("Field Name").Width(225);
c.Bound(fld => fld.Field_Description).Title("Field Description");
}).Scrollable(c =>
{
c.Enabled(true);
c.Height(700);
}).Footer(false).Sortable(c =>
{
c.Enabled(false);
c.OrderBy(oc =>
{
oc.Add(fld => fld.SeqNbr);
});
})
)
</div>
And with some less than beautiful JS the comboboxes cascade and eventually populate the grid:
function productChanged(e) {
clearLayout();
var layoutCombo = $("#layoutList").data('tComboBox');
if (layoutCombo == null) {
alert("Can't find layoutList");
return;
}
if (e.value == "" || e.value == null) {
clearLayout();
return;
}
layoutCombo.loader.showBusy();
$.get('#Url.Action("GetProductLayouts", "Maintenance")', { prodID: e.value }, function (result) {
layoutCombo.dataBind(result);
layoutCombo.loader.hideBusy();
});
}
function layoutChanged(e) {
var prodCombo = $("#productList").data('tComboBox');
var fieldGrid = $("#fieldList").data('tGrid');
if (fieldGrid == null) {
alert("Can't find fieldList");
}
if (prodCombo == null) {
alert("Can't find prodCombo");
}
if (e.value == "" || e.value == null) {
clearGrid();
return;
}
fieldGrid.rebind({ prodID: prodCombo.value(), layoutID: e.value });
$("#mastercheckbox").css("display", "block");
}
function fieldGridBound(e) {
var prodCombo = $("#productList").data('tComboBox');
var layoutCombo = $("#layoutList").data('tComboBox');
$.get('#Url.Action("GetLayoutFields", "Maintenance")', { prodID: prodCombo.value(), layoutID: layoutCombo.value() }, function (result) {
var cbGroup = $(".checkBoxGroup");
$(cbGroup).each(function (i, e) {
if (result.indexOf(e.value) >= 0) {
$(e).attr('checked', 'checked');
} else {
$(e).removeAttr('checked');
}
});
});
}
This works beautifully except in the situation where the two combo boxes are filled, the grid is bound, and the user goes to select a different value from the first combo box. The second combo box rebinds as expected, but if the values bound to the combobox didn't change (in position or display value) and the user selects the same item again, the change event doesn't get fired.
Specific example
In the database I have a hierarchy of Products and Layouts:
Product A
Platinum Layout
Gold Layout
Silver Layout
Product B
Platinum Layout
Gold Layout
Silver Layout
Product C
Platinum Layout
Silver Layout
Scenario 1
User selects 'Product A' from the first drop down causing the second drop down to be populated with Platinum, Gold, and Silver Layouts.
User selects 'Platinum Layout' from the second drop down causing related information to show in the grid.
User selects 'Product B' from the first drop down causing the second drop down to again be populated with Platinum, Gold, and Silver Layouts.
User selects 'Platinum Layout' from the second drop down again, however the changed event doesn't fire because the combo box didn't forget what was selected from before being rebound.
Scenario 2
User selects 'Product A' from the first drop down causing the second drop down to be populated with Platinum, Gold, and Silver Layouts.
User selects 'Platinum Layout' from the second drop down causing related information to show in the grid.
User selects 'Product C' from the first drop down causing the second drop down to again be populated with Platinum, Gold, and Silver Layouts.
User selects 'Platinum Layout' from the second drop down, causing the same erroneous behavior described in step 4 of Scenario 1.
Scenario 3
User selects 'Product A' from the first drop down causing the second drop down to be populated with Platinum, Gold, and Silver Layouts.
User selects 'Silver Layout' from the second drop down causing related information to show in the grid.
User selects 'Product C' from the first drop down causing the second drop down to be populated with Platinum and Silver Layouts.
User selects 'Silver Layout' from the second drop down causing related information to show in the grid (as should have happened in the other 2 scenarios).
In order to try to force the combo box to forget which item was selected prior to being rebound, I've tried manually setting the selected item to -1 (nothing) before binding using:
layoutCombo.select(-1);
and I've also tried reloading the combo box after the bind using
layoutCombo.reload();
However neither of them worked for me.
Has anyone else seen this behavior under similar circumstances? Is there any way to clear the combo box's last selected item variable manually from within my page (without digging around in the Telerik source)?

After playing with it a little more and hoping it would just work, it looks like it works if I fire the change event manually after layoutCombo.select(-1) and before I force the dataBind on the second combo box. Here's what my productChanged code looks like now:
function productChanged(e) {
clearLayout();
var layoutCombo = $("#layoutList").data('tComboBox');
if (layoutCombo == null) {
alert("Can't find layoutList");
return;
}
if (e.value == "" || e.value == null) {
clearLayout();
return;
}
layoutCombo.loader.showBusy();
$.get('#Url.Action("GetProductLayouts", "Maintenance")', { prodID: e.value }, function (result) {
layoutCombo.select(-1);
layoutCombo.trigger.change(); //**** Trigger the change manually so the combobox knows its value has changed
layoutCombo.dataBind(result);
layoutCombo.loader.hideBusy();
});
//layoutCombo.reload();
}
It feels like a bit of a hack since the combo box should know it's own value already. Any other ideas to make this cleaner would be much appreciated.

Related

TreeView, give value

I have this code:
foreach (MyClass info in data)
{
if (info.year!= "" && info.year!= null)
{
TreeViewYear.SelectedNode = TreeViewYear.RootNodes[0].Children.FirstOrDefault(x => x.Content?.ToString() == info.year);
}
}
Imagining that the foreach runs twice with the years "5" and "2", he selects correctly but then when he runs the second time, gets only the 2 value, that is, the value 2 and withdraws the 5.
If you want to select more than one item, you should set the SelectionMode of the TreeView to Multiple and add the items to be selected to the SelectedNodes property:
TreeViewYear.SelectedNodes.Add(
TreeViewYear.RootNodes[0].Children.FirstOrDefault(x => x.Content?.ToString() == info.year));

Select RadioButton based on database value

Working on MVC 5 app.
I have a table with a bunch of columns. One column contains a radio button list of items. Since this is an "edit" view I need to pre-populate the selected radio button properly. (ie select the item that's in the db)
Part of my controller code...
newVmRecord.SurveyAnswerOption =
new SelectList(db.SurveyAnswerOptions,
"AnswerOptionText", "AnswerOptionText", ar.SurveyAnswer);
Here's the razor:
#foreach (SelectListItem item in
(IEnumerable<SelectListItem>)Model[i].SurveyAnswerOption)
{
#Html.RadioButtonFor(modelItem => Model[i].SelectedSurveyAnswer,
Model[i].SurveyAnswerOption, new { #Checked =
Model[i].SelectedSurveyAnswer}) #item.Text
}
The available options are 'yes', 'no' and 'n/a'. In the database, for example, if 'no' was already selected then it should be pre-selected when this view loads. The radio buttons appear correctly, but, the #Checked doesn't work correctly.
By the way, I am sure there is existing data because I put this line of code as the first line the foreach....
#Html.DisplayTextFor(modelItem => Model[i].SelectedSurveyAnswer);
Any suggestions? Thanks!
Please try this:
#foreach (SelectListItem item in (IEnumerable<SelectListItem>)Model[i].SurveyAnswerOption)
{
#Html.RadioButtonFor(modelItem => Model[i].SelectedSurveyAnswer,#item.Value, Model[i].SelectedSurveyAnswer == item.Value ? new {Checked = "checked"} : null) #item.Text
}

How to detect if a check box is selected using MVC3 Razor

As I am new to MVC framework, I have been spending a couple of hours to generate a check box list in a View file. Finally, I could figure it out well. Here is my code:
#foreach (var item in Model.GetRoleNames)
{
#Html.CheckBox("chk_" + item.Value, new { value = item.Value })#item.Text<br />
}
But, I need to detect which of them is selected and if all the ckeckboxes are left unchecked, then preventing some operations.
Question: How can I get the checked items when I am within a controller action?
As the others said, you should use a Boolean value as the second parameter to CheckBox to indicate the checked status. A bit of string manipulation should help you get the ids of the selected check boxes..
First lets change the way the checkbox helper is used
<div id='myCheckboxDiv'>
#foreach (var item in Model.GetRoleNames)
{
#Html.CheckBox("chk_" + item.Value, false)#item.Text<br />
}
</div>
As you can see, I have set the second parameter to false and wrapped the mix in a div
And, when you want to get the ‘values’ associated with the selected checkboxes
var values = $(‘# myCheckboxDiv’).find('input:checkbox:checked').map(function () {
// get the name ..
var nameOfSelectedItem = this.attr('name');
// skip the ‘chk_’ part and give me the rest
return nameOfSelectedItem.substr(4);
}).get();
I am assuming item.Value to be a number. If its is not, please remove the white spaces using C#

Set the max number of items that can be selectable in ListBoxFor<>

I have a list with 40 results in a list box that can be multi-selected, but I want to limit the number of selections to be only a certain number, let's say 5. In C# MVC, I have:
#Html.ListBoxFor(model => model.Location, new SelectList(Model.AllLocations, Model.Location), new { id = "AllLocations" })
What's the best way to set this constraint on the control?
Javascript. Html provides no mechanism for that. Something like this:
$(document).ready(function() {
// Add a click event for options in the list.
$('#MyModel_Location option').click(function() {
// Check if the parent has reached the limit of selected items.
if ($(this).parent().val().length > 5) {
// Removed the selected attribute from this option.
$(this).removeAttr("selected");
}
});
});

Populate a DropDown/Select based on the value chosen on another DropDown

I'm a beginner developer but I stumbled across a case I can't solve.
I'm using ASP.NET MVC with C# plus some javascript (JQuery, JSON...).
What I have to do is to populate a dropdown based on the value chosen in other.
It seems simple (and I know it is) but this particular case is eluding me.
I've lost many hours and I'm still bonking my head. If anyone can help I'd be very grateful.
My code is as follows:
I have an object of the class "Task" that have both a Phase and an Order. The Orders available to the user in the second dropdown will depend on the Phase this Task was assigned to in the firts dropdown. Order is merely an Int32 (order from ordering in a schedule, not from business order)
The First DropDown uses this IF to check if a session is null, then procedes to show a default message or bring a selected value as default.
<%
if (TempData["TaskObject"] != null)
{
var Phases = new SelectList(ViewData["phaseList"] as List<Phase>, "Phase_ID", "Phase_Name", ((Task)TempData["TaskObject"]).Phase_ID.ToString());
%>
<%=Html.DropDownList("Phase_ID", Phases, new { #class = "textbox"})%>
<%}%>
<%else
{%>
<%=Html.DropDownList("Phase_ID", (new SelectList((List<Phase>)ViewData["phaseList"], "Phase_ID", "Phase_Name")),
"Please Choose...",
new { #class = "textbox"})%>
<%} %>
The second DropDown is much like the first, but its SelectList is a list of lists. Each list contais the possible choices for each choice in the first DropDown. There won't be many, so don't worry about it.
<%if (TempData["TaskObject"] != null)
{
var orderList = (ViewData["orderList"] as List<List<int>>)[0];
var orders = new SelectList(orderList, ((Task)TempData["TaskObject"]).Phase_ID.ToString());
%>
<%=Html.DropDownList("Order_ID", orders, new { #class = "textbox"})%>
<%}%>
<%else
{%>
<%=Html.DropDownList("Order_ID", (new SelectList((List<int>)ViewData["phaseList"], "Phase_ID", "Phase_Name")),
"Please Choose...",
new { #class = "textbox"})%>
<%} %>
The question now is: how do I make the second DropDown change its values based on the selected value in the first DropDown ? I'm very poor at JavaScript (started studying though). We're using JQuery, JSON at the project.
Thanks in advance for your atention.
You basically want to attach a javascript event onto the first drop list and have jquery query a web service (or other) to get the details for that ID. Then in javascript you re-render the second drop list with the available options. A pretty good example is here. Javascript extract from the example is below:
$(function() {
$.getJSON("/Home/Countries/List", function(data) {
var items = "---------------------";
$.each(data, function(i, country) {
items += "" + country.Text + "";
});
$("#Countries").html(items);
});
$("#Countries").change(function() {
$.getJSON("/Home/States/List/" + $("#Countries > option:selected").attr("value"), function(data) {
var items = "---------------------";
$.each(data, function(i, state) {
items += "" + state.Text + "";
});
$("#States").html(items);
});
});
});
You need to catch the first DropDown's change event. and in this populate / select the value you needs.
$('#Phase_ID').change(function(){
var t = $(this);
$('#Order_ID').val(t.val()); // this is only for example.
});
There's a good tutorial on how to do that From Stephen Walther
it should be easy to do

Categories

Resources