Creating dropdowns according to the database - c#

There are different properties for 3 (x,y,z) properties in my database.
I created a dropdown and according to the selection I will make in the dropdown, I want to bring the properties belonging to this property in the database with another dropdown.
(For example I have x, y,z properties. X has ( a,b) , y has (c,d) , z has ( e,f) properties. When I choose the x property in dropdown I want to see a and b properties in the next dropdown. If I choose y property, c and d properties will show up in the next dropdown.)
Beginning of My Code
<form id="CareModal">
#Html.HiddenFor(model => model.PersonID)
#Html.Hidden("DoesAddictionExist", false)
#Html.DropDownList("AddictionStatusID", (IEnumerable<SelectListItem>)ViewBag.AddictionStatus, null, new { #class = "form-control", #onchange = "AddictionChanged(this.value)" })
</form>
Someone said I should use Ajax but I don't know how.

Wherever you want the second dropdown to be put:
<select class="form-control" data-val="true" id="AN ID" name="A NAME (NOT NEEDED)"></select>
In your AddictionChanged method, make an ajax call to the controller.
Something like:
var json = '{dropdownId: ' + //Value passed into function + '}';
$.ajax({
url: '#Url.Action("// Method", "// Controller")',
type:'POST',
data: json,
success: function(result){
// Do whatever
//Create a markup for a select
var markup = "<option Value='0'>Select option</option>";
//Populate the markup
for (var i = 0; i < result.length; i++) {
markup += "<option Value=" + result[i].Value + ">" + result[i].Text + "</option>";
}
//Populate dropdown with value
$("#//DROPDOWNLIST ID").html(markup).show();
}
});
So this calls the controller (that has the parameter dropdownId), passes it an id (whatever you are passing to this function). You, in your controller, would call a service/ db (Not sure how you project is structured) and return a list to this ajax/js function. The code inside the success creates the markup and inserts it inside a dropdown.

Related

Get the value of Html.DropDownList

I currently have the following code in one of my Razor view in an MVC project: <b>Item Code: </b>#Html.DropDownList("ItemID", (SelectList)ViewBag.Items)
I would like to access the value of the drop down list later in an #Ajax.ActionLink in the Razor view. Is there a way to access the value of the drop down list in the view?
Use JQuery to get the current selected value -
$('#dropDownId').val();
If you don't have a special library (like jQuery) to deal with your DOM elements, you can use vanilla Javascript as per the following example:
//get the element by its ID value
var dropdownElement = document.getElementById("ddlItems");
// now we have a reference to the dropdown field, let's read the selected value (or text):
// 1- selected value
var selectedValue = dropdownElement.options[dropdownElement.selectedIndex].value;
// 2- selected text
var selectedText = dropdownElement.options[dropdownElement.selectedIndex].text;
// display a popup with selected text and value
window.alert("selected value is: (" + selectedValue + "), and selected text is: (" + selectedText + ").");
<select id="ddlItems">
<option value="1">1st item</option>
<option value="2">2nd item</option>
<option value="3" selected="selected">3rd item</option>
</select>
If I understand your problem correctly, you're attempting to pass selected value from DropDownList helper into #Ajax.ActionLink helper from the view, which is impossible because #Ajax.ActionLink helper processed and rendered server-side before sending to browser.
You can use #Html.ActionLink helper without routeValues parameter instead and set id attribute of that anchor tag:
#Html.ActionLink("Get Item", "TargetAction", "TargetController", null, new { id = "link" })
Then use unobtrusive AJAX to handle click event of that link and pass selected value from dropdown element there:
$('#link').click(function(e) {
e.preventDefault();
// get selected value from dropdownlist
var selected = $('#ItemID').val();
$.ajax({
type: 'GET',
url: this.href,
data: { id: selected }, // action parameter with selected value
cache: false, // disable caching
success: function (result) {
// do something to target DOM
}
});
return false;
});
Additional notes:
1) Make sure that parameter(s) passed into data setting matches exactly with parameter(s) in the target controller action pointed by href attribute of the link.
public ActionResult TargetAction(int id)
{
// do something
}
2) You can use strongly-typed version of DropDownList, i.e. DropDownListFor to bind viewmodel property.
#Html.DropDownListFor(model => model.ItemID, ViewBag.Items as SelectList, ...)

ASP.Net MVC adding dynamic EditorFor elements

