Returning the property of another model that is bound to a Model in the first model - razor

I'm trying to access the Question list from within the TestModel and return the QuestionModel's Property.
I need to return it in the TestModel to determine the questions to be contained in a test, but I can't, I can't find where I went wrong.
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<QuestionModel> Question { get; set; }=new List<QuestionModel>();
}
public class QuestionModel
{
public int Id { get; set; }
public AppUser User { get; set; }
public string Question { get; set; }
public bool check { get; set; }
public List<TestModel>? Tests { get; set; } = new List<TestModel>();
}
I used TestModel as one of the tuple objects.
Since the code is long, I only shared the area where I had problems.
#model Tuple<IList<TestModel>,IList<UserViewModel>>
<table class="table table-striped">
#{
int i = 0;
}
#foreach (var item in Model.Item1)
{
<form id="form[#i]" class="container m-xl-2">
<tr id="Allquest_#i" hidden="hidden">
<td colspan="5">
<div>
<input asp-for=#Model.Item1[i].Id hidden>
#for (int indexQuest = 0; indexQuest < item.Question.Count; indexQuest++)
{
<input type="checkbox" asp-for="#Model.Item1[i].Question[indexQuest].check" checked="#Model.Item1[i].Question[indexQuest].check">
<a>#Model.Item1[i].Question[indexQuest].Question</a>
<br />
}
</div>
</td>
<td>
<button type="submit" asp-controller="Test" asp-action="DeleteQuestionToTest" formmethod="post" class="btn btn-danger">Seçili Soruları Sil</button>
</td>
</tr>
</form>
i++;
}
Here I tried to capture it as a TestModel. I tried to capture it as a list and as a single model, but I couldn't.
[HttpPost]
public IActionResult DeleteQuestionToTest([Bind(Prefix ="Item1")] IList<TestModel> tests)
{
return View();
}
How can I fix the code?

I came up with a workaround by creating a separate form and specifying it in the html of the models.
#model Tuple<IList<TestModel>,IList<UserViewModel>>
<table class="table table-striped">
#{
int i = 0;
}
<form id="MainForm" asp-controller="Test" asp-action="DeleteQuestionToTest" formmethod="post"></form>
#foreach (var item in Model.Item1)
{
<form id="form[#i]" class="container m-xl-2">
<tr id="Allquest_#i" hidden="hidden">
<input asp-for=#Model.Item1[i].Id form="MainForm" hidden>
<td colspan="5">
<div>
#for (int indexQuest = 0; indexQuest < item.Question.Count; indexQuest++)
{
<input asp-for="#Model.Item1[i].Question[indexQuest].Id" form="MainForm" hidden>
<input type="checkbox" asp-for="#Model.Item1[i].Question[indexQuest].check" form="MainForm" checked="#Model.Item1[i].Question[indexQuest].check">
<a>#Model.Item1[i].Question[indexQuest].Question</a>
<br />
}
</div>
</td>
<td>
<button type="submit" form="MainForm" class="btn btn-danger">Seçili Soruları Sil</button>
</td>
</tr>
</form>
i++;
}
I returned all the tests this was a workaround, I have no idea how to return a single test.

Related

Change the HTML element in a Blazor application by pressing a button?

