How can I solve the problem with Models in ASP.NET.MVC? - c#

I have a problem. I have posts on the wall. And if the user has entered the site, then he can send his response to the post. How do I make it so that when using my TakeAnswer method, I can create a new row in the database? Now I only save the user's response, but not the ID of the post to which he replied.
[HttpGet]
public IActionResult Index()
{
var posts = db.Posts.ToList();
if (posts == null)
return View();
var temp = new IndexModel();
temp.Posts = posts;
temp.PostID = 0;
temp.IndexAnswer = "";
return View(temp);
}
[HttpPost]
public async Task<IActionResult> TakeAnswer(IndexModel model, string PostID)
{
if (ModelState.IsValid)
{
db.Answers.Add(new Answer { UserId = GetUserId, UserAnswer = model.IndexAnswer, PostId = int.Parse(PostID) });
await db.SaveChangesAsync();
}
return View();
}
public class IndexModel
{
[BindProperty]
public string IndexAnswer { get; set; }
[BindProperty]
public int PostID { get; set; }
public IEnumerable<Post> Posts { get; set; }
}
#model CourseProject.ViewModels.IndexModel
<form asp-action="TakeAnswer" asp-controller="Home">
#if (Model != null)
{
#foreach (var post in Model.Posts)
{
<div class="card my-3">
<h5 class="card-header font-weight-bold">
#Html.DisplayFor(model => post.PostName)
</h5>
<div class="card-body">
<p class="card-text">#Html.DisplayFor(model => post.PostContent)</p>
#if (User.Identity.IsAuthenticated)
{
<div class="form-group">
<label asp-for="IndexAnswer">Your answer to this problem</label><br />
<input type="text" asp-for="IndexAnswer" />
</div>
<div>
<button type="submit" class="btn btn-primary" asp-route-PostID="#post.Id">Reply</button>
</div>
}
</div>
<div class="card-footer">
<p>Task created: #Html.DisplayFor(model => post.Date)</p>
</div>
</div>
}
}
</form>

Related

How to Get Selected List of DropDownList from Database or Model and Populate in Dropdown on View