I have a small project with an EditorTemplate.
I show some items which are initially in a List<T> but I want to be able
to add Items when the user presses a Button.
normally I add the items to the View like this
#for (int i = 0; i < Model.Models.Count; i++)
{
#Html.EditorFor(model => model.Models[i], "_AddArticleFullQuantity");
}
When I want to add items dynamically I tried to
create a button which uses ajax to call the server
<button id="addButton" type="button" class="btn btn-default btn-block" onclick="m_GUIRequests.AddArtikelToDiv()">add Article</button>
GUIRequests.prototype.AddArtikelToDiv = function ()
{
this.Request.CallAjax("/NewItemDelivery/GetPartialView_AddArticleFullQuantity", "", GUIRequests.AddToView);
}
GUIRequests.AddToView = function (html) {
$("#addedItems").append(html);
}
The button makes an ajax call to my controller which will do the following
public ActionResult GetPartialView_AddArticleFullQuantity()
{
WrongItemsReceivedModel model = new WrongItemsReceivedModel();
ModelContainer<WrongItemsReceivedModel> container = (ModelContainer<WrongItemsReceivedModel>)TempData["ModelContainer"];
container.Add(model);
return PartialView("~/views/Shared/EditorTemplates/_AddArticleFullQuantity.cshtml", container.Models[0]);
}
And in the end I get what I expected it will show me my template BUT the items initially shown from the List are numbered
So normally I have elements like:
<input class="form-control col-md-6 text-box single-line" data-val="true" data-val-required="MESSAGE" id="Models_0__ModelNumberID" name="Models[0].ModelNumberID" onchange="m_GUIRequests.SetWrongItemsReceivedValues()" type="text" value="">
But I get this:
<input class="form-control col-md-6 text-box single-line" data-val="true" data-val-required="MESSAGE" id="ModelNumberID" name="ModelNumberID" onchange="m_GUIRequests.SetWrongItemsReceivedValues()" type="text" value="">
I think its because I add one with the EditorFor "command" but the other one is added as PartialView.
Is there any way how I can add an EditorFor element so that my logic won't break ?
For editing a variable length list in ASP.NET MVC I would recommending reading the following article. It presents a very clean approach to implement this. On the server you will not need any TempData for persistence and also it illustrates the usage of a nice little helper that will allow you to generate the proper input field names.
As far as your question is concerned, you are correct that the reason why you get wrong input names is because when you return the partial view directly from the controller action, it no longer has the parent context of the Editor Template. There are some ways to circumvent this but it's very hacky and I would rather recommend the approach presented in the article.
Normally i would go for steven sanderson's blog post as Darrin mention as it has become as one of the the industry's standard. Yes partial view is a pain in your scenario.
In your scenario where you would want to keep editor template logic and dynamic added elements linked i would go and generate same name as editor for requries as below
This is my code just to give you the example.
$("#addItemdynamically").click(function () {
$.ajax({
url: '#Url.Action("GetNewGuid", "NewWebForms")',
cache: false,
success: function (newguid) {
id = newguid;
var html = '<tr class="editorRow">' +
'<td><input type="radio" id="Selected" name="Selected" value=' + id + ' /></td>' +
'<td><input type="hidden" name=\OptionsList.Index value=' + id + ' /></td>' +
'<td><input type="text" name=\OptionsList[' + id + '].Text /></td>' +
'<td><input type="hidden" name=\OptionsList[' + id + '].guid value=' + id + ' /></td>' +
'<td> delete</td>' +
'</tr>'
$("#editorRows tbody").append(html);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
}
});
return false;
});
Basically my new guid is getting newly generated guid from the server side and appending it to the row which is generated by pressing add new item button.
you can generate int digit if you like in here but that also require some other hack.

How to handle repeating form fields in ASP MVC

