Simplest way to pass an object in razor pages - asp.net-core

I'm new to Razor and I'm trying to pass data from "Index.html" to "Quiz.html" but I'm struggling to put the pieces together using different tutorials. This is where I got so far. I'm trying to do it without using a service but I'm not sure if it's possible.
Thanks!
Index.html
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome, #Model.Name</h1>
<p>This is My Quiz App</a>.</p>
<form method="post">
<label>What's your name?</label>
<input type="text" asp-for="#Model.Visitor.Name">
<button type="submit">Send</button>
</form>
</div>
Index.cs
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
[ViewData]
[BindProperty]
public string Name { get; set; }
public Visitor Visitor { get; set; }
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
Name = "Stranger";
}
public IActionResult OnPost()
{
return RedirectToPage("/Quiz", new { Visitor.Name });
}
}
}
Quiz.html
#page
#model QuizModel
#{
ViewData["Title"] = "Quiz Page";
}
<div class="text-center">
<h1 class="display-4">Thanks for checking my first website out, #Model.Name. Are you ready?</h1>
<p>Let's see how much you know about me.</a>.</p>
</div>
Quiz.cs
public class QuizModel : PageModel
{
[ViewData]
[BindProperty]
public string Name { get; set; }
public Visitor Visitor { get; set; }
public void OnGet()
{
Name = ?
}

You can directly submit the form from Index.cshtml to Quiz.cs with asp-page tag helper. Define a OnPost handler in Quiz.cs
public class QuizModel : PageModel
{
[ViewData]
[BindProperty]
public string Name { get; set; }
[BindProperty]
public Visitor Visitor { get; set; }
public void OnGet()
{
}
public void OnPost()
{
Name = Visitor.Name;
}
}
Index.cshtml:
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome, #Model.Name</h1>
<p>This is My Quiz App.</p>
<form asp-page="Quiz" method="post">
<label>What's your name?</label>
<input type="text" asp-for="Visitor.Name">
<button type="submit">Send</button>
</form>
</div>
Result:

Related

dropzone image passing with a model

I have a form that includes several inputs(text) and below them, there is a dropzone area. I need to pass these data and image together in a model.
I have a model like this:
public BannerItem bannerItem { get; set; }
public IFormFile imagefile { get; set; }
I am using tags like asp-for and i dont know how to bind dropzone image to the imagefile. I tried js but it didn't work. Can you help me with this?
Here is a whole working demo you could follow:
Model
public class TestVM
{
public BannerItem bannerItem { get; set; }
public IFormFile imagefile { get; set; }
}
public class BannerItem
{
public int Id { get; set; }
public string Name { get; set; }
}
View (Index.cshtml)
#model TestVM
<form asp-action="Test" asp-controller="Home" method="post" enctype="multipart/form-data" class="dropzone dz-clickable form-horizontal form-bordered" id="dropzoneForm">
<div class="form-group form-actions">
<input asp-for="bannerItem.Name" />
<div class="col-md-9 col-md-offset-4">
<button type="submit" id="submit" class="btn btn-sm btn-primary"><i class="fa fa-floppy-o"></i> Upload</button>
</div>
</div>
</form>
#section Scripts
{
<link rel="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/dropzone.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/dropzone.js"> </script>
<script>
function myParamName() {
return "imagefile";
}
Dropzone.options.dropzoneForm = {
autoProcessQueue: false,
paramName: myParamName, // The name that will be used to transfer the file
uploadMultiple: true,
parallelUploads: 100,
init: function () {
console.log("active");
var wrapperThis = this;
$("#submit").click(function (e) {
e.preventDefault();
wrapperThis.processQueue();
});
},
accept: function (file, done) {
done();
}
};
</script>
}
Controller
public class HomeController : Controller
{
public async Task<IActionResult> Index()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Test(TestVM model)
{
//do your sufff...
}
}

Why this Model Binding not working in Razor Page

I am using ASP.NET Core 3.1 with a simple example to test model binding to post a form. The property to be bound is an object named "Student". Bud the model binding is not working with post method. I will appreciate any help to point out what's wrong here.
Here are the code of my test programs:
'Student Class':
namespace ModelBindPost.Models
{
public class Student
{
public int Id;
public string FirstName;
public string LastName;
}
}
'Edit.cshtml.cs'
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ModelBindPost.Models;
namespace ModelBindPost.Pages
{
public class EditModel : PageModel
{
[BindProperty(SupportsGet = true)]
public Student Student { get; set; }
public EditModel()
{
Student = new Student();
}
public IActionResult OnGet()
{
Student.Id = 1;
Student.FirstName = "Jean";
Student.LastName = "Smith";
return Page();
}
public IActionResult OnPost()
{
string name = this.Student.FirstName;
return Page();
}
}
}
' Edit.cshtml':
#page
#model ModelBindPost.Pages.EditModel
#{
}
<h2>Model Binding Test</h2>
<form method="post">
<div class="form-group">
<lable asp-for="Student.Id"></lable>
<input asp-for="Student.Id" class="form-control" />
</div>
<div class="form-group">
<lable asp-for="Student.FirstName"></lable>
<input asp-for="Student.FirstName" class="form-control" />
</div>
<div class="form-group">
<lable asp-for="Student.LastName"></lable>
<input asp-for="Student.LastName" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
A simple public field cannot work for model binding. You need add getter and setter to create property like below:
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

