MVC dropdown menu of variables - c#

I am working on an MVC4 Project and I'm looking to add a search by dropdown menu so that the user can select different variables to search through.
My Model
public class BloodStoredModel
{
[Required]
public int ID { get; set; }
[Required]
[DisplayName("Blood Type")]
public string bloodType { get; set; }
[Required]
[DisplayName("RH Factor")]
public string rhFactor { get; set; }
[Required]
[DisplayName("Last Name")]
public string donorLastName { get; set; }
[Required]
[DisplayName("First Name")]
public string donorFirstName { get; set; }
[Required]
[DisplayName("Address")]
public string address { get; set; }
[Required]
[DisplayName("Phone #")]
public string telephoneNumber { get; set; }
public class BloodDBContext : DbContext
{
public DbSet<BloodStoredModel> BloodStored { get; set; }
}
}
Here is my Controller method
public ActionResult SearchIndex(string searchString)
{
//string searchString = id;
var list = new SelectList(new[]
{
new{ID="1",Name="bloodType"},
new{ID="2",Name="rhFactor"},
new{ID="3",Name="donorLastName"},
new{ID="4",Name="donorFirstName"},
new{ID="5",Name="address"},
new{ID="6",Name="telephoneNumber"}
},
"ID", "Name", 1);
ViewData["list"] = list;
var bloodSearch = from m in db.BloodStored
select m;
if (!String.IsNullOrEmpty(searchString))
{
//bloodSearch = bloodSearch.Where(s => s.donorLastName.Contains(searchString));
bloodSearch = list.Select((value, index) => new { value, index })
.Where(s => s.value.Contains(searchString))
.Select(s => s.index);
}
return View(bloodSearch);
}
The commented lambda expression works but only for that certain variable. What I would like to do is have that be selectable dynamically through a dropdown list.
Here is my relevant view
#using (Html.BeginForm()){
<p> #Html.DropDownList("list", ViewData["list"] as SelectList)
#Html.TextBox("SearchString")<br />
<input type="submit" value="Filter" /></p>
}

