Passing list of dynamically created dropdownlists to controller in MVC - c#

I have a MVC5 project with a form where the user can click and add new dropdowns dynamically, it uses select2 and ajax to get the posible values and filter...
//ViewModel
public class MyViewModel
{
public List<string> Skus { get; set; }
//Tried public List<List<string>> Skus { get; set; } w/no success
}
//MVC Razor view
<div id="SkuContainer">
Product variations: #Html.DropDownListFor(m => m.Skus, Enumerable.Empty<SelectListItem>(), "Select", new { multiple = "true", #class = "Skus", #id = "Skus1" })
</div>
<input id="btnAddSku" type="button" value="Add variations" class="btn btn-primary" />
<input id="btnRemoveSku" type="button" value="Remove variations" class="btn btn-danger" />
....
$(document).ready(function () {....
$("#btnAddSku").on("click", function () {
var i = 2;
var dropdown = "<select data-val='true' class='Skus' id=Skus" + i + " name=Skus style='width:1000px' multiple> </select >";
var VariationContainer = "<div id='variationsdiv'><br/> Product variations: " + dropdown + " </div>";
$("#SkuContainer").append(VariationContainer);
i++;
});
...
//Controller:
public ActionResult Confirm(MyViewModel model)
{
Debug.WriteLine(model.Skus ) // I get all the selected values, it works but I can't diferenciate each dropdown because of how the model is structured.
}
How can I set the model and the view to get a list of lists of selected values so I can diferentiate each dropdown?
Thank you

Related

My cascaded dropdowns losing selected values after submit in ASP.NET Core MVC?

How can I keep selected values for both dropdown after submit action?
In my scenarios, my cascaded dropdown is populating from partial view. I'm new to ASP.NET Core MVC. Let me know if you want more clarifications.
My view:
<form asp-controller="Recommendation" asp-action="SubmitData" method="post">
<select id="States" class="form-control selectpicker" asp-for="StateID" asp-
items="#(new SelectList(ViewBag.StateList,"StateID","State"))"
placeholder="Select Categories"
onchange="console.log($(this).children(':selected').length)">
</select>
#Html.DropDownListFor(m => m.CityID, new SelectList(""), new {#class="select2
form-control", #style = "width: 100%" })
<button id="btnSubmit" class="btn btn-secondary btn-sm">Submit</button>
</form>
onChange function on first dropdown to call 2nd one:
<script type="text/javascript">
$(document).ready(function () {
$("#States").change(function () {
var StateID = $(this).val();
/*debugger;*/
$("#CityID").empty();
$.ajax({
type: "Get",
url: "/Recommendation/GetCityList?iStateID=" + StateID,
contentType: "html",
success: function (response) {
$("#CityID").append(response);
},
error: function (jqXHR, textStatus, errorThrown) {
}
})
})
});
</script>
Partial View for Child dropdown
<option value="">Select City</option>
#if (ViewBag.CityOptions != null)
{
foreach(var item in ViewBag.CityOptions)
{
<option value="#item.Value">#item.Text</option>
}
}
Controller:
[HttpGet]
public ActionResult IndexGet()
{ // From where I get values.
Entity entity = new Entity();
StateList = gateway.SelectList();
StateList.Insert(0, new Model { StateID = 0, State = "Select State" });
ViewBag.StateList = StateList;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SubmitData(RecommendModel recommendModel)
{ // Submit form method and I used RedirectToAction for calling view again.
{
}
return RedirectToAction("IndexGet", "Recommendation");
}
[HttpGet]
public ActionResult GetCityList(long iStateID)
{ // For partial call
Entity entity = new Entity();
MCAlist = entity.GetCityList(iStateID);
ViewBag.CityOptions = new SelectList(MCAlist,"MCAID","MCA");
return PartialView("_CityOptionPartial");
}
Looks like maybe you are using the bootstrap-select plugin. You can try adding $(this).selectpicker('refresh'); at the top of your change event.

Filling Cascading dropdown from database during edit

I need help filling dependent dropdowns. I have dependent dropdown that work when entering data, select the State dropdown and the dependent dropdowns reload based on the state selected.
Issue is when I want to edit, the state is filled and selected from database, but the dependents don't get filled and selected. The onChange function doesn't get activated or hit.
Here are my codes:
<div class="form-row">
<div class="col">
<div class="form-group">
<label asp-for="Sposted"></label>
<select asp-for="Sposted"
class="form-control"
asp-items="#(new SelectList(#ViewBag.statelist, "Stateid", "Statename" ))"
onchange="sposted(this)">
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="Pcommand"></label>
<select asp-for="Pcommand" class="form-control" id="Pcommand"
asp-items="#(new SelectList(string.Empty, "Commandid", "Cfname"))">
<option>Select ...</option>
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="PayP"></label>
<select asp-for="PayP" id="PayP"
class="form-control"
asp-items="#(new SelectList(string.Empty, "Ppid", "Ppfull"))"></select>
</div>
</div>
</div>
The 2 dropdowns, Pcommand and PayP are dependent on sposted. Again, when editing, the sposted drop down is selected and filled from db, but doesn't cascade to the other 2.
Here is the JS:
<script type="text/javascript">
//$(document).ready(function () {
//$('#Sposted').change(function () {
function sposted(stateid) {
console.log(stateid.value);
var url = '#Url.Content("~/")' + "MemberList/RetPayPoint";
//var ddlsource = "#Sposted";
//$.getJSON(url, { Stateid: $(ddlsource).val() }, function (data) {
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
}//});
// });
</script>
Thank you in advance.
A few days later, I have decided to add the controller method that is supposed to fill the dropdowns in the view.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
//memid = memlist.FirstOrDefault().MemberId;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
return View(obj);
}
All he information needed to fill the view elements are in obj. It loads the selects the state from the id in obj, but the onchange isn't fired to fill the dependent dropdowns.
When editing using selected stateid you need to get both dropdowns data, just like you are getting PayP data by using selected stateid like:
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
You will call your function sposted and pass selected stateid both times while creating or editing.
After days of research, I couldn't seem to find a way to to force the onchange to call Ajax to dynamically fill the dependent dropdowns. So I took a cue from Mateen's 3rd comment and rewrote the method in the controller to read load the relevant items into a ViewBag.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
ViewBag.payp = _mr.GetPayPoint(obj.Sposted.Value).ToList();
ViewBag.pcommand = _mr.GetCommand(obj.Sposted.Value).ToList();
return View(obj);
}

How to increase value on button click with controller

I want to be able to increase the criteria number on button click
HTML Code:
<div class="criteria-header">
<span class="criteria-value">Criteria #ViewData["criteriaNo"]</span>
<div id="criteria-image">
<img src="~/images/red-cross.png" style="width: 100%" />
</div>
</div>
<input type="submit" value="Add new criteria" class="btn background-gold btn-180 btn-login col-2 criteria-btn" formaction="AddCriteria"/>
<input type="submit" value="Create" class="btn background-gold btn-180 btn-login col-2 criteria-btn" formaction="Create"/>
When i click on add criteria i need it to increase the criteria number to 2,3,4 and so on.
But because in the controller i set the criteria number to 1 everytime i click the button it will run through the controller and keep resetting the data.
public class JudgeController : Controller
{
int criteriaNo = 1;
public ActionResult JudgeCriteria()
{
ViewData["ShowCriteria"] = showCriteria;
ViewData["criteriaNo"] = criteriaNo;
Console.WriteLine(criteriaNo);
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddCriteria()
{
criteriaNo += 1;
showCriteria = true;
return RedirectToAction("JudgeCriteria");
}
}
Pass your criteria number from client side so you will be able to add it subsequently. And
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddCriteria(int number = 1)
{
number += 1;
showCriteria = true;
return RedirectToAction("JudgeCriteria", new { criteriaNo = number});
}
public ActionResult JudgeCriteria(int criteriaNo)
{
ViewData["ShowCriteria"] = showCriteria;
ViewData["criteriaNo"] = criteriaNo;
Console.WriteLine(criteriaNo);
return View();
}
After this pass your criteria from frontend and you will be good to go!

Multi select drop-down items auto select attribute on update

On a page i have a multi select drop-down menu. It works fine whenever i need to insert data BUT a problem accrues when i need to update the inserted data.
The Problem Whenever i click the edit button next to my data (in my case - about book data) every field inside the Form fills up but the select drop-down menu items does not get auto selected to what was previously selected. I have to re-select it manually again. The process of updating the data itself works fine (once i re-select it again).
It uses many-to-many relationship. Worked fine when i used check-boxes but I want to re-do it on drop-down menu.
The Controller
public ViewResult Index(int? Id)
{
SelectList selectList = new SelectList(_authorRepository.GetAllAuthors()
.Select(x => new { x.Id, Title = x.Name + " " + x.Lastname }), "Id", "Title");
BooksIndexViewModel viewModel = new BooksIndexViewModel()
{
Books = _booksRepository.GetAllBooks(),
AuthorOptions = selectList,
authors = _authorRepository.GetAllAuthors(),
Book = _booksRepository.GetBook(Id ?? 0),
publishers = _publisherRepository.GetAllPublishers(),
indexPage = _dataRepository.Generatedata("Knygos", Id,
ControllerContext.RouteData.Values["controller"].ToString())
};
return View(viewModel);
}
The AuthorOptions is what passes the asp-items.
The Form itself uses Book.
Index.cshtml (other lines where removed, only form left)
<form asp-controller="#Model.indexPage.controller"
asp-action="#Model.indexPage.action"
asp-route-id="#if (Model.indexPage.routeId.HasValue) {#Model.indexPage.routeId.Value}" method="post">
<div class="inputs">
<div> <input asp-for="#Model.Book.Title" /> </div>
<div> <select asp-for="#Model.Book.BookAuthors"
asp-items="#Model.AuthorOptions" name="author[]"></select> </div>
<div>
<select asp-for="#Model.Book.PublisherId"
asp-items="#(new SelectList(Model.publishers, "Id", "Title"))"></select>
</div>
<div><input asp-for="#Model.Book.Cost" /></div>
<div><input asp-for="#Model.Book.Code" /></div>
<div><input asp-for="#Model.Book.InvNr" /></div>
<div><input asp-for="#Model.Book.Description" /></div>
</div>
<button type="submit">Save</button>
</form>
The line that im after is <select asp-for="#Model.Book.BookAuthors" asp-items="#Model.AuthorOptions" name="author[]"></select>. It, and the entire Form, gets data form my repository.
The repository
public Book GetBook(int Id)
{
return db.Books.Include(x => x.BookAuthors).SingleOrDefault(x => x.Id == Id);
}
The Value inside the drop-down is AuthorId, the BookAuthors inside the Book model is a IList and connected to a BookAuthor model:
public class BookAuthor
{
public int BookId { get; set; }
public Book Book { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; }
}
So the problem is, why whenever i get the Book's data (from my Id) all the fields (including PublisherID that is a drop-down but single-to-single connection) gets selected BUT my Authors drop-down does not? What am I missing?
EDIT 1
By changing asp-for="#Model.Book.BookAuthors" => asp-for="#Model.Book.BookAuthors[0].AuthorId" Does the Trick in order to get selected BUT if the book data has more then 1 author, only 1 author is selected from drop-down meniu. + the drop-down becomes no longer multi-select but can be overridden by adding attribute multiple but still only select 1 item from the drop-down menu.
Figured out a trick.
In a viewModel created a IList of integer public IList<int> AuthorIds. inside the .cshtml, int the asp-for="" used the newly created integer list AuthorIds. Inside the controller, the AuthorIds in the ViewModel gets passed with _booksRepository.GetBook(Id).BookAuthors.Select(x => x.AuthorId).ToList();
So the project looks like this:
Controller
public ViewResult Index(int? Id)
{
BooksIndexViewModel viewModel = new BooksIndexViewModel()
{
Books = _booksRepository.GetAllBooks(),
AuthorOptions = new SelectList(_authorRepository.GetAllAuthors()
.Select(x => new { x.Id, Title = x.Name + " " + x.Lastname }), "Id", "Title"),
Book = _booksRepository.GetBook(Id),
publishers = _publisherRepository.GetAllPublishers(),
indexPage = _dataRepository.Generatedata("Knygos", Id,
ControllerContext.RouteData.Values["controller"].ToString())
};
if (Id != null)
viewModel.AuthorIds = _booksRepository.GetBook(Id).BookAuthors.Select(x => x.AuthorId).ToList();
return View(viewModel);
}
cshtml
<form asp-controller="#Model.indexPage.controller" asp-action="#Model.indexPage.action"
asp-route-id="#if (Model.indexPage.routeId.HasValue) {#Model.indexPage.routeId.Value}"
method="post" class="form grid">
<div class="inputs">
<div><input asp-for="#Model.Book.Title" class="w100" /></div>
<div><select asp-for="#Model.AuthorIds" asp-items="#Model.AuthorOptions"
name="author[]" multiple></select></div>
<div><select asp-for="#Model.Book.PublisherId"
asp-items="#(new SelectList(Model.publishers, "Id", "Title"))">
</select></div>
<div><input asp-for="#Model.Book.Cost" /></div>
<div><input asp-for="#Model.Book.Code" /></div>
<div><input asp-for="#Model.Book.InvNr" /></div>
<div><input asp-for="#Model.Book.Description" /></div>
</div>
<button type="submit">Save</button>
</form>
Nothing else has changed.

How to get the selected item from a DropDownList?

I know this is a question that many people responded on the site , but no solution seems to work to my problem.
I am new to MVC and do not know how to send the selected item in the drop down list to the controller .
public class MonthDropDownList
{
public IEnumerable<SelectListItem> Months
{
get
{
return DateTimeFormatInfo
.InvariantInfo
.MonthNames
.Where(m => !String.IsNullOrEmpty(m) )
.Select((monthName, index) => new SelectListItem
{
Value = (index + 1).ToString(),
Text = monthName
});
}
}
public int SelectedMonth { get; set; }
}
Here is my view :
#model Plotting.Models.MonthDropDownList
#Html.DropDownListFor(x => x.SelectedMonth, Model.Months)
#using (Html.BeginForm("MonthlyReports", "Greenhouse", FormMethod.Post))
{
<input type="submit" name="btnSubmit" value="Monthly Report" />
}
And here is the ActionResult in which i should use the selected date :
public ActionResult MonthlyReports(MonthDropDownList Month)
{
Debug.Write("Month" + Month.SelectedMonth);// <- always = 0
InitChartModel();
cDate.DateTitle = "Day";
string msg = dal.Connection("month");
List<Greenhouse> greenhouse = dal.FindIfDMY("month" , Month.SelectedMonth , msg);
cDate.DateData = GetChart(greenhouse, "month");
return View("MonthlyReports", cDate);
}
You should move your DropDownList into your form.
#model Plotting.Models.MonthDropDownList
#using (Html.BeginForm("MonthlyReports", "Greenhouse", FormMethod.Post))
{
#Html.DropDownListFor(x => x.SelectedMonth, Model.Months)
<input type="submit" name="btnSubmit" value="Monthly Report" />
}
Your form control needs to be inside the form tags
#using (Html.BeginForm("MonthlyReports", "Greenhouse", FormMethod.Post))
{
#Html.DropDownListFor(x => x.SelectedMonth, Model.Months) // move here
<input type="submit" name="btnSubmit" value="Monthly Report" />
}

Categories