MVC checkbox list bounding to model

I am trying to collect all the options that the user have selected for a checkbox list. The checkbox list is built using a foreach loop and I have a int[] that I am trying to put the id into. Any help would be great.
View
#{
int idxFormats = 0;
foreach (var item in Model.ListOfFormats)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="chkFormat" />
<label asp-for=#item.Selected>#Html.Raw(#item.Name)</label>
#Html.HiddenFor(m => Model.selectedFormats[idxFormats]);
</div>
idxFormats++;
}
#Html.ValidationMessageFor(model => model.selectedFormats[idxFormats])
}
Model
public List<GenericValues> ListOfFormats { get; set; }
[Display(Name = "At least one 'Format' must be selected")]
public int[] selectedFormats { get; set; }
Change the Checkbox name to selectedFormats
<input type="checkbox" value=#item.Value name="selectedFormats" />
Test example:
Model:
public class Test
{
public List<GenericValues> ListOfFormats { get; set; }
public int[] selectedFormats { get; set; }
}
public class GenericValues
{
public int Value { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
View:
#model Test
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<form method="post">
#{
foreach (var item in Model.ListOfFormats)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="selectedFormats" />
<label asp-for=#item.Selected>#Html.Raw(#item.Name)</label>
</div>
}
}
<input type="submit" value="submit" />
</form>
Controller:
public IActionResult Index()
{
Test test = new Test
{
ListOfFormats = new List<GenericValues>
{
new GenericValues
{
Name = "A",
Value = 1,
},
new GenericValues
{
Name = "B",
Value = 2,
},
new GenericValues
{
Name = "C",
Value = 3,
}
}
};
return View(test);
}
[HttpPost]
public IActionResult Index(Test test)
{
return Ok();
}
Result:
if you are looking to put id as value of your idxFormats then use this code in your checkbox:
<input type="checkbox" value=#item.Value name="chkFormat" id="#idxFormats" />
Edit:
I am not so familiar with c#, I tested with minimum code :
// Replace the model correct path by yours
#model IEnumerable<WebApplication1.Models.MyModels.ListOfFormats>
#{
int idxFormats = 0;
foreach (var item in Model)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="chkFormat" id="#idxFormats"/>
<label>#Html.Raw(#item.Name)</label>
</div>
idxFormats++;
}
}

How to solve empty model trouble using both Ajax.BeginForm and Html.BeginForm in MVC

