Pass a list from a view to a controller - entity-framework

I have this controller which creates a List where T is a class model called GamingEvents.
public async Task<IActionResult> Index(DateTime start, DateTime end)
{
List<GamingEvents> gamingEventsListings = await sg.GenerateGameEventsSchedule();
ViewData["RangeStart"] = start;
ViewData["RangeEnd"] = end;
return View(gamingEventsListings);
}
In my view I generate this table to display the data:
#model List<GameManager.Models.GamingEvents>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.GameId)
</td>
<td>
#Html.DisplayFor(modelItem => item.GameName)
</td>
<td>
#Html.DisplayFor(modelItem => item.DayNames)
</td>
</tr>
}
Now, I want to send all this data to another controller. So I made this form:
<form asp-controller="Scheduling" asp-action="ScheduleBlock" method="post">
<fieldset>
<button formaction="/Scheduling/ScheduleBlock/">Schedule Games</button>
</fieldset>
</form>
So I need the method, GenerateGameEventsFromSchedule(), to accept the two data properties I pass to the view, ViewData["RangeStart"] and ViewData["RangeEnd"].
So I started to write the controller:
[HttpPost]
public async Task<IActionResult> GenerateGameEventsFromSchedule(DateTime start, DateTime end)
{
foreach (event in GamingEvents)
{
//...do this
}
return View();
}
Obviously it's not finished.
My problem is, how would I pass the list of GamingEvents from my view above, to this new controller so that I can do additional processing on each item in the list?
Thanks!

Related

Asp.net core posting checkbox data from View to Controller

I'm new to Asp.net core and was wondering what I am doing wrong.
I have models like this that are populating my View:
Public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
Public class Collection
{
public List<Person> People { get; set; }
}
A View that takes a form of checkbox items and is meant to set 'isSelected' to true.
#model Collection
#using (Html.BeginForm("PostSelectedPerson", "Person", FormMethod.Post))
{
<tbody>
#for (int i = 0; i < Model.People.Count; i++)
{
<tr>
<td><input type="checkbox" name="#Model.People[i].IsSelected" value="true" checked /></td>
#Html.HiddenFor(model => model.People[i].IsSelected)
<td>
#Model.People[i].Id
</td>
</tr>
<input type="submit" value="Submit" name="Submit" />
}
</tbody>
}
And an Action that is meant to be passed the updated Collection model.
[HttpPost]
public IActionResult PostSelectedPerson(Collection c)
{
//return something.
}
The View is populated, but when the form is submitted, the action gets an empty Collection.
I expect a Collection with a list of Person with isSelected set to true for those with checkboxes marked.
The View is populated, but when the form is submitted, the action gets an empty Collection.
If you'd like to include both Id and IsSelected info in formdata and post them to action, please use additional hidden form field for Id property and specify name attribute for hidden field to match property of custom model class, which would help bind value to properties of the model automatically, like below.
#using (Html.BeginForm("PostSelectedPerson", "Person", FormMethod.Post))
{
<table>
<tbody>
#for (int i = 0; i < Model.People.Count; i++)
{
<tr>
<td>
<input asp-for="#Model.People[i].IsSelected">
</td>
<td>
#Model.People[i].Id
<input type="hidden" name="People[#i].Id" value="#Model.People[i].Id" />
</td>
<td>
#Model.People[i].Name
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Submit" />
}
Test Result
I expect a Collection with a list of Person with isSelected set to true for those with checkboxes marked.
If you want only selected person data are post to action, you can dynamically generate/populate formdata based on selected rows, then make ajax request to post it to your action on JavaScript client.

Is there any way to have Controller, ViewModel and View without Model? It's for an Index only view

What I want to do is a parametrized report, i would love to use SSRS or other fancy tools for this but it's sort of dangerous at this point because i don't really want to mess around with the company server and I dont have much time; Also If it's a tool it should be a free and light tool and i didn't find one by now.
So, my idea is making a simple controller with Index that will return a List to View according to parameters and the View will use that ViewModel as Model then the users can export that list to CSV or PDF, the problem is: MVC is asking for a real db model to complete the scaffolding, how can this be done then?
Controller (I call an stored proc here)
public class ReporteEntregasPresentacionController : Controller
{
private EntregaMedicamentosEntities db = new EntregaMedicamentosEntities();
public ActionResult Index(DateTime DateFrom, DateTime DateTo)
{
ReporteEntregasPresentacionViewModel rep = new ReporteEntregasPresentacionViewModel();
string sqlQuery = "[dbo].[spEntregasPorPresentacion] ({0},{1})";
Object[] parameters = { DateFrom, DateTo };
rep.LstEntregasPresentacionViewModel = db.Database.SqlQuery<ItemEntregasPresentacionViewModel>(sqlQuery, parameters).ToList();
return View(rep);
}
}
ViewModel:
public class ReporteEntregasPresentacionViewModel
{
public int index;
public List<ItemEntregasPresentacionViewModel> LstEntregasPresentacionViewModel;
}
public class ItemEntregasPresentacionViewModel {
public string idProducto { get; set; }
public string Descripcion { get; set; }
public string EntregasTotales { get; set; }
}
I don't have a View now but i should be something like this:
#model EntregaMedicamentos.Models.ReporteEntregasPresentacionViewModel
<link href="~/Content/css/styles.css" rel="stylesheet" />
#{
ViewBag.Title = "ReporteEntregasPresentacion";
}
<h2>ReporteEntregasPresentacion</h2>
#using (Html.BeginForm("Index", "Entrega", FormMethod.Post))
{
<div class="card text-white bg-secondary">
<h5 class="card-header">Search</h5>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="input-group">
#Html.TextBox("DateFrom", ViewBag.currentFilter1 as DateTime?, new { #class = "form-control", placeholder = "Desde fecha", #readonly = "true", type = "datetime" })
#Html.TextBox("DateTo", ViewBag.currentFilter2 as DateTime?, new { #class = "form-control", placeholder = "Hasta fecha", #readonly = "true", type = "datetime" })
<button id="Submit4" type="submit" style='font-size:22px ;color:blue'><i class='fas fa-search'></i></button>
</div>
</div>
</div>
</div>
</div>
}
<br>
<table class="table table-striped ">
<tr class="table-primary">
<th>
Código
</th>
<th>
Producto
</th>
<th>
Entregas Totales
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.idProducto)
</td>
<td>
#Html.DisplayFor(modelItem => item.Descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Valor)
</td>
</tr>
}
</table>
I ended up creating a real table/model and then it worked fine with the viewmodel. Thanks.

