Save multiselect c# - c#

I use cshtml for my select:
<div class="form-group">
<label class="control-label col-md-2" for="Ligne">Ligne</label>
<div class="container">
<select name="Ligne" id="ligne" class="selectpicker" title="Select something" data-live-search="true" multiple="multiple">
#foreach (var item in Model.allLignes)
{
<option value=#Html.DisplayFor(modelItem => item.CodeLigne)>#Html.DisplayFor(modelItem => item.CodeLigne)</option>
}
</select>
</div>
</div>
But when I send form, it saves only one value...
Can you help me?
my controller:
public ActionResult Create([Bind(Include = "Id,name,begin,end,Ligne")] RT TypeRT)
cmdPerso.CommandText = "insert into RT (name, begin, end, Ligne, CreateBy) VALUES ('" + TypeRT.name+ "','" + TypeRT.begin+ "','" + TypeRT.end+ "','" + TypeRT.Ligne+ "','" + User.Identity.Name + "')";
I want to use this select expression for edit form.
Thank you in advance.

First, change the type of your TypeRT.Ligne to List<string> (you can change string to another type if needed, like List<int>).
Now your controller will get the list of selected values, but then your query must save them. Ideally, this list should be saved in another table and you should save each value in a separate row. That's a good normalized design.
However, it seems from your code that you save the list in a single field of the same table, perhaps comma-separated? That's not a good design and it needs to be normalized like I mentioned above, but if you really want to do so then you have to join the array items using the separator that you want:
String.Join(",", TypeRT.Ligne);
If you're using .NET < 4, you have to use ToArray first:
String.Join(",", TypeRT.Ligne.ToArray());
Note: your query is vulnerable to SQL injection. Use a parameterized query instead.