I wanted to ask if it is possible to change the type of an HTML element in a Blazor application by pressing a button.
That I turn a normal text into a text input field for example.
I have a table where the first column has a button for each entry in the table.
My goal is that when you press the button, the fields turn into input fields in time, so you can edit the values.
This is just a quick photo edit, but this is how I imagined it.
You can use an index array to track the edit status of each company. When the button is clicked, the corresponding value in the index array will be toggled. If the value is set to true, the cell will display an input field where you can edit the company name. The updated name will be saved to the list.
Instead of using a simple string to store company information, you can create a class that contains multiple properties such as the company name and location..
Output:
Demo: https://blazorfiddle.com/s/lil3olrf
Implementation:
#page "/"
<h3>Companies</h3>
<table class="table table-bordered table-sm">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Company</th>
<th scope="col">Location</th>
</tr>
</thead>
<tbody>
#foreach (var company in Companies)
{
var index = Companies.IndexOf(company);
<tr>
<td>
<button type="button" class="btn btn-primary"
#onclick="#(() => { Edits[index] = !Edits[index]; })">
#(Edits[index] ? "Back" : "Edit")
</button>
</td>
<td>
#if (Edits[index])
{
<input class="form-control" type="text"
style="background-color:lightyellow;"
value="#company.Name"
#oninput="#(e => { Companies[index].Name = e.Value.ToString(); })"/>
}
else
{
#company.Name
}
</td>
<td>
#if (Edits[index])
{
<input class="form-control" type="text"
style="background-color:lightyellow;"
value="#company.Location"
#oninput="#(e => { Companies[index].Location = e.Value.ToString(); })"/>
}
else
{
#company.Location
}
</td>
</tr>
}
</tbody>
</table>
<ul>
#*Check realtime changes to Company names when you edit them*#
#foreach (var company in Companies)
{
<li>#company.Name: #company.Location</li>
}
</ul>
#code {
private List<Company> Companies { get; set; } = new List<Company>
{
new Company("Globex Corporation", "Germany"),
new Company("Soylent Corp", "Switzerland"),
new Company("Umbrella Corporation", "Netherlands")
};
private bool[] Edits { get; set; }
protected override void OnInitialized()
{
Edits = new bool[Companies.Count];
}
public class Company
{
public Company(string name, string location)
{
Name = name;
Location = location;
}
public string Name { get; set; }
public string Location { get; set; }
}
}
Here's a basic component and demo page to demonstrate how you can do this. There's a component and a demo page.
#page "/"
<div>
<button class="btn btn-dark" disabled="#isEdit" #onclick="GoEdit">Edit</button>
#if (this.isEdit)
{
#EditControl
}
else
{
#ViewControl
}
</div>
#code {
[Parameter] public RenderFragment ViewControl { get; set; }
[Parameter] public RenderFragment EditControl { get; set; }
protected string disabled => isEdit ? "disabled": "";
protected bool isEdit { get; set; }
private void GoEdit(MouseEventArgs e)
=> isEdit = !isEdit;
}
And a demo page:
#page "/Demo"
<h3>EditorTest</h3>
<CascadingValue Value="model">
<EditForm EditContext="editContext">
<EditFormState #ref="editFormState" EditStateChanged="EditStateChanged"></EditFormState>
<div>
<SwitchedEditorComponent>
<EditControl>
Email: <InputText #bind-Value="model.Email" placeholder="Enter your Email Address"></InputText>
</EditControl>
<ViewControl>
Email: <InputText #bind-Value="model.Email" disabled></InputText>
</ViewControl>
</SwitchedEditorComponent>
</div>
</EditForm>
</CascadingValue>
#code {
private dataModel model { get; set; } = new dataModel();
private EditFormState editFormState;
private EditContext editContext;
protected override Task OnInitializedAsync()
{
this.editContext = new EditContext(model);
return base.OnInitializedAsync();
}
private void EditStateChanged(bool editState)
{
StateHasChanged();
}
public class dataModel
{
public string Email { get; set; }
}
}

ASP.NET Core : moving data from one table into another