Need help creating Creating Controller to Delete item from database

Good evening everyone! I have been following along with a tutorial to learn how to program in .NET. The tutorial goes over how to add an item but it doesn't cover deletion. Here is my code:
Service Layer
public async Task Delete(int locationId)
{
var location = _context.Locations.Where(l => l.Id == locationId);
_context.Remove(location);
await _context.SaveChangesAsync();
}
Controller
public IActionResult Delete(int id)
{
_locationService.Delete(id);
return RedirectToAction("Index", "Location");
}
View
<table class="table table-hover" id="locationIndexTable">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone Number</th>
<th>Delete Location</th>
</tr>
</thead>
<tbody>
#foreach (var location in Model.LocationList)
{
<tr>
<td>
<a asp-controller="Location" asp-action="Detail" asp-route-id="#location.Id">
#location.Name
</a>
</td>
<td>
#location.Address
</td>
<td>
#location.PhoneNumber
</td>
<td>
<a asp-controller="Location" asp-action="Delete" asp-route-id="#location.Id" class="btn btn-sm btn-primary">TODO Delete</a>
</td>
</tr>
}
</tbody>
My button clicks through and redirects back to my location index view. However it does not delete the location from the database as intended. I know the issue must lie with the controller.
In the off chance that this will help someone in the future here is what I changed my code to to get it to work:
Service Layer
public async Task Delete(int locationId)
{
var location = _context.Locations.SingleOrDefault(l => l.Id == locationId);
_context.Remove(location);
await _context.SaveChangesAsync();
}
Controller
public async Task <IActionResult> Delete(int id)
{
await _locationService.Delete(id);
return RedirectToAction("Index", "Location");
}
The problem is because of the where method! It returns a collection and EF's Remove method does not complain about it as it takes an object. Try changing that with FirstOrDefault or SingleOrDefault or the Find method and you will be good to go.
public async Task Delete(int locationId)
{
var location = _context.Locations.FirstOrDefault(l => l.Id == locationId);
_context.Remove(location);
await _context.SaveChangesAsync();
}
However if you tried using the Generic version, you would surely notice the problem immediately. A better way would be to to:
//EF Core
var item = await dbContext.FindAsync<Location>(locationId);
dbContext.Remove<Location>(item);
await dbContext.SaveChangesAsync();