I have a form which asks users for their personal info and their family members.
fields of the family members section is repeating.
my question is what is best practice to handle these kind of repeating forms?
I currently use AJAX to repeat forms but how to collect data from these repeating fields?
since some one asked for how I repeat form, I do it like this:
AJAX Call
$(document).on('click', '.btn-add-item', function (e) {
e.preventDefault();
var $results = $('#results');
$.ajax({
url: '/AJAX/AddFamilyForm',
type: 'post',
success: function (data) {
$(data).appendTo($results);
afterAJAX();
}
});
});
C# code
[HttpPost]
public PartialViewResult AddFamilyForm()
{
if (!Request.IsAjaxRequest()) return null;
return PartialView("_FamilyForm");
}
This is some skeleton code on how to get this to work with proper model-binding in MVC. You'll need to write some JS to be able to delete/add new rows.
Model
public class MyModel
{
public FamilyMembers[] FamilyMembers { get; set; }
}
View
<button id="addNewFamilyMember" type="button">Add</button>
#if (Model.FamilyMembers != null)
{
for (int i = 0; i < Model.FamilyMembers.Length; i++)
{
<tr>
<td>
<button type="button">Delete</button>
#Html.Hidden("FamilyMembers.Index", i)
</td>
<td>
#Html.TextBoxFor(m => Model.FamilyMembers[i].Relation)
</td>
<td>
#Html.TextBoxFor(m => Model.FamilyMembers[i].FullName)
</td>
</tr>
}
}
Below is the code for adding a new member. It creates html dynamically and is able to bind to the posted model because of naming conventions. time gives each added row a unique id so all the data stays together.
JS (using Jquery)
var hidden = '#Html.Hidden("FamilyMembers.Index", "{id}")';
var relationHtml = '#Html.TextBox("FamilyMembers[{id}].Relation")';
var fullNameHtml = '#Html.TextBox("FamilyMembers[{id}].FullName")';
$("#addNewFamilyMember").on("click", function () {
var time = Date.now();
var deleteHtml = "<button type='button'>Delete</button>";
$("#familyMembers-table").find("tbody")
.append($("<tr><td>" + hidden.replace("{id}", time) + deleteHtml + "</td>" +
"<td>" + relationHtml.replace("{id}", time) + "</td>" +
"<td>" + fullNameHtml.replace("{id}", time) + "</td></tr>"));
});
One of the solution could be combination of hidden field and control name.
Steps:
Use a hidden field to keep the count the number of row.
Create controls with name like text_relation_1 for first row and text_relation_2 for second row and so on
Generate other controls in same way.
Increase and decrease the hidden field value so that when values post you can know the number of rows added by the user
On your action use FormCollection and loop though hidden field number and get the values from FormCollection
Like suppose I created 3 rows then I can create a action like below
public ActionResult SomeActionMethod(FormCollection formCollection, string hid)
{
for(int i=1;i<hid;i++)
{
var relationId="text_relation_"+i;
var firstrealtion=formCollection[relationId];
...
}
}
You don't need any extra Ajax requests for this, since you can use established and standard <form> features.
Just append [] to the name of the added forms and you'll end up with an array rather than a single value in your HTTP request once the form is submitted:
<input type="text" name="relation[]" /><input type="text" name="fullname[]" />
<input type="text" name="relation[]" /><input type="text" name="fullname[]" />
<input type="text" name="relation[]" /><input type="text" name="fullname[]" />
In this example you'd end up with an array relation and an array fullname, both containing your datasets.

Assigning value to Html.DropdownList from a controller method via ViewBag