I am performing a Bitwise-Create operation on my modal(view) and I am to select a dropdown list of users from another table/model and bind to the view so I can forward the request to them. I want to select users based on a certain role, if possible: but I just want to select the users from the database table.
If you need any other model or controller, kindly prompt me so i add it.
Please help..
Below is my Code:
Cshtml Code for the Modal View:(Removed Other TextFields):
So where I have the select tags, i want to get the select list of users and add it.
<div class="row">
<div class="col-md-12">
<form asp-action="AddOrEdit" asp-route-id="#Model.BitwiseId" autocomplete="false" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col-md-6">
<div class="form-group">
<label asp-for="AccountName" class="control-label"></label>
<input asp-for="AccountName" class="form-control" />
<span asp-validation-for="AccountName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="File" class="control-label"></label>
<input type="file" name="userfile" class="form-control" accept=".xlsx"/>
<span asp-validation-for="File" class="text-danger"></span>
</div>
<div class="form-group">
<label for="cars">Select 1st Approver </label>
<select name="group_heads" id="group_heads" class="form-control">
<option value="">Select</option>
<option value="2">Bobby</option>
</select>
</div>
<hr />
<div class="d-grid gap-2">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
Code: Controller for the Bitwise - Add Method:
namespace BOGBitwiseApp.Controllers
{
public class BitwiseController : Controller
{
private readonly ApplicationDbContext _context;
public BitwiseController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
return View(await _context.Bitwises.ToListAsync());
}
// GET: Transaction/AddOrEdit(Insert)
// GET: Transaction/AddOrEdit/5(Update)
[NoDirectAccess]
public async Task<IActionResult> AddOrEdit(int id = 0)
{
if (id == 0)
return View(new BitwiseModel());
else
{
var bitwiseModel = await _context.Bitwises.FindAsync(id);
if (bitwiseModel == null)
{
return NotFound();
}
return View(bitwiseModel);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrEdit(int id, [Bind("BitwiseId,..., Amount")] BitwiseModel bitwiseModel, ...)
{
if (ModelState.IsValid)
{
//New
if (id == 0)
{
string filename = userfile.FileName;
...
await userfile.CopyToAsync(stream);
var data = _context.Users.ToListAsync();
bitwiseModel.Date = DateTime.Now;
_context.Add(bitwiseModel);
await _context.SaveChangesAsync();
}
//Update
else
{
try
{
_context.Update(bitwiseModel);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BitwiseModelExists(bitwiseModel.BitwiseId))
{ return NotFound(); }
else
{ throw; }
}
}
return Json(new { isValid = true, html = Helper.RenderRazorViewToString(this, "_ViewAll", _context.Bitwises.ToList()) });
}
return Json(new { isValid = false, html = Helper.RenderRazorViewToString(this, "AddOrEdit", bitwiseModel) });
}
Model Code for Bitwise (Add):
public class BitwiseModel
{
[Key]
public int BitwiseId { get; set; }
[Required]
[Column(TypeName = "nvarchar(100)")]
[DisplayName("Customer Name")]
public string AccountName { get; set; }
[NotMapped]
[DisplayName("Invoice File")]
public IFormFile? File { get; set; }
}
**Model for Users Table:**
public class ApplicationUser : IdentityUser
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public int UsernameChangeLimit { get; set; } = 2;
public byte[]? ProfilePicture { get; set; }
}

How To Get TreeView Model from view to controller on .net core 3.1 MVC

I have a .net core 3.1 MVC project where i am displaying a custom made treeview along with 2 textbox.
Here is the Model i used:
public class DeviceGroupAvailabilityModel
{
public string ChapterTitle { get; set; }
public string ChapterDetail { get; set; }
public List<TreeViewModel> TreeViewModels { get; set; }
}
And
public class TreeViewModel
{
public string ParentNode { get; set; }
public bool isChecked { get; set; }
public List<TreeViewModel> ChildNodes { get; set; }
}
Here is the function that i use to display the tree full on the cshtml file.
Here is part of the cshtml file:
here is my controller:
public async Task<IActionResult> Index()
{
List<TreeViewModel> TreeModel = BuildModels(await prtgClient.GetExtendedGroupsAsync(_pRTGApiClient),1);
DeviceGroupAvailabilityModel deviceGroupAvailabilityModel = new DeviceGroupAvailabilityModel
{
ChapterTitle = "Device And Group Availability",
ChapterDetail = "",
TreeViewModels = TreeModel
};
return View("Index",deviceGroupAvailabilityModel);
}
public IActionResult Cancel()
{
return RedirectToAction("Index","Home");
}
[HttpPost]
public async Task<IActionResult> Save([FromForm]DeviceGroupAvailabilityModel deviceGroupAvailabilityModel)
{
int reportID = await _dbConnection.GetReportId(deviceGroupAvailabilityModel.ChapterTitle);
deviceGroupAvailabilityModel.TreeViewModels.Select(async group => await AddGroupToReport(group.ParentNode, reportID));
return View("Index");
}
private async Task AddGroupToReport(string groupName,int reportID)
{
int groupId = await _dbConnection.GetGroupId(groupName);
await _dbConnection.AddGroupToReport(groupId, reportID);
}
private List<TreeViewModel>BuildModels(List<ExtendedGroup>extendedGroups,int rootID)
{
List<TreeViewModel> TreeModel = new List<TreeViewModel>();
extendedGroups.ForEach(group =>
{
if (group.parentId == rootID)
{
TreeModel.Add(new TreeViewModel
{
ParentNode = group.name,
ChildNodes = BuildModels(extendedGroups, group.objid)
});
}
});
return TreeModel;
}
Model Binding from controller to view works great but from view to controller in only get the Two textbox not the list of treeview model.
Is there a way to solve this?
kind regards,
Edit: Full CSHTML Code withoud Title:
#model DeviceGroupAvailabilityModel
#functions{
void DisplayTree(List<TreeViewModel>models)
{
<ul>
#foreach (TreeViewModel treeViewModel in models)
{
<li>
<input type="checkbox" id="#treeViewModel.ParentNode" name="#treeViewModel.ParentNode" checked="#treeViewModel.isChecked" />
#treeViewModel.ParentNode
#if (treeViewModel.ChildNodes.Count > 0)
{
DisplayTree(treeViewModel.ChildNodes);
}
</li>
}
</ul>
}
}
#using (Html.BeginForm("Save", "DeviceGroupAvailability",FormMethod.Post)) {
<div class="container">
<div class="row">
<div class="col-auto">
<div class="card shadow" style="border-left-color:#0087e9;border-left-width:medium">
<h6 class="card-header text-center bg-warning">SELECT GROUP TO REPORT</h6>
<div class="card-body">
<div class="tree well">
#{
DisplayTree(Model.TreeViewModels);
}
</div>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="card shadow ml-3 mb-3" style="border-left-color:#0087e9;border-left-width:medium">
<h6 class="card-header text-center bg-warning">CHAPTER TITLE</h6>
<div class="card-body">
#Html.TextBoxFor(m=>m.ChapterTitle)
</div>
</div>
</div>
<div class="row">
<div class="card shadow ml-3 mb-3" style="border-left-color:#0087e9;border-left-width:medium">
<h6 class="card-header text-center bg-warning">CHAPTER Description</h6>
<div class="card-body">
#Html.TextBoxFor(m=>m.ChapterDetail)
</div>
</div>
</div>
<div class="row">
<input type="submit" class="btn ml-5 bg-primary text-white" value="Save" />
<button type="button" class="btn bg-primary ml-5 text-white" onclick="location.href='#Url.Action("Cancel", "DeviceGroupAvailability")'">Cancel</button>
</div>
</div>
</div>
</div>
}
#section Scripts{
<script type="text/javascript">
$(":checkbox").change(function () {
//begin Cheking all child elements
var ulsiblings = $(this).siblings("ul");
var lichilt = ulsiblings.find("li");
var checkchild = lichilt.find(":checkbox");
checkchild.prop("checked", this.checked);
//begin checking Parent element
//if child is checked
var checkLiParent = $(this).parent();
var checkliSiblings = checkLiParent.siblings("li");
var lisibCheck = checkliSiblings.find(":checkbox");
var isAllChecked;
lisibCheck.each(function () {
if (this.checked) {
isAllChecked = true;
}
else {
isAllChecked = false;
}
})
if (isAllChecked) {
var checkParent = checkLiParent.parent();
var parentSib = checkParent.siblings(":checkbox");
parentSib.prop("checked", this.checked);
}
})
</script>
}