I'm currently developing an e-commerce website using ASP.NET Core. I'm trying to move data from the Products table into the Items table using a button press so that the data in the items table can be presented on the basket page. Any help would be appreciated.
The relevant button is using the asp-action=AddToCart:
<div class="card-body">
<h3 class="card-title">#product.Name</h3>
<svg class="bd-placeholder-img card-img-top" width="100%" >
<img float="left" width="450" height="450" src="~/assets/Clothing/#product.ProductImage" alt="Image of #product.Name" />
</svg>
<p class="card-text">#product.Description</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
#if (User.IsInRole("Admin"))
{
<a class="btn btn-sm btn-outline-secondary" asp-page="/UpdateProductInfo"
asp-route-id="#product.Id">Update</a>
}
<a class="btn" asp-action="AddToCart">Add to Cart</a>
<p class="float-right card-text" >£#product.Price</p>
</div>
</div>
</div>
C#
[BindProperty]
public Item Items { get; set; }
public IActionResult addToCart()
{
_db.Items.Add(Items);
_db.SaveChanges();
return Page();
}
product.cs model
public class Product
{
public String Id { get; set; }
[ForeignKey("Name")]
public String Name { get; set; }
public String Description { get; set; }
[ForeignKey("Price")]
public int Price { get; set; }
[ForeignKey("ProductImage")]
public String ProductImage { get; set; }
public String ProductImageName { get; set; }
}
Item.cs model
public class Item
{
[Key]
[ForeignKey("Name")]
public String Name { get; set; }
[ForeignKey("Price")]
public int Price { get; set; }
[ForeignKey("ProductImage")]
public String ProductImage { get; set; }
}
item class must be like this :
public class Item
{
[Key]
public int ItemId { get; set; }
public Product Product { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public String ProductImage { get; set; }
}
and your product class :
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name{ get; set; }
public int Price { get; set; }
public int Description{ get; set; }
public string ProductImage { get; set; }
public string ProductImageName { get; set; }
}
it was a (single to single) relationship between two tables
I'm trying to move data from the Products table into the Items table
using a button press so that the data in the items table can be
presented on the basket page. Any help would be appreciated.
From your description, I assume in the main page, you are listed the Products and each row of the product will have an "Add to Cart" button, after clicking it, it will add the selected Product to the Item table, right?
Since your application is an Asp.net core Razor Page application, for the "Add to Cart" button, you could use the handler method to transfer the route parameter to the method, and then add the selected product to Item table. Refer the following sample:
Model:
public class Product
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public int Price { get; set; }
public String ProductImage { get; set; }
public String ProductImageName { get; set; }
}
public class Item
{
[Key]
public String Name { get; set; }
public int Price { get; set; }
public String ProductImage { get; set; }
}
ProductIndex.cshtml:
#page
#model RazorPageSample.Pages.ProductIndexModel
<div class="row">
<div class="col-md-6">
<form method="post">
<table class="table">
<thead>
<tr><th colspan="5">Product Table</th></tr>
<tr>
<th>
Product ID
</th>
<th>
Product Name
</th>
<th>
Description
</th>
<th>
Price
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Products)
{
<tr>
<td>
#item.Id
</td>
<td>
#item.Name
</td>
<td class="text-right">
#item.Description
</td>
<td class="text-right">
£#item.Price
</td>
<td class="text-right">
<button asp-page-handler="AddToCart" class="btn btn-primary" asp-route-id="#item.Id">Add to Cart</button>
</td>
</tr>
}
</tbody>
</table>
</form>
</div>
<div class="col-md-6">
<table class="table">
<thead><tr><th colspan="5">Item Table</th></tr>
<tr>
<th>
Item Name
</th>
<th>
Price
</th>
<th></th>
</tr>
</thead>
<tbody>
#if (Model.Items !=null && Model.Items.Count > 0)
{
foreach (var item in Model.Items)
{
<tr>
<td>
#item.Name
</td>
<td class="text-right">
£#item.Price
</td>
<td class="text-right">
</td>
</tr>
}
}
</tbody>
</table>
</div>
</div>
ProductIndex.cshtml.cs:
public class ProductIndexModel : PageModel
{
//Here I use a DataRepository to set the initial data.
private readonly IDataRepository _repository;
public ProductIndexModel(IDataRepository repository)
{
_repository = repository;
}
[BindProperty]
public List<Item> Items { get; set; } //item list.
public List<Product> Products { get; set; } // product list
public void OnGet()
{
Products = _repository.GetProducts();
}
public async Task<IActionResult> OnPostAddToCartAsync(string id)
{
// use session to store the items.
// you could directly store the new item into database. in this scenario, you could query the database and get the existing items.
if (HttpContext.Session.Get<List<Item>>("_Items") != default)
{
Items = (List<Item>)HttpContext.Session.Get<List<Item>>("_Items");
}
if (id != null)
{
var product = _repository.GetProducts().Where(c => c.Id == id).FirstOrDefault();
Item newitem = new Item()
{
Name = product.Name,
Price = product.Price
};
Items.Add(newitem);
HttpContext.Session.Set<List<Item>>("_Items", Items);
}
//reset the Products.
Products = _repository.GetProducts();
return Page();
}
}
The screenshot as below:
More detail information, you could refer the following links:
Handler Methods in Razor Pages
Write a basic form
Session and state management in ASP.NET Core
[Note]If you want to use Session to store the Object,after configuring your application use session, remember to add SessionExtensions.

Passing list of models from one page to controller

I've tried to pass a list of models to controller but with no luck. I have a problem with generating empty view and then pass values from filled forms to controller. What I have:
Models
public class PostsModel
{
[Required]
[DataType(DataType.DateTime)]
public DateTime PublishDate { get; set; }
[Required]
public List<PostModel> Posts { get; set; }
}
public class PostModel
{
public string Language {get;set;}
public string X {get;set;}
public string Y {get;set;}
// and other properties
}
Controller
public IActionResult New()
{
ViewData["ButtonName"] = "Add";
return View(new PostsModel { PublishDate = DateTime.UtcNow });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> New(PostsModel model)
{
if (ModelState.IsValid)
{
// some code
// never reaches this point
}
return View(model);
}
Form:
<form method="post">
<h4>XYZ</h4>
<hr />
#{
Model.Posts = new List<PostModel>(2);
for (var i = 0; i < 2; i++)
{
Model.Posts.Add(new PostModel());
}
foreach (var test in Model.Posts)
{
<h4>xyz</h4>
<div class="form-group">
<label asp-for="#test.Subject">Temat</label>
<input asp-for="#test.Subject" class="form-control" />
<span asp-validation-for="#test.Subject" class="text-danger"></span>
</div>
}
}
<button type="submit" class="btn btn-primary">#ViewData["ButtonName"]</button>
</form>
Of course model is never valid. I don't have an idea how to do such functionality.
As #StephenMuecke said, using for-loop is working approach. In this particular problem that I had it's enough to do:
Controller:
public IActionResult New()
{
ViewData["ButtonName"] = "Add";
// example:
return View(new PostsModel { PublishDate = DateTime.UtcNow, Posts = new List<PostModel>(2) { new PostModel(), new PostModel() } });
}
View:
for (var i = 0; i < Model.Posts.Count; i++)
{
<h4>xyz</h4>
<div class="form-group">
<label asp-for="#Model.Posts[i].Subject">Temat</label>
<input asp-for="#Model.Posts[i].Subject" class="form-control" />
<span asp-validation-for="#Model.Posts[i].Subject" class="text-danger"></span>
</div>
#*and so one*#
}
I also want to thank M. Kostrzewski and M. Kaletka who also helped me on some .net group

Using ng-repeat to create ng-tables which display info from a List

I have a Person object, which has a list of Reports.
public class Person
{
public string IdNum { get; set; }
public string LastName { get; set; }
public Int32 LocFlag { get; set; }
public IList<Report> Reports { get; set; }
}
public class Report
{
public long ReportNum { get; set; }
public DateTime? ReceivedDate { get; set; }
public string Subject { get; set; }
}
I have a list of these people from my controller - vm.Persons and vm.PersonParams.
My intention is to produce a seperate ng-table for each Person, each table should display information from their Reports.
The method I'm using now produces a single empty table:
<div class="table-responsive">
<table ng-table="vm.PersonParams" class="table table-hover">
<tr ng-repeat="row in $data">
<td data-title="'Report Number'" >{{row.Reports.ReportNum }} </td>
<td data-title="'Date'" >{{row.Reports.ReceivedDate }} </td>
<td data-title="'Subject'" >{{row.Reports.Subject }} </td>
</tr>
</table>
</div>
Values of Persons and PersonParams:
vm.Persons = [{"IdNum ":"23713","LastName ":"Smith","LocFlag":0,"Reports":[{"ReportNum":321231,"ReceivedDate":"2010-09-16T15:25:00","Subject":"Tax",}]},{"IdNum":"32552","LastName":"Xavier","LocFlag":1,"Reports":[{"ReportNum":324342,"ReceivedDate":"2013-09-11T07:50:00","Subject":"Filing Request"}]}];
vm.PersonParams = {"data":[]};
If it's the total code you are using, then you missed ng-repeat in the outer div. What is $data here? Probably you made a mistake over there too.
You might need to use it as shown below
<div class="table-responsive" ng-repeat = "person in vm.Persons">
<table class="table table-hover">
<tr ng-repeat="report in person.Reports">
<td data-title="'Report Number'" >{{report.ReportNum }} </td>
<td data-title="'Date'" >{{report.ReceivedDate }} </td>
<td data-title="'Subject'" >{{report.Subject }} </td>
</tr>
</table>
</div>
Let me know if this helps!

MVC Radio Button List Grid

I've got an issue trying to read the selected values from the radio button list in my [HttpPost] Controller. Any help would be greatly appreciated.
My models are the following:
public partial class RoleModel
{
public Guid RoleId { get; set; }
public string Description { get; set; }
public List<RoleModuleAccessRight> RoleModuleAccessRights { get; set; }
}
public class RoleModuleAccessRight
{
public string ModuleName { get; set; }
public int ModuleId { get; set; }
public bool HasFullControl { get; set; }
public bool HasReadOnly { get; set; }
public bool HasNoAccess { get; set; }
}
My Controllers:
[HttpGet]
public ActionResult Edit(Guid id)
{
RoleModel role = BusinessLayer.UserManager.GetRoleModel(id);
role.RoleModuleAccessRights = BusinessLayer.UserManager.GetModulesForRoleId(role.RoleId);
return PartialView("_Edit", role);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(RoleModel model)
{
if (ModelState.IsValid)
{
BusinessLayer.UserManager.UpdateAccessRights(model);
string url = Url.Action("List", "Roles");
return Json(new { success = true, url = url });
}
return PartialView("_Edit", model);
}
My View code:
#foreach (RoleModuleAccessRight item in Model.RoleModuleAccessRights)
{
#Html.HiddenFor(model => item.ModuleId)
string radioName = string.Format("RoleModuleAccessRights_{0}", item.ModuleId.ToString());
<tr>
<td>#item.ModuleName</td>
<td>
<div class="checkbox">
#Html.RadioButton(radioName, item.HasFullControl, item.HasFullControl)
</div>
</td>
<td>
<div class="checkbox">
#Html.RadioButton(radioName, item.HasReadOnly, item.HasReadOnly)
</div>
</td>
<td>
<div class="checkbox">
#Html.RadioButton(radioName, item.HasNoAccess, item.HasNoAccess)
</div>
</td>
</tr>
}
The issue im having is that when i post the form im not able to grab the information in my [HttpPost] Controller. It returns "null"
The mark up generated is the following:
Looking at your code, your ids are not unique which is going to break things, also using a dedicated template will simplify your problem. See this example https://stackoverflow.com/a/7668325
Another more generic article: Multiple radio button groups in MVC 4 Razor