I have a #Html.DropDownList on my view whose initial values are null. The values of the list must be populated based on the selected value from an other dropDownList. I have my two dropDownLists as below
<div class="col-sm-7">
#Html.DropDownList("City", null, new {#id="City", #class="form-control"})
</div>
<div class="col-sm-7">
#Html.DropDownList("Theatre", null, new {#id = "Theatre", #class = "form-control"})
</div>
Theatre must be populated based on the value selected in the dropDown list for city. As Theatre cannot be null, I initially set the ViewBag.Theatre to an empty list in my controller's action method. Once a city is selected, I am doing an ajax call from jQuery to call a different method in my controller to set the ViewBag.Theatre to my returned list.
But the contents of the Theatre dropDown are still empty. How do I refresh the contents of the dropDown after the ViewBag.Theatre value is changed?
Here is my jQuery to call the controller method
$("#City").change(function() {
if ($("#City").val() != 0) {
var ty = $("#City").val();
$.ajax({
url: rootDir + "/AnalysisHistory/SetTheatres",
data: {city: city },
type: "POST",
dataType: "html",
success: function () {
$(".form").show();
$("#loading").hide();
$("#analysisDetails").slideDown('slow');
});
} else {
$(".form").hide();
}
});
On change for the dropdown list for the city, here is what I did to populate the theaters drop down:
•I emptied the contents of the dropdown list for the theaters
•As I am receiving the new list as a JSON, on Success, I am re-populating the list with new contents. Here is my code
success: function (datax) {
var result = "";
var listObj = $.parseJSON(datax);
$(listObj).each(function (i, val) {
result += '<option value="' + val.Value + '">' + val.Text + '</option>';
});
$("#Theatre").html(result);
$(".form").show();
$("#loading").hide();
$("#analysisDetails").slideDown('slow');
}

MVC Cascading Drop Down Not Selected When Editing

I am developing an MVC 4 web application. One of the Razor views has two drop down lists. The first drop down list is populated by the ViewModel data which is passed to the view. The secondary drop down list is populated using a JQuery and Ajax call based on the selected ID from the first drop down list (cascading).
I have this working fine, however, whenever a user wishes to edit an existing record I can't get the selected secondary drop down list value to be selected.
This is my Razor code for the two drop down lists
<div class="lbl_a">
Employer:
</div>
<div class="editor-field sepH_b">
#Html.DropDownListFor(model => model.Employer, Model.EmployerList, "Select", new { #class = "inpt_a" })
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DirectorateID, "Directorate/ Service Group")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.DirectorateID, Model.DirectorateList, "Select")
</div>
This is my JQuery code
$(document).ready(function () {
//Pre load on page load
onEmployerChange();
//Hide and show DIVS based on selection
$("#Employer").change(onEmployerChange);
function onEmployerChange() {
var dataPost = { orgID: val };
$.ajax({
type: "POST",
url: '/User/GetDirectorates/',
data: dataPost,
dataType: "json",
error: function () {
alert("An error occurred." + val);
},
success: function (data) {
var items = "";
$.each(data, function (i, item) {
items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";
});
$("#DirectorateID").html(items);
}
});
}
}
});
When a user selects a value from the first drop down list, the selected ID is passed to the GetDirectorates action within the User Controller.
This is my GetDirectorates action which returns Json data
public ActionResult GetDirectorates(string orgID)
{
if (String.IsNullOrWhiteSpace(orgID))
orgID = "0";
var Directorates = _ListService.GetListItemsByOrganisationID(Convert.ToInt32(orgID));
List<SelectListItem> directorateList = new List<SelectListItem>();
directorateList.Add(new SelectListItem() { Text = "Select", Value = "" });
foreach (var directorate in Directorates)
{
directorateList.Add(new SelectListItem() { Text = directorate.description, Value = directorate.listItemID.ToString(), Selected = false });
}
return Json(new SelectList(directorateList, "Value", "Text"));
}
Whenever the users wishes to edit an existing record I pass both the values for the first and second drop down list. Both drop down lists are populated with the proper data as expected, however, the selected value for the second drop down list is never selected.
This is a shortened version of the Edit action which the user calls when attempting to edit an existing record but shows the two drop down list selected values being passed.
public ActionResult EditNonMember(int id, string feedback, string courseDateID, string courseID)
{
//code to retrieve data here
vm.Employer = UserDetails.Employer;
vm.DirectorateID = UserDetails.DirectorateID;
return View(vm);
}
Would anyone be able to help me with this?
Thanks.
You need to get the directorate list for the saved employer id and set the DirectorateList collection and then the DirectorateID (from saved record);
public ActionResult EditNonMember(int id, string feedback, string courseDateID,
string courseID)
{
//code to retrieve data here
var userDetails=repositary.GetUserFromSomeId(id);
vm.Employers=GetEmployers();
vm.Employer = userDetails.Employer;
vm.DirectorateList=GetDirectorateListForEmployer(userDetails.Employer);
vm.DirectorateID = userDetails.DirectorateID;
return View(vm);
}
private List<SelectListItem> GetEmployers()
{
// to do : Return all employers here in List<SelectListItem>
}
private List<SelectListItem> GetDirectorateListForEmployer(int employerId)
{
// to do : Return all Directorates for the selected employer
}
This should do the trick:
var subSelect = $("#DirectorateID");
// clear the selection
subSelect.empty();
//append each option to the list
$.each(data, function (i, item) {
subSelect.append($('<option/>', {
value: item.Value,
text: item.Text
}));
});
Rather than setting it via the html method, I'm simply appending an option.
This is the method I use for cascading dropdown lists using ajax.

Categories

Resources