Work with the tools that the ASP MVC framework provides:
In your ViewModel, the property to which the selected values are bound must be an array. Available options can be stored in the MultiSelectList class.
using System.Web.Mvc;
public class MultiSelectViewModel {
/// <summary>
/// Selected values of the multi select.
/// </summary>
public string[] SelectedValues { get; set; }
/// <summary>
/// Possible options.
/// </summary>
public MultiSelectList AvailableOptions { get; set; }
}
In your Controller (GET case), assign the available options:
MultiSelectList can be instantiated by passing a collection of options and the names of the properties that hold the Value and Text of an option (e.g. "CodeLigne").
Ligne[] allLignes = DbContext.Lignes.ToArray(); // all possible options
// for edit use case: the options that have been selected during create use case
string[] previouslySelectedLigneCodes = new { "1", "3" };
// your ViewModel containing the multiselect properties
var vm = new MultiSelectViewModel();
vm.AvailableOptions = new MultiSelectList(
allLignes, "CodeLigne", "NomLigne", previouslySelectedLigneCodes);
In your View, you can render the MultiSelect using ListBoxFor:
#model MultiSelectViewModel
<label for="#Html.IdFor(m => m.SelectedValues)">Ligne</label>
#Html.ListBoxFor(m => m.SelectedValues, Model.AvailableOptions,
new {#class = "selectpicker", title ="Select something"})
Further reading: Step-By-Step Implementation of MultiSelectList In .NET MVC.

Related

Putting data from two tabels in one ViewData

I'm trying to put data form two tabels (AcademicDegrees, Lecturers) conneted by one to many relation into one ViewData to generate options to field (with label and id as value). It shoud be somthing like this where id are used as values nad other field as label.
ViewData["ClassroomsId"] = new SelectList(_context.Classroom, "ClassroomsID", "Number");
When all the date for field was in one table I used getter form field to get it.
[NotMapped]
public string toStringVar => FirstName + " " + LastName;
When I added tabel with academic degrees I moved to different solution.
var lecturers = _context.Lecturer;
var degree = _context.AcademicDegrees;
var lecturersList = new List<SelectListItem>();
foreach (Lecturers l in lecturers)
{
_context.AcademicDegrees.Where(d => d.AcademicDegreeId == l.AcademicDegreesId).Load();
foreach(AcademicDegrees d in degree)
{
lecturersList.Add(new SelectListItem(
$"{d.Name} {l.FirstName} {l.LastName}", l.LecturersID.ToString()
));
}
}
ViewData["LecturersId"] = new SelectList(lecturersList);
The problem is that it isn't interpreted as I want it to be.
I also can't put it directly in to SelectList because it doesn't have empty constructor or add method. Is there any other way to implement a SelectList?
In my opinion, it is like redundant work as you have the IEnumerable<SelectListItem> instance which can be used to build the select option.
And you pass IEnumerable<SelectListItem> instance to create the SelectList instance.
Would suggest to pass IEnumerable<SelectListItem> value to ViewData.
Solution for IEnumerable<SelectListItem>
Controller
ViewData["LecturersId"] = lecturersList;
View
#Html.DropDownListFor(model => model./*YourProperty*/, (IEnumerable<SelectListItem>)ViewData["LecturersId"])
Updated
Since you are using ASP.NET Core MVC, with tag helper:
<select asp-for="/*YourProperty*/"
asp-items="#((IEnumerable<SelectListItem>)ViewData["LecturersId"]))">
</select>
Solution for SelectList
If you are keen on the SelectList, make sure that you have provided the dataValueField and dataTextField according to this constructor
public SelectList (System.Collections.IEnumerable items, string dataValueField, string dataTextField);
as below:
ViewData["LecturersId"] = new SelectList(lecturersList, "Value", "Text");
Besides, the query part would be suggested to optimize by joining both tables as below:
var lecturersList = (from a in _context.Lecturer
join b in _context.AcademicDegrees on a.AcademicDegreeId equals b.AcademicDegreeId
select new SelectListItem($"{b.Name} {a.FirstName} {a.LastName}", a.LecturersID.ToString())
).ToList();

Asp.net Core, set multiple selected values in Razor Page

So, I am trying to create a multi-select dropdown list and I want to set some default selected values in it. I get the values and store them in an array of strings containing the values in each one. I tried to set them as 1 string and it didn't work, tried setting them as an array of strings and it didn't work as well.
Here is the code:
<select name="FacultyList" multiple class="sel form-control" asp-for="Faculties"
id="uniFaculties" asp-items="#(new SelectList(facultyList,"Name","Name",#selectedFaculties))">
</select>
facultyList is a list of values I get from and api.
selectedFaculties is an array of strings that contains the selected values.
Note: I'm using the Chosen jQuery library as well if that makes a difference.
There is a MultiSelectList that you can use for this:
new MultiSelectList(facultyList, "Name", "Name", #selectedFaculties)
I just noticed from your code that you're using asp-for on the select. When doing that, the selected values you pass to either SelectList or MultiSelectList will be ignored. The reason is because it's expecting the selected values to be in the Faculties property that you're binding to. In case you run into that, here is a working example for you.
View
<select name="FacultyList" multiple class="sel form-control" asp-for="SelectedFaculties"
id="uniFaculties" asp-items="#(new MultiSelectList(Model.AvailableFaculties, "Name", "Name"))">
</select>
Controller
public IActionResult Faculty()
{
var vm = new FacultyViewModel
{
AvailableFaculties = new List<Faculty>
{
new Faculty
{
Name = "Arts"
},
new Faculty
{
Name = "Science"
},
new Faculty
{
Name = "Mathematics"
}
},
SelectedFaculties = new List<string> { "Arts", "Mathematics" }
};
return View(vm);
}
This will select Arts and Mathematics. Notice that the selected values are coming from the same property that we're binding the select to using asp-for, and that we're no longer passing selected values to the MultiSelectList directly.

Default value of DropDownList in an Html.BeginForm block

While a search of "Default value of DropDownList" produces results, this is not a duplicate question because the specific issue is not listed in the examples and answers I have searched.
Here is the main question first, followed by supporting background and details:
When I place a DropdownList in an Html.BeginForm block, how can I have the default DropDownList values be an item other than the first item in the list?
What I have done so far:
SO, Microsoft Virtual Academy, and a general Internet Search using various search terms, with no effective answers that solve this specific issue.
Looking at the overloads of Html.DropDownList on MSDN. The optionLabel parameter inserts an item at the very top of the list, such as "Select an Item", which is not desired behavior.
jQuery, which does work as intended, but I'm really hoping there is a much simpler way that doesn't involve jQuery.
My Working Theory: The method I learned (and shown below) does not allow for default values and it is not a case of not knowing a particular overload of Html.DropDownList.
Background Info:
In the process of learning MVC 5 and gathering instructions from tutorials and SO answers, I learned this style of creating a DropDownList that is placed within a Html.BeginForm() block in the View. It works, if I want the default value to be the first item in the list or if I want to add an item inserted at the top that says "select an item."
However, there are times when it is meaningful to for the default value to be other than the first in the list.
In the controller, the defaults of the parameter are set Index(string campus = "MRA", string fy = "FY16"), and the query returns the correct result, but DropDownLists are not set accordingly when loading the page for the very first time.
Controller
public ActionResult Index(string campus = "MRA", string fy = "FY16")
{
/* The ViewBags feed DropDownLists used to filter the query */
ViewBag.CampusList = new List<string> { "CRA","DRA","MRA","PRA"};
ViewBag.FyList = new List<string> {"FY15","FY16" };
IEnumerable<AssociatedW3SuspensionOrProbation> query =
db.AssociatedW3SuspensionOrProbation
.Where(m=>m.Campus==campus).Where(m=>m.FY==fy)
.OrderBy(m=>m.StudentName).ThenBy(m=>m.LatestEntryDate);
return View(query.ToList());
}
View
The dropdowns function correctly: when the form is submitted, the query results are chosen by the selected dropdown values and the dropdowns load with the selected values.
#using (Html.BeginForm())
{
<div class="panel panel-default">
<div class="panel-body">
<p>
<strong>Campus</strong>: #Html.DropDownList("campus",
new SelectList(ViewBag.CampusList)) ||
<strong>FY</strong>: #Html.DropDownList("fy",
new SelectList(ViewBag.FyList))
</p>
<div><input type="submit" value="Search" /></div>
</div>
</div>
}
Is there a simple answer to this problem, or does this require a totally different approach?
What you have to do is create SelectList in the controller action and there is a constructor overload which can be used to set selected value, but for that you would need a List<T> which is not string but a custom type that contains 2 properties 1 for TextField and 1 for ValueField.
You have to use second Constructor overload listed here
Here is the example code:
ViewBag.CampusList = new SelectList(
new List<string> { "CRA","DRA","MRA","PRA"},
campus // selected value
);
ViewBag.FyList = new SelectList(
new List<string> {"FY15","FY16" },
,fy // selected value
);
and in your view:
#Html.DropDownList("campus",
ViewBag.CampusList as SelectList)
#Html.DropDownList("fy",
ViewBag.FyList as SelectList)