The reason the value is not changing in the backend is because you are using DropDownList instead of DropDownListFor. DropDownListFor will automatically bind the selection to your model once the submit button is pressed (POST is executed). You are going to have to include the drop down list in a ViewModel or tweak your front end using JavaScript/Jquery.
EDIT
You would have to create a new class:
public DropDownOption
{
public int Id {get; set;}
public string Description {get; set;}
}
create a ViewModel:
public myViewModel
{
public List<DropDownOption> DropDownOptions {get; set;}
public int OptionSelected {get; set;}
}
Controller:
{
//other stuff
var myVM = new myViewModel();
myVM.DropDownOptions = new List<DropDownOption>(){
new DropDownOption{Id = 1, Name = "bloodType"},
new DropDownOption{Id = 2, Name = "rhFactor"},
//etc.
}
View:
#model .myViewModel
//other stuff
#Html.DropDownListFor(m => m.OptionSelected,
Model.DropDownOptions.Select(option => new SelectListItem
{
Text = option.Description,
Value = option.Id
})

To search the array of BlookSearchModel using a property selected by the user you would need to use reflection. Add the following function.
private string GetValue(BloodStoredModel obj, string propertyName)
{
Type type = typeof(BloodStoredModel);
if (type != null)
{
PropertyInfo property = type.GetProperty(propertyName);
if (property != null)
{
return (string)property.GetValue(obj);
}
}
return null;
}
You can then you it like this
bloodSearch = models.Where(s => string.Compare(GetValue(s, propertyName), searchString) == 0);
Of course there is a potential for errors by hard coding the property names. You could use reflection to enumerate the property names.
ViewBag.SearchFields = from prop in properties
select new SelectListItem() { Text = prop.Name };
This would also select the Id field from your model. However, you can modify the linq statement to exclude it.
EDIT I added the following. Plus I changed the above code to use ViewBag instead of ViewData.
To have your view use this you can do this.
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form1" }))
{
#Html.DropDownList("SearchFields")
<input type="submit" value="submit" onclick="return SetAction();" />
}
<script>
function SetAction() {
form = document.getElementById("form1");
dropdown = document.getElementById("SearchFields");
form.action = "/" + "?searchString=" + dropdown.value;
return true;
}
</script>

Related

Object reference not set to an instance of an object., model is null

I am trying to display a checklist that gets data from MySQL Database and displays it in a view and updates the value of the variable (IsChecked) of each element in the table by whether we have checked the amenity or not (i am displaying some amenities). The model of the view is Hotel_5.ViewModel.BookingRoom, where BookingRoom is a custom model i created where i use multiple models. I get the exception at Model.AmenitiesList.Count(). The model is null.
This is my view
<div class="form-group">
#for (var i = 0; i < Model.AmenitiesList.Count(); i++)
{
#Html.CheckBoxFor(m => m.AmenitiesList[i].IsChecked, new { #class = "form-control" });
<label>#Model.AmenitiesList[i].amenityType</label>
//If you need to hide any values and get them in your post
#Html.HiddenFor(m => m.AmenitiesList[i].AmenityId)
#Html.HiddenFor(m => m.AmenitiesList[i].AmenityPrice)
}
</div>
This is my ViewModel
public class BookingRoom
{
public Bookings bookings { get; set; }
public Rooms rooms { get; set; }
public List<Amenities> AmenitiesList { get; set; } = new List<Amenities>();
}
This is my Amenities Model
public class Amenities
{
[Key]
public int AmenityId { get; set; }
public double AmenityPrice { get; set; }
public AmenityType amenityType { get; set; }
public bool IsChecked { get; set; }
}
public enum AmenityType
{
tv,
wi_fi,
hair_dryer,
help
}
When Querying you should Include its AmenitiesList too, otherwise it will be null:
In Controller:
var bookingRoom = context.BookingRooms.Include(b => b.AmenitiesList).FirstOrDefault(b => b.Id == someId);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
please note that what I queried might not be what you want, it is just to demonstrate how to use Include() and also you should add using Microsoft.EntityFrameworkCore.

How to populate multiple tags into input form in ASP.NET

I have a form which has a place where a user can insert multiple tags separated by a comma into the database. I got it to insert, but I'm having trouble retrieving it to show on my edit form.
This is my Edit Action:
public IActionResult Edit(int id)
{
var gallery = _ctx.GalleryImages.SingleOrDefault(m => m.Id == id);
if (gallery == null)
return NotFound();
var categories = _ctx.Categories.ToList();
var model = new GalleryFormViewModel(gallery)
{
Tags = gallery.Tags,
Category = categories,
};
return View("Views/Image/UploadForm.cshtml", model);
}
Here is my ViewModel:
public class GalleryFormViewModel
{
public int? Id { get; set; }
public string Title { get; set; }
public IEnumerable<ImageTag> Tags { get; set; }
public IEnumerable<Category> Category { get; set; }
[Required]
public int CategoryId { get; set; }
public IFormFile ImageUplaod { get; set; }
public GalleryFormViewModel()
{
Id = 0;
}
public GalleryFormViewModel(GalleryImage galleryImage)
{
Id = galleryImage.Id;
Title = galleryImage.Title;
Tags = galleryImage.Tags;
CategoryId = galleryImage.CategoryId;
}
}
And here is the Form input: (I'm using this form for creating and editing the gallery)
<div class="form-group">
#Html.LabelFor(m => m.Tags)
#Html.TextBoxFor(m => m.Tags, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Tags)
</div>
Here is the Tag Model:
namespace SimpleImageGallery.Data.Models
{
public class ImageTag
{
public int Id { get; set; }
public string Description { get; set; }
}
}
Here is the Gallery Model:
public class GalleryImage
{
public virtual IEnumerable<ImageTag> Tags { get; set; }
// ....
}
This is how the tags table looks in the database:
It seems like I'm not getting any errors, maybe something is wrong in the actual input field?
There are some mistakes :
First, you have to Include the Tags to retrieve them from DB (if using Entity Framework):
var gallery = _ctx.GalleryImages.Include(m=>m.Tags).SingleOrDefault(m => m.Id == id);
Secondly, you are doing the same this twice :
var model = new GalleryFormViewModel(gallery)
{
Tags = gallery.Tags,
Category = categories,
};
and
public GalleryFormViewModel(GalleryImage galleryImage)
{
Id = galleryImage.Id;
Title = galleryImage.Title;
Tags = galleryImage.Tags;
CategoryId = galleryImage.CategoryId;
}
Thirdly, you cannot do this : #Html.TextBoxFor(m => m.Tags, new { #class = "form-control" }) for a enumerable, you have to reconstruct the string.

Setting selected values in a Listbox from the model in .net mvc

I am trying to bind my model to Multiple Select in .net MVC. This is my model
public class RuoloProgetto
{
[Key]
public int id_ruolo_prog { get; set; }
[Display(Name = "Ruolo")]
public int id_ruolo { get; set; }
[ForeignKey("id_ruolo")]
public virtual Ruolo ruolo { get; set; }
public int id_progetto { get; set; }
//[ForeignKey("id_progetto")]
//public virtual Progetto progetto { get; set; }
[Display(Name = "Utente")]
public string id_utente { get; set; }
[ForeignKey("id_utente")]
public virtual IdentityUser utente { get; set; }
[DisplayName("Carico di lavoro in %")]
[Required]
public int percentuale { get; set; }
public int versione { get; set; }
[DisplayName("Moduli Responsabile")]
public int[] Choices { get; set; }
public virtual List<ModelRP> moduli { get; set; }
}
This is in my controller function that sets the values for the selectlist:
List<SelectListItem> specifiche = new List<SelectListItem>();
var specifiche2 = db.Specificha.Where(p => p.id_progetto == Progetti.id_progetto).Select(x => new { x.id_specifiche, x.desc_specifiche }).ToList();
foreach (var item in specifiche2)
{
specifiche.Add(new SelectListItem { Value = item.id_specifiche.ToString(), Text = item.desc_specifiche });
}
ViewData["Specs"] = specifiche;
and this is in my view:
#Html.ListBoxFor(m => item.Choices,
new MultiSelectList((IEnumerable<SelectListItem>)ViewData["Specs"], "Value", "Text",
item.moduli.Select(fl => new SelectListItem
{
Text = fl.moduloutente.desc_specifiche.ToString(),
Value = fl.moduloutente.id_specifiche.ToString(),
Selected = item.moduli.Any(y => y.id_specifiche == fl.id_specifiche)
})),
new
{
Selected = true,
#Class = "js-example-basic-multiple form-control",
Multiple = "multiple",
#Name = "progetto.ruoloprogetto[" + index + "].Choices",
#Id = "progetto.ruoloprogetto[" + index + "]_Choices",
#Placeholder = "Moduli",
})
The ViewData comes ok! The problem is with the selected values! When I check in immediate window item.moduli is correctly filled with the data, but nothing appears as selected in the interface!
Can someone see what I'm doing wrong?
Your binding the list box to property Choices so you need to set the value of Choices in the controller before you pass the view and then just
#Html.ListBoxFor(m => item.Choices, (IEnumerable<SelectListItem>)ViewData["Specs"], new { #class = "js-example-basic-multiple form-control" })
If the values of the option values are (say) 1 to 10, and Choices is [2, 4] then the second and forth options will be selected.
Note also do not need to set Multiple = "multiple" (thats already done by the helper), and you should not be trying to override the name attribute (other wise binding will fail on post back). In addition Selected and Placeholder are not valid attributes for <select>

how to use ICollection for SelectList in Contoller of MVC?

I am developing .NET MVC application.
I want to send the collection of the objects from controller to View using select list.
without using view bag.
ViewModel :
public class AdviceCreateVM
{
public int Id { get; set; }
public string AdviceNo { get; set; }
public ICollection<CompanyVM> Companies { get; set; }
}
public class CompanyVM
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller Code :
public class AdviceCreateController : Controller
{
public ActionResult Create()
{
adviceVM.Companies = new SelectList(ledgerService.GetAll().OrderBy(t => t.Name), "Id", "Name");
}
}
It gives an error -
Cannot implicitly convert type 'System.Web.Mvc.SelectList' to
'System.Collections.Generic.ICollection'. An
explicit conversion exists (are you missing a cast?)
You're trying to assign a SelectList to property of type ICollection<CompanyVM> -- which won't work. You need some like:
var viewModel = new AdviceCreateVM
{
adviceVM.Companies =
ledgerService.GetAll().OrderBy(t => t.Name)
.Select(t=>
new CompanyVM
{
Id = t.Id, // "Id"
Name = t.Name // "Name"
})
.ToList()
};
I'm just guessing on the assignments here, since you didn't specify them.
In the view, you will have to make the select list from Companies property.
#Html.DropDownListFor(model => model.CompanyId,
model.Companies.Select(company =>
new SelectListItem
{
Value = company.Id,
Text = company.Name
}), "--Select Company--")
As indicated in the comments, SelectList does not implement ICollection. Change you view model collection to SelectList
public class AdviceCreateVM
{
public int Id { get; set; }
public string AdviceNo { get; set; }
public SelectList Companies { get; set; } // change to select list
public int CompanyID { get; set; } // for binding the the drop down list
}
Controller
public ActionResult Create()
{
AdviceCreateVM model = new AdviceCreateVM(); // initialise model
model.Companies = new SelectList(ledgerService.GetAll().OrderBy(t => t.Name), "Id", "Name");
}
View
#model YourAssembly.AdviceCreateVM
#using (Html.BeginForm()) {
....
#Html.DropDownFor(m => m.CompanyID, Model.Companies)
...

