Pass select/drop-down item's value to controller only receives 0 - c#

I've successfully created a view to show some records from votings. But on that same view i try to call another method on my controller to export those records and it only receives 0 as a parameter.
This is my model.
public class Vote
{
public int Id { get; set; }
public int CPF { get; set; }
public virtual Candidate Candidate { get; set; }
public int CandidateID { get; set; }
public DateTime Moment { get; set; }
}
This is my Index.
public async Task<IActionResult> Index()
{
var context = _context.Vote.Include(v => v.Candidate).Include(v => v.Candidate.Election);
//This is going to be on the view for the user to select the year to export data
ViewData["Election"] = new SelectList(_context.Election, "Id", "Year");
return View(await context.ToListAsync());
}
That's the action I'm tryig to call.
[HttpPost]
public IActionResult Export(int electionYear)
This is the form I'm using to POST to the controller.
#model IEnumerable<Models.Vote>
...
//Here i show the votes and then below i show this form with the Elections
<form asp-action="Export">
<div class="form-group">
<select class="form-control" asp-items="ViewBag.Election"></select>
</div>
<div class="form-group">
<input type="submit" value="Exportar" class="btn btn-default" />
</div>
</form>
I tried it with the [FormBody] and it gives me 415 ERROR

The Export endpoint is expecting a form value called electionYear. But your <select> doesn't have that name (or any name). Try:
<select name="electionYear" class="form-control" asp-items="ViewBag.Election"></select>

Related

How to send data from view to controller with drop down list asp.net core 5 MVC

So I'm doing a project in asp.net core and I've got multiple drop down lists which should send data to the controller once I click the submit button. The problem is that i have never been able to send any data to the controller.
Here's the concerned part of the view (there's only one drop down list now but I'll add more):
#using DemoProjectCar.Models
#model JoinModels
<form asp-action="searchCar">
<label for="carType">car Type:</label>
<select name="carType" id="carType">
<option value="Aucun" name="data">Aucun</option>
#foreach (var car in Model.cars)
{
<option name="data">#Html.DisplayFor(modelItem => car.carType)</option>
}
</select>
<div class="form-group">
<input id="SearchButton" type="submit" value="search" class="btn btn-dark" />
</div>
</form>
Here's the controller:
public IActionResult searchCar(String data)
{
//Gets a list of both models in the view
JoinModels join = getJoinModel();
//Whatever i wanna do with the data
return View("Index", join);
}
Here's both the Join Model and the carModel
namespace DemoProjectCar.Models
{
public class JoinModels
{
public List<_user> user { get; set; }
public List<_cars> cars { get; set; }
}
}
namespace DemoProjectCar.Models
{
public class _cars
{
public int id { get; set; }
public String carType{ get; set; }
public cars()
{
}
}
}
I know something like that would usually work (i think):
<select asp-for="id" asp-items="#(new SelectList(ViewBag.message,"id","carType"))">
but because I've got a join model it doesn't work
Try this in your HTML:
<select asp-for="data" asp-items="#(new SelectList(Model.cars, "id", "carType"))"></select>
And in your ViewModel(JoinModels), you need to create an attribute to send to your Post method:
public class JoinModels
{
// New attribute to receive in your post data
public string data { get; set; }
public List<_user> user { get; set; }
public List<_cars> cars { get; set; }
}
Then in your post method searchCar(String data), you will receive the selected Id.
Here's a link to help you more: Examples about how to create an dropdopwn

ASP.NET Core MVC model validation in viewmodel with base model