How to use grid in VS2010 MVC3 to add and edit data?

I'm using Microsoft VS 2010 C#, MVC3.
I have Calsserooms and Students with many to many relation ship, so I add an intermediat table called Classroom_Students.
When adding students to a classroom, I use a combo box in my view filled with all students names, I choose one by one in every submit
#using (Html.BeginForm("AddStudentToClassroom", "Calssrooms", FormMethod.Post))
{
#Html.LabelFor(c=>c.Students, "Choose a Student")
<select name = "StudentID">
#foreach (var it in Model.Students)
{
<option value="#it.ID">#it.StudentName </option>
}
</select>
<input type="submit" value= "Add" />
}
My question is:
How can I use gride, instead of this combo, to select many students, select all or deselect all to add???
I'll appreciate any help.
This is the code in my controller.
For page first call, I fill combobox as following:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult AddStudentToClassroom(int id) //id of calssroom
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails (); // these are for
ClsromView.Classroom = en.Classroom.Single(c => c.ID == id);// loading calssroom information and to
ClsromView.Students = en.Students.ToList(); // fill students list for the combobox
return View(ClsromView);
}
}
When submiting the form, view, and click the add button, it calls the following overloaded add function for saving data:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddStudentToClassroom(AddStudToCals ClasStud) //ClasStud is the submited data from the view
{
using (ExaminationEntities en = new ExaminationEntities())
{
ClassroomDetails ClsromView = new ClassroomDetails(); // these are for
ClsromView.Calssroom = en.Calssroom.Single(c => c.ID == ClasStud.ClassroomID); // loading calssroom information and to
ClsromView.Students = en.Student.ToList(); // fill students list for the combobox
using (ExaminationEntities exn = new ExaminationEntities())
{
Calssroom_Student To_DB_ClasStud = new Calssroom_Student (); //To_DB_ClasStud object to get the submited values and to save it in the DB
To_DB_ClasStud.CalssroomID = ClasStud.CalssroomID;
To_DB_ClasStud.StudentID = ClasStud.StdentID;
en.AddToClassroom_Student(To_DB_ClasStud);
en.SaveChanges();
}
return View(ClsromView);
}
}
Well, the option that requires the least changes to your markup is to add the multiple property to your select. Then, change the action method to accept a params int[] ids, iterate through them, and you should be good-to-go. At worst, you might have to change your parameter to a string and do a Split() on ,, but I don't recall that being how the model binder supports multi-selects.
If this doesn't seem to fit your needs, there is an article on the ASP.NET website that explains using a MultiSelectList to bind to the ListBox helper, here:
http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc

ASP.NET MVC DropDownListFor with model of type List<string>

I have a view with a model of type List<string> and I want to place a drop down list on the page that contains all strings from the list as items in the drop down. I am new to MVC, how would I accomplish this?
I tried this:
#model List<string>
#Html.DropDownListFor(x => x)
but that threw an error.
To make a dropdown list you need two properties:
a property to which you will bind to (usually a scalar property of type integer or string)
a list of items containing two properties (one for the values and one for the text)
In your case you only have a list of string which cannot be exploited to create a usable drop down list.
While for number 2. you could have the value and the text be the same you need a property to bind to. You could use a weakly typed version of the helper:
#model List<string>
#Html.DropDownList(
"Foo",
new SelectList(
Model.Select(x => new { Value = x, Text = x }),
"Value",
"Text"
)
)
where Foo will be the name of the ddl and used by the default model binder. So the generated markup might look something like this:
<select name="Foo" id="Foo">
<option value="item 1">item 1</option>
<option value="item 2">item 2</option>
<option value="item 3">item 3</option>
...
</select>
This being said a far better view model for a drop down list is the following:
public class MyListModel
{
public string SelectedItemId { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
and then:
#model MyListModel
#Html.DropDownListFor(
x => x.SelectedItemId,
new SelectList(Model.Items, "Value", "Text")
)
and if you wanted to preselect some option in this list all you need to do is to set the SelectedItemId property of this view model to the corresponding Value of some element in the Items collection.
If you have a List of type string that you want in a drop down list I do the following:
EDIT: Clarified, making it a fuller example.
public class ShipDirectory
{
public string ShipDirectoryName { get; set; }
public List<string> ShipNames { get; set; }
}
ShipDirectory myShipDirectory = new ShipDirectory()
{
ShipDirectoryName = "Incomming Vessels",
ShipNames = new List<string>(){"A", "A B"},
}
myShipDirectory.ShipNames.Add("Aunt Bessy");
#Html.DropDownListFor(x => x.ShipNames, new SelectList(Model.ShipNames), "Select a Ship...", new { #style = "width:500px" })
Which gives a drop down list like so:
<select id="ShipNames" name="ShipNames" style="width:500px">
<option value="">Select a Ship...</option>
<option>A</option>
<option>A B</option>
<option>Aunt Bessy</option>
</select>
To get the value on a controllers post; if you are using a model (e.g. MyViewModel) that has the List of strings as a property, because you have specified x => x.ShipNames you simply have the method signature as (because it will be serialised/deserialsed within the model):
public ActionResult MyActionName(MyViewModel model)
Access the ShipNames value like so: model.ShipNames
If you just want to access the drop down list on post then the signature becomes:
public ActionResult MyActionName(string ShipNames)
EDIT: In accordance with comments have clarified how to access the ShipNames property in the model collection parameter.
I realize this question was asked a long time ago, but I came here looking for answers and wasn't satisfied with anything I could find. I finally found the answer here:
https://www.tutorialsteacher.com/mvc/htmlhelper-dropdownlist-dropdownlistfor
To get the results from the form, use the FormCollection and then pull each individual value out by it's model name thus:
yourRecord.FieldName = Request.Form["FieldNameInModel"];
As far as I could tell it makes absolutely no difference what argument name you give to the FormCollection - use Request.Form["NameFromModel"] to retrieve it.
No, I did not dig down to see how th4e magic works under the covers. I just know it works...
I hope this helps somebody avoid the hours I spent trying different approaches before I got it working.

Categories