many to many relationship update data mvc .net core

I have a many to many relationship in .net core mvc, but I have no idea how to implement a edit view.
The models are
Studios
public class Studio
{
public int StudioID { get; set; }
public string Name { get; set; }
public ICollection<StudioAddress>StudioAddresses { get; set; }
}
Addresses
public class Address
{
public int AddressID { get; set; }
public string Street { get; set; }
public ICollection<StudioAddress> StudioAddresses { get; set; }
}
StudioAddress
public class StudioAddress
{
public int StudioID { get; set; }
public Studio Studio { get; set; }
public int? AddressID { get; set; }
public Address Address { get; set; }
}
My databasecontext
modelBuilder.Entity<StudioAddress>()
.HasKey(sa => new { sa.StudioID, sa.AddressID });
modelBuilder.Entity<StudioAddress>()
.HasOne(sa => sa.Studio)
.WithMany(s => s.StudioAddresses)
.HasForeignKey(sa => sa.StudioID);
modelBuilder.Entity<StudioAddress>()
.HasOne(sa => sa.Address)
.WithMany(a => a.StudioAddresses)
.HasForeignKey(sa => sa.AddressID);
Now, I have created the edit Get method in my studioscontroller
// get
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var studio = await _context.Studios
.Include(s => s.StudioAddresses).ThenInclude(s => s.Address)
.Where(s => s.StudioID == id)
.AsNoTracking()
.FirstOrDefaultAsync();
if (studio == null)
{
return NotFound();
}
return View(studio);
}
But I have no idea how to update the related data for studio and address?
Bot are forms with textfields. The original microsoft docs are confusing (they work with tickboxes) and weird methods to whitelist fields. Is there a simpler, more intuitive way of doing this?
Based on your model definition, you could try to design the Edit view and the Post method like below :
Here is the “Edit” view:
#model SOMVCDemo.Models.Studio
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="StudioID" />
<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">
<label class="control-label">StudioAddresses</label>
<table>
<tbody>
#{ int i = 0;}
<tr>
#foreach (var StudioAddress in #Model.StudioAddresses)
{
<td>
<input type="hidden" name="studioAddresses[#i].AddressID" asp-for="#StudioAddress.AddressID" class="form-control" />
<input type="text" name="studioAddresses[#i].Address.Street" asp-for="#StudioAddress.Address.Street" class="form-control" />
</td>
i++;
}
</tr>
</tbody>
</table>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
Here is the POST method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Studio studio)
{
if (id != studio.StudioID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
var st = _context.Studios.FirstOrDefault(n => n.StudioID == studio.StudioID);
st.Name = studio.Name;
_context.Update(st);
foreach(var i in studio.StudioAddresses)
{
var address = _context.Addresses.FirstOrDefault(n=>n.AddressID == i.AddressID);
address.Street = i.Address.Street;
_context.Update(address);
}
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!StudioExists(studio.StudioID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(studio);
}

Can’t update ICollection property

The problem is when I try to update Master and Details Tables at the same time.
When call Post Edit Task the Details objects don´t appear.
The Edit View displays all Details rows correctly, but while debugging the Edit POST, Casas is empty
MODELS
public partial class Modelo : IValidatableObject {
public Modelo()
{
Casas = new HashSet<Casa>();
}
public int Modeloid { get; set; }
public string Modelo1 { get; set; }
public virtual ICollection<Casa> Casas { get; set; }//Don’t work to update
}
public partial class Casa // DETAIL TABLE
{
public int Casaid { get; set; }
public int Modeloid { get; set; } // FK to Modelo
public string Casa1 { get; set; }
public virtual Modelo Modelo { get; set; }
}
CONTROLLER
public class ModelosController : Controller
. . . . . . . . .
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Modelo modelo)
{
if (id != modelo.Modeloid)
{
return NotFound();
}
if (ModelState.IsValid)
{
// Here modelo.Modelo1 has current modified value
// but modelo.Casas.Count == 0
_context.Update(modelo);
await _context.SaveChangesAsync();
}
}
// GET: Modelos/Edit
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var modelo = await _context.Modelo
.AsNoTracking()
.Include(m => m.Fotomodelos)
.Include(m => m.Casas)
.SingleOrDefaultAsync(m => m.Modeloid == id);
if (modelo == null)
{
return NotFound();
}
return View(modelo);
}
View EDIT.CSHTML
#using System.IO
#model Disponibilidad.Models.Modelo
<form asp-action="Edit">
<div class="form-horizontal">
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Modeloid" />
<div class="form-group">
<label asp-for="Modelo1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Modelo1" class="form-control" />
<span asp-validation-for="Modelo1" class="text-danger"></span>
</div>
</div>
#{
for (int i = 0; i < Model.Casas.Count; i++)
{
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Modeloid"
value="#Model.Modeloid" />
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Casaid" />
<div class="form-group">
<label asp-for="#Model.Casas.ElementAt(i).Casa1"
class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="#Model.Casas.ElementAt(i).Casa1"
class="form-control" /> <!-- DISPLAY OK Detail rows -->
<span asp-validation-for="#Model.Casas.ElementAt(i).Casa1"
class="text-danger"></span>
</div>
</div>
}
}
<div class="btn-group">
<button type="submit" class="btn btn-danger">Save</button>
</div>
</div>
</form>
When you use a for cycle instead of foreach in Razor, the name of the properties doesn't get rendered correctly when using the default asp-for TagHelpers.
You can correct your example changing your razor form inputs as follow:
From:
<input type="hidden" asp-for="#Model.Casas.ElementAt(i).Casaid" />
To:
<input type="hidden" name="modelo.Casas[#i].Casaid" value="#Model.Casas.ElementAt(i).Casaid" />