I am developing a web app with ASP.NET Core MVC, and I have a problem with model validation.
When I set validation in class and then use it in view model, validation does not work. How can I struggle with it?
This is my code:
public class Il : IEntity
{
[Required(ErrorMessage = "Kodu boş geçilemez")]
public int IlKodu { get; set; }
public int UlkeId { get; set; }
[Required(ErrorMessage = "Ad boş geçilemez")]
public string Ad { get; set; }
public int Id { get; set; }
public DateTime? KayitTarihi { get; set; }
public DateTime? GuncellemeTarihi { get; set; }
}
ViewModel class;
public class IlAddViewModel
{
public Il Il { get; set; }
public List<Ulke> Ulkeler{ get; set; }
}
Then the view:
<div class="container pt-4 eklemeDiv col-4">
<form asp-controller="Il" asp-action="Add" asp-area="Admin" method="post">
<div class="form-group">
<label asp-for="Il.IlKodu">Il Kodu</label>
<input asp-for="Il.IlKodu" class="form-control" placeholder="İl Kodu Giriniz">
<span asp-validation-for="Il.IlKodu" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Il.Ad">Il Kodu</label>
<input asp-for="Il.Ad" class="form-control" placeholder="İl Kodu Giriniz">
<span asp-validation-for="Il.Ad" class="text-danger"></span>
</div>
<div class="form-group">
<label >Ülke</label>
<select style="width: 100%;height:30px" id="selectIl" asp-for="Il.UlkeId"
asp-items="#(new SelectList(Model.Ulkeler,"Id","Ad"))">
<option>Lütfen Seçim Yapınız</option>
</select>
</div>
<input id="btnIlEkle" type="submit" value="Ekle" class="btn btn-xs btn-success" />
<a class="btn btn-xs btn-primary" asp-action="Anasayfa" asp-area="Admin" asp-controller="Admin"><i class="fas fa-chevron-left"></i>Anasayfaya Dön</a>
</form>
</div>
The view model does not show validation messages in view. And also how can I show validation messages for list elements?
My friends, all parts of my code are correct for structure, just one error is missing and finally i found it today. I am sharing this solution to help others;
Also controller code;
[HttpPost]
public async Task<ActionResult> Add(IlAddViewModel ilAddViewModel)
{
var kayitVarmi = _ilService.BenzerKayitVarMi(ilAddViewModel.Il.IlKodu, ilAddViewModel.Il.Ad);
if (kayitVarmi)
{
TempData.Add("Hata", "Böyle bir kayıt mevcut");
return RedirectToAction("Add");
}
else
{
if (ModelState.IsValid && !kayitVarmi)
{
ilAddViewModel.Il.KayitTarihi = DateTime.Now;
await _ilService.Add(ilAddViewModel.Il);
TempData.Add("Message", String.Format("{0} başarıyla eklendi", ilAddViewModel.Il.Ad));
return RedirectToAction("Anasayfa", "Admin", new { Area = "Admin" });
}
}
return RedirectToAction("Add");
}
To achieve this validation error, you must add necessary javascript packages as below;
<script src="~.../jquery-validation/dist/jquery.validate.js"></script>
<script src="~.../jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.js"></script>
These javascript packages help to show validation messages without making post to action method.
In the controller you will have access to check the model state to verify if it is valid or not. The controller code should like this
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Employee employee)
{
try
{
//Here ModelState.IsValid will be true in case all the required fields that are mentioned in employee class
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View();
}
catch (Exception)
{
return View();
}
}
}

ASP.NET MVC EF Core, Property Access in View while on selected ID for different Model

I´m having an issue where I have three models as show below: Person, Competence with PersonCompetence between them. My current controller method gets an Id from previous page and shows that person with a list of this person's Competence and Level. In this View however I want to have a POST for new Competence. So at the same time you are adding a new one and you can see which ones you already have.
With the controller method I have now I can access the PersonCompetence and Competence when showing the list.
I dont have access to the Competence properties for asp-for="Competence" marked ###### in the View for AddComp.
I need the ID of person for POST to right person
I need the CompetenceType for POST to that property
I need PersonCompetence to show the list of current PersonCompetence.
I get that with the current #model CompetenceRadar.Models.Person I only reach Person properties.
I have looked at having a ViewModel with access to all tables with an IEnumerable for each table, but this breaks my current Controller when I search for the Id of the person showing. I have switched the #model in the View, but then I can't access Person ID/name.
So how do I access the Competence properties , list one person and get a list of PersonCompetences for that Person.
Please tell me if you want me to clarify something.
I don't need working code, just something to point me in the right direction for a solution.
Is it a ViewModel?
Can I POST without the asp-forattribute?
Models
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public ICollection<PersonCompetences> PersonCompetences { get; set; }
}
public class PersonCompetence
{
public int ID { get; set; }
public int PersonID { get; set; } // FK
public int CompetenceID { get; set; } // FK
public int Level { get; set; }
public Competece Competence { get; set; }
public Person Person { get; set; }
}
public class Competence
{
public int ID { get; set; }
public string CompetenceType { get; set; }
public string CompetenceCategory { get; set; }
public ICollection<PersonCompetence> PersonCompetences { get; set; }
}
AddComp Kontroller function
public async Task<IActionResult> AddComp(int? id)
{
var person = await _context.Personer
.Include(pk => pk.PersonCompetences)
.ThenInclude(k => k.Competence)
.FirstOrDefaultAsync(m => m.ID == id);
return View(person);
}
View_AddComp View for AddComp
#model CompetenceRadar.Models.Person
<h1>AddComp</h1>
<div class="row">
<form asp-action="AddComp">
<input type="hidden" asp-for="ID" />
<div class="form-group col-sm-4">
<label asp-for="#############" class="control-label col-sm-4"></label>
<input asp-for="#############" class="form-control col-sm-4" />
<span class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-dark" />
</div>
</form>
</div>
#foreach (var item in Model.PersonCompetences)
{
<div class="row py-2 rounded" style="background-color:lightslategray">
<div class="col-sm-3 pt-2">#item.Competence.CompetenceType</div>
<div class="col-sm-1 pt-2">#item.Niva</div>
<div class="col-sm-3 pt-2">#item.Competence.CompetenceCategory</div>
<div class="col-sm-5 d-flex justify-content-end">
<a class="btn btn-dark mr-1" role="button" asp-area="" asp-controller="Competence" asp-action="UpdateLevel" asp-route-id="#item.ID">Update</a>
<a class="btn btn-dark mr-1" role="button" asp-area="" asp-controller="Competence" asp-action="DeleteComp" asp-route-id="#item.CompetenceID">Remove</a>
</div>
</div>
}
Simple anwser is that I needed a ViewModel with all three Models
public class ExampleViewModel {
public Person person { get; set; }
public PersonCompetence personCompetence { get; set; }
public Competence competence { get; set; }}
This alows me to access the different values for ID, CompetenceType and a List for of the current PersonCompetence.
What is ViewModel in MVC?