Want to demonstrate my object property instead of my object

I have DropDownList that read fils from my database and show this files in my DropDownList.
The current solution is show on my DropDownListItem System.Web.Mvc.SelectList instead of my Object property. I want to include a drop down list of my object (read from database) across my webpage.
This is my object:
public class MyObject
{
public int id { get; set; }
public string fileName { get; set; }
public string browser { get; set; }
public string protocol { get; set; }
public string family { get; set; }
}
My controller:
public ActionResult Index()
{
List<MyObject> list = db.MyObjects.Where(x => x.family == "Web").ToList();
ViewBag.Files = new SelectList(list, "Id", "protocol");
return View();
}
I also try:
List<MyObject> list = db.Captures.Where(x => x.family == "Web")
.DistinctBy(y => y.protocol)
.ToList();
Index.cshtml
#Html.DropDownList("File", new SelectList(ViewBag.Files), "Select webmail site", new { style = "vertical-align:middle;" })
What i want to see in my DropDownList is my protocol property.
All the above not help and all i can see all the time is System.Web.Mvc.SelectList
Change your controller to:
public ActionResult Index()
{
ViewBag.Files = db.MyObjects.Where(x => x.family == "Web").ToList();
return View();
}
and your Index.cshtml
#Html.DropDownList("File", new SelectList(list, "Id", "protocol"), "Select webmail site", new { style = "vertical-align:middle;" })

Categories