How to handle one to many relation ship Knockout-Entity Framework

So I have I have a simple structure where one purchase have a collection of expenses, and each expense have an account(plastic, cash, plastic#2...).
So the json my api gets is similar to this:
[
{"$id":"1","Id":1,"Name":"apple","Value":100.0,"AccountId":1,"Account":
{"$id":"2","Id":1,"Name":"Cash"}},
{"$id":"3","Id":2,"Name":"pear","Value":50.0,"AccountId":1,"Account":
{"$ref":"2"}},
{"$id":"4","Id":3,"Name":"raspberry","Value":10.0,"AccountId":1,"Account":
{"$ref":"2"}}
]
I see my json is not writing my cash account each time it needs it, it is refering it with
{"$ref":"2"}
where
{"$id":"2","Id":1,"Name":"Cash"}
so when I render my table with this html:
<table>
<tbody data-bind="foreach: gastos">
<tr>
<td data-bind="text: $data.id"></td>
<td data-bind="text: $data.name"></td>
<td data-bind="text: $data.value"></td>
<td data-bind="text: $data.account.Name"></td>
<td>
<button type="button" class="btn btn-xs">
<i class="glyphicon glyphicon-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
I get this, because the account for pear, and raspberry are nulls:
So how do you handle $ref in knockout?
I am mapping to 'gastos' this way:
$.getJSON('#ViewBag.GastosUrl', function (data) {
data.forEach(function(o) {
gastos.push(new gastoVM(o.Id, o.Name, o.Value, o.Account));
});
});
var gastoVM = function(Id, Name, Value, Account) {
var self = this;
self.id = Id;
self.name = Name;
self.value = Value;
self.account = Account;
};
thanks.
I'm not familiar with entity-framework but with the data as provided, a couple options available (JSFiddle):
Build up the account information alongside the gastos. And only provide the $id or $ref for later referencing.
var vm = {
gastos: [],
accounts: {},
accountLookup: function(accountId){
return this.accounts[accountId];
}
}
//... inside AJAX call
var accountId = o.Account["$id"]
if(accountId)
{
vm.accounts[accountId] = o.Account;
}
Use a ko utility method to lookup the account from within your array.
accountLookupByUtil: function(accountId) {
var gasto = ko.utils.arrayFirst(this.gastos, function(item) {
if(item.account['$id'] == accountId)
{
return item
}
});
return gasto.account;
}
From the html:
<td data-bind="text: $root.accountLookup($data.accountId).Name"></td>
<td data-bind="text: $root.accountLookupByUtil($data.accountId).Name"></td>
Note: Both methods are available in the fiddle, thus some properties are provided that would not be necessary depending upon the method used.

mvc ajax begin form and renderpartial validation open

ı am using a view in ajax begin form. ı search one thing and result is correct then alert not render the partial view. but it isnt render correct view a blank page and a see my partial view. thanks
my view
#using (Ajax.BeginForm("AjazKullanici", new AjaxOptions { UpdateTargetId = "trBilgiler", HttpMethod = "Post" }))
{
<tr>
<td style="width: 20%">
T.C. Kimlik No :
</td>
<th align="left">
#Html.TextBoxFor(model => model.TcNo)
#Html.ValidationMessageFor(model => model.TcNo)
<input type="submit" id="btnBilgiGetir" value="Bilgi Getir" class="Button" width="75px" />
</th>
</tr>
}
<tr id="trBilgiler">
#{Html.RenderPartial("BilgilerKullanici");}
</tr>
my controller
public ActionResult AjazKullanici()
{
ViewData["dropGizliSoru"] = _db.EHASTANEGIZLISORUs;
return View();
}
[HttpPost]
public PartialViewResult AjazKullanici(YeniKullaniciModel model)
{
if (model.TcNo != null)
{
var userKontrol = _db.KULLANICIBILGILERIs.Where(x => x.KULLANICIKOD == model.TcNo);
if (userKontrol.Any())
{
Response.Write("<script langauge='javascript'>alert('Girmiş Olduğunuz T.C. Kimlik Numarasına Ait Kullanıcı Kaydı Vardır.')</script>");
return PartialView();
}
else
{
return PartialView("BilgilerKullanici",model);
}
}
return PartialView();
}