ASP.NET CORE MVC SelectList from a collection of Objects

So I have these 2 classes representing tables in a local db using ef core migration in an asp.net core app
public class Teacher
{
public int ID { get; set; }
public string FistName { get; set; }
public string LastName { get; set; }
public Class Class { get; set; }
public string FullName
{
get
{
return $"{LastName} {FistName}";
}
}
public override string ToString()
{
return FullName;
}
}
and
public class Class
{
public int ID { get; set; }
public int TeacherID { get; set; }
public string Name { get; set; }
public Teacher Teacher { get; set; }
public ICollection<Student> Students { get; set; }
}
I want to add in my classes controller the functionality to create a new instance of the "Class" class by typing out a name in a textbox and selecting a teacher from a dropdownlist.
Here are my create http get & post methods
public IActionResult Create()
{
var teachers = from s in _context.Teachers
where s.Class == null
select s;
ViewData["Teachers"] = new SelectList(teachers.ToList());
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Class #class)
{
if (ModelState.IsValid)
{
#class.TeacherID = #class.Teacher.ID;
_context.Add(#class);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View("Index");
}
and the form for submitting user-typed data
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Teacher" class="control-label"></label>
<select asp-for="Teacher" class ="form-control" asp-items="ViewBag.Teachers"></select>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
I can see the right data in the dropdown list but for some reason inside the POST method #class.Teacher is null. What am I doing wrong?
First update your Create GET method as follows:
public async Task<IActionResult> Create()
{
var teachers = await _context.Teachers.Where(t => t.Class == null).ToListAsync();
ViewData["Teachers"] = new SelectList(teachers,"ID","FullName");
return View();
}
Then write your FormGroup for select list as follows:
<div class="form-group">
<label asp-for="TeacherID" class="control-label">Teacher</label>
<select asp-for="TeacherID" class ="form-control" asp-items="ViewBag.Teachers">
</select>
<span asp-validation-for="TeacherID" class="text-danger"></span>
</div>
Now update your Create POST method as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Class #class)
{
if (ModelState.IsValid)
{
_context.Classes.Add(#class); // now your #class is containing the `TeacheID` value selected from drop-down.
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View("Index");
}
Now everything should work fine!
Make the following changes
Create http get method , view SelectList Class , set ID to the dataValueFieldof the selectList and set FullNameto the dataTextFieldof selectList
public IActionResult Create()
{
var teachers = from s in _context.Teacher
where s.Class == null
select s;
ViewData["Teachers"] = new SelectList(teachers.ToList(),"ID","FullName");
return View();
}
The select tag in the form
<select asp-for="TeacherID" class="form-control" asp-items="ViewBag.Teachers"></select>
A select list will only return a primitive type (string, int, etc.), not an entire class instance. As a result, you'll need to bind the value to a property that is also such a primitive type. Since you already have a TeacherID property, you can just use that. When you save, EF will fixup the Teacher reference with the corresponding id.
<select asp-for="TeacherID" class ="form-control" asp-items="ViewBag.Teachers"></select>
"Teacher" is a complex class, that will always be null, I think you're getting confused, replace "Teacher" by "teacherID". EF will do the job.

Correct way to do Create and Update actions for one to many objects in .Net Core Ef Core

I'm working on my first .Net Core application and I was able to put together the CRUD actions for my first table.
The second table has a foreign key to the first table and I think I've gone off on the wrong path in trying to put together the Create and Update actions. The Update action needs to pass in all items from the foreign key table for the user to select from. But as an update Action, the View needs to have the actual objects foreign key selected from the drop-down list.
What's the correct way to do this? I can't seem to find a consistent answer on Google.
Table 1 Model:
public class HTMLElement
{
public int Id { get; set; }
public string Element { get; set; }
public string ElementName { get; set; }
public virtual ICollection<CustomizedElement> CustomizeHTMLElements { get; set; }
}
Table 2 Model:
public class CustomizedElement
{
public int Id { get; set; }
public string Name { get; set; }
public int? HTMLElementId { get; set; }
public HTMLElement HTMLElement { get; set; }
}
ViewModel for Table Two:
public class CustomizedHTMLElementViewModel
{
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "HTML Element")]
public int HTMLElement { get; set; }
[Display(Name = "HTML Elements")]
public ICollection<HTMLElement> HTMLElements { get; set; }
}
Create Controller:
I want to pass in all of the items from Table 1 into the view for a drop-down list that the user can select from and this works but not sure if it's the correct way to do this.
[HttpGet]
public IActionResult AddCustomizedHTMLElement()
{
var elements = new CustomizedHTMLElementViewModel
{
HTMLElements = db.HTMLElements.ToList()
};
return View(elements);
}
The Post action is working but not sure if it's the most efficient.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddCustomizedHTMLElement(CustomizedHTMLElementViewModel CHTMLEV)
{
if (ModelState.IsValid)
{
var element = db.HTMLElements.Single(e => e.Id == CHTMLEV.HTMLElement);
CustomizedElement cElement = new CustomizedElement()
{
Name = CHTMLEV.Name,
HTMLElement = element,
};
db.CustomizedElements.Add(cElement);
db.SaveChanges();
return RedirectToAction("CustomizedHTMLElements");
}
return View(CHTMLEV);
}
I'm having a really hard time with the Update action. I want to pass in all foreign keys but also have the objects foreign key selected in the drop-down list in the View
[HttpGet]
public IActionResult UpdateCustomizedHTMLElement(int Id)
{
var mElement = db.CustomizedElements.Include(e => e.HTMLElement).FirstOrDefault(e => e.Id == Id);
ViewBag.ElementsList = db.HTMLElements.ToList();
return View(mElement);
}
I haven't worked on the Update actions [HttpPost] yet until I get the View right.
Update View:
<form method="post" asp-controller="Templates" asp-action="UpdateCustomizedHTMLElement">
<div class="form-group">
<label asp-for="Name"></label>:
<input class="form-control form-control-sm" type="text" asp-for="Name" />
<span class="text-danger" asp-validation-for="Name"></span>
</div>
<div class="form-group">
<label asp-for="HTMLElement"></label>:
#Html.DropDownListFor(m => m.HTMLElement, new SelectList(ViewBag.ElementsList, "Id", "Element"), new { #class = "form-control" })
<span class="text-danger" asp-validation-for="HTMLElement"></span>
</div>
<div>
<button class="btn btn-primary" type="submit" value="Submit">Save</button>
<button class="btn btn-secondary" type="button" value="Cancel" onclick="location.href='#Url.Action("CustomizedHTMLElements", "Templates")'">Cancel</button>
</div>
</form>
public class UpdateCustomizedHTMLViewModel
{
public int SelectedHtmlElementId { get; set;}
public CustomizedElement ElementToUpdate { get; set;}
public ICollection<HTMLElement> HTMLElements { get; set;}
}
Then fill ElementToUpdate and HTMLElements in your get and when you select the HTMLElement you want to update with in the dropdown you assign that Id to SelectedHtmlElementId

Categories

Resources