ASP MVC 6 RC1 Edit form creates

I have a simple Web application in ASP.NET MVC 6 RC1.
The problem is that when editing a previously added item. The item returned to the Edit POST has an ID = 0, so it creates a copy of the data I was trying to update.
When pressing the Edit link, it takes me to the correct route:
http://localhost:41250/Proyectos/Edit/1
And the GET IActionResult recieves the correct id.
But inside the edit form, when I press the Save button, in the Controller POST part of the Edit it recieves a proyecto who has all the data from the form except the id (ProyectoId) which is 0.
Model:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace RegistroHora.Models
{
public class Proyecto
{
[ScaffoldColumn(false)]
[Key]
public int ProyectoId { get; set; }
[Required]
public string Nombre { get; set; }
[Required]
[Display(Name ="Número de Horas")]
public decimal NumHoras { get; set; }
[Required]
[Display(Name = "Tipo de Horas")]
public string TipoHoras { get; set; }
[Display(Name = "Proyecto Finalizado")]
public bool Concluido { get; set; }
public virtual ICollection<Registro> Registros { get; set; }
}
}
View:
#model RegistroHora.Models.Proyecto
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Proyecto</h4>
<hr />
<div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Nombre" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Nombre" class="form-control" />
<span asp-validation-for="Nombre" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="NumHoras" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="NumHoras" class="form-control" />
<span asp-validation-for="NumHoras" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="TipoHoras" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="TipoHoras" class="form-control" />
<span asp-validation-for="TipoHoras" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkboxs">
<input asp-for="Concluido" type="checkbox"> #Html.DisplayNameFor(i => i.Concluido)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
}
Controller:
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Data.Entity;
using RegistroHora.Models;
namespace RegistroHora.Controllers
{
public class ProyectosController : Controller
{
private ApplicationDbContext _context;
public ProyectosController(ApplicationDbContext context)
{
_context = context;
}
// GET: Proyectos
public IActionResult Index()
{
return View(_context.Proyecto.ToList());
}
// GET: Proyectos/Details/5
public IActionResult Details(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Proyecto proyecto = _context.Proyecto.Single(m => m.ProyectoId == id);
if (proyecto == null)
{
return HttpNotFound();
}
return View(proyecto);
}
// GET: Proyectos/Create
public IActionResult Create()
{
return View();
}
// POST: Proyectos/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Proyecto proyecto)
{
if (ModelState.IsValid)
{
_context.Proyecto.Add(proyecto);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(proyecto);
}
// GET: Proyectos/Edit/5
public IActionResult Edit(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Proyecto proyecto = _context.Proyecto.Single(m => m.ProyectoId == id);
if (proyecto == null)
{
return HttpNotFound();
}
return View(proyecto);
}
// POST: Proyectos/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Proyecto proyecto)
{
if (ModelState.IsValid)
{
_context.Update(proyecto);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(proyecto);
}
// GET: Proyectos/Delete/5
[ActionName("Delete")]
public IActionResult Delete(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Proyecto proyecto = _context.Proyecto.Single(m => m.ProyectoId == id);
if (proyecto == null)
{
return HttpNotFound();
}
return View(proyecto);
}
// POST: Proyectos/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
Proyecto proyecto = _context.Proyecto.Single(m => m.ProyectoId == id);
_context.Proyecto.Remove(proyecto);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
}
I have NO problem with Index, Create, Delete or Details, only Edit.
You need to pass the ProyectoId value from your form. You may keep that in a hidden field inside your form.
<form asp-action="Edit">
<input type="hidden" asp-for="ProyectoId" />
<!-- Your existing form fields for other properties goes here -->
<input type="submit" value="Save" class="btn btn-default" />
</form>
Another approach is to change signature for method Edit, like this:
public IActionResult Edit(int id, Proyecto proyecto)
In this case, you can pass id over action URL. In this case you need to modify action URL in your view as:
<form asp-action="Edit" asp-route-id=#Model.ProyectoId>
Of cource, you need proper Route that support Id as parametar.
P.s. Id you prefere the first approach, just remove [ScaffoldColumn(false)] from your property class.
Since the update in edit is around the key(ProyectoId); you cannot change it; however instead of making it will disappear by

Categories

Resources