I am new to MVC and stuck in passing modal to controller.
I have read many similar threads in SO, to no avail.
Here, I have a view for entering order details.
User will enter order item details (using ajax.BeginForm) and when he clicks save, whole order will be saved in backend (using Html.BeginForm). Ajax.BeginForm is working properly and passing + displaying records properly. But Html.BeginForm is passing model as nothing.
Here is my code ...
My Models
public class OrderItemsModel
{
public string SrNo { get; set; }
public int? ItemCode { get; set; }
public string ItemName { get; set; }
public Decimal? Qty { get; set; }
public Decimal? Rate { get; set; }
public Decimal? Amount { get; set; }
}
public class OrderModel
{
public string OrderNumber { get; set; }
public string OrderDate { get; set; }
public int? CustomerCode { get; set; }
public string CustomerName { get; set; }
public string Note { get; set; }
//List of items selected in Order
public List<OrderItemsModel> ItemsSelected { get; set; }
}
Extract from My View
#model OrderApplication.Models.OrderModel
#{
ViewBag.Title = "Index";
Model.ItemsSelected = ViewBag.getlist;
}
#using (Ajax.BeginForm("UpdateItemList", "Order", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "selectedtable" }))
{
<h2 style="margin-left:5%;">Order Entry</h2>
//Order No & Date
<div class="row">
<div class="col-sm-6">
<div class="col-sm-3">
#Html.LabelFor(model => model.OrderNumber, "OrderNo"):
</div>
<div class="col-sm-3">
#Html.TextBoxFor(model => model.OrderNumber, new { #class = "form-control", #readonly = "readonly" })
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-3">
#Html.LabelFor(model => model.OrderDate, "Date"):
</div>
<div class="col-sm-3">
#Html.TextBoxFor(model => model.OrderDate, new { #class = "form-control" })
</div>
</div>
</div>
<br />
//Table of entries
<div id="selectedtable">
#Html.Partial("_selectTable", Model);
</div>
<br />
}
#*Main Save*#
<div class="row">
<div class="col-sm-12">
<div class="col-sm-3">
#using (Html.BeginForm("SaveData", "Order", new { order = Model, id = "loginform", #class = "justify-content-center" }))
{
<input type="submit" value="Save Order" class="btn btn-success" />
}
</div>
<div class="col-sm-3">
<input type="button" class="btn btn-success" value="Clear Form" onclick="location.href='#Url.Action("Clear", "Order")'" />
</div>
</div>
</div>
My Controller
public class OrderController : Controller
{
public List<OrderItemsModel> dd = new List<OrderItemsModel>() ;
[HttpPost]
public ActionResult SaveData(OrderModel order, string id)
{
if (order == null) //order is always Nothing
{
return View(order);
}
if (order.CustomerCode == 0)
{
return View(order);
}
return View(order);
}
}
}
You shouldn't use both Ajax.BeginForm and Html.BeginForm, as it won't work. Please, check this post as might be of help to decide which one you wish to choose:
https://forums.asp.net/t/1757936.aspx?When+to+use+Html+BeginForm+vs+ajax+BeginForm
If you still want to use Html.BeginForm, just move the using sentence to replace your Ajax.BeginForm at the top of the page, so the form covers all fields, and the model won't be empty.

How to represent a Question/Answer page inside my asp.net MVC core web application

I have the following 3 models, which represents a submission of questions/answers:-
public partial class Submission
{
public Submission()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Independent { get; set; }
public string Comment { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestion
{
public SubmissionQuestion()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string Question { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestionSubmission
{
public int SubmissionQuestionId { get; set; }
public int SubmissionId { get; set; }
public string Answer { get; set; }
public virtual Submission Submission { get; set; }
public virtual SubmissionQuestion SubmissionQuestion { get; set; }
}
now i want to build a view which will show the submission firstname,lastname & comments + all the questions and for each question to show the answer fields as a free text for the user to enter it. to be honest i am not sure how i need to build the view and receive it inside the action method? any help?
It seems you want to display the data of specified submission's firstname,lastname,comments,the related questions.And with each question,you could enter an answer.Then pass the filled data to the action.
Here is a simple demo like below:
Model:
public class ViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Comment { get; set; }
public List<string> Question { get; set; }
public List<string> Answer { get; set; }
}
public partial class Submission
{
public Submission()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Independent { get; set; }
public string Comment { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestion
{
public SubmissionQuestion()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string Question { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestionSubmission
{
public int SubmissionQuestionId { get; set; }
public int SubmissionId { get; set; }
public string Answer { get; set; }
public virtual Submission Submission { get; set; }
public virtual SubmissionQuestion SubmissionQuestion { get; set; }
}
View(If you want to edit the firstname,lastname..you could remove the readonly):
#model ViewModel
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" readonly />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control" readonly />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Comment" class="control-label"></label>
<input asp-for="Comment" class="form-control" readonly />
<span asp-validation-for="Comment" class="text-danger"></span>
</div>
#for (var i = 0; i < Model.Question.Count(); i++)
{
<label>#Model.Question[i]</label><br />
<input asp-for="#Model.Question[i]" hidden />
<input asp-for="#Model.Answer[i]" />
<br />
}
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Controller:
public async Task<IActionResult> Create()
{
//specified one submissions' data and the related questions
var model = await _context.Submission.Include(s => s.SubmissionQuestionSubmission)
.ThenInclude(s => s.SubmissionQuestion).Select(s => new ViewModel()
{
FirstName = s.FirstName,
LastName = s.LastName,
Comment = s.Comment,
Question = s.SubmissionQuestionSubmission.Where(s => s.SubmissionId == 1).Select(s => s.SubmissionQuestion.Question).ToList(),
}).FirstOrDefaultAsync();
return View(model);
}
[HttpPost]
public async Task<IActionResult> Create(ViewModel submission)
{
//do your stuff...
return View();
}
Result: