Session problem.Why "Continue shopping" does not work? - asp.net-core

I have this view with some product list. List from different table
<form method="get">
<td class="button13"><button type="submit" asp-action="Buy" asp-route-id="#p.ProductId" asp-controller="Search">Buy</button></td>
<input type="hidden" name="returnUrl" value="#ViewContext.HttpContext.Request.PathAndQuery()" />
</form>
Then we go to form post to add some information about client. And then we will go to cart
Controller
public ViewResult Index(string returnUrl)
{
return View(new CartIndexViewModel
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
public ActionResult AddToCart(string returnUrl,int priceCart,DateTime dateFromCart, int Tick,int Fli)
{//we are here after form post
Cart cart = GetCart();
cart.AddItem(1,priceCart,dateFromCart);
SaveCart(cart);
return RedirectToAction("Index", new { returnUrl });
}
private Cart GetCart()
{
Cart cart = HttpContext.Session.GetJson<Cart>("Cart") ?? new Cart();
return cart;
}
private void SaveCart(Cart cart)
{
HttpContext.Session.SetJson("Cart", cart);
}
Second View
#model Phone1.Models.ViewModels.CartIndexViewModel;
<h2>Your cart</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Quantity</th>
<th>Item</th>
<th class="text-right">Price</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
#foreach (var line in Model.Cart.Lines)
{
<tr>
<td class="text-center">#line.Quantity</td>
<td class="text-left">#line.PriceCart</td>
<td class="text-left">#line.DateFromCart.ToString("D")"</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right">Total:</td>
<td class="text-right">
#Model.Cart.ComputeTotalValue().ToString("c")
</td>
</tr>
</tfoot>
</table>
<div class="text-center">
<a class="btn btn-primary" href="#Model.ReturnUrl"><h3>Continue shopping</h3></a>
</div>
And Infrastructure files
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace Phone1.Infrastructure
{
public static class SessionExtensions
{
public static void SetJson(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetJson<T>(this ISession session, string key)
{
var sessionData = session.GetString(key);
return sessionData == null
? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
}
}
}
And other Infrasructure`s file
using Microsoft.AspNetCore.Http;
namespace Phone1.Infrastructure
{
public static class UrlExtensions
{
public static string PathAndQuery(this HttpRequest request) =>
request.QueryString.HasValue
? $"{request.Path}{request.QueryString}"
: request.Path.ToString();
}
}
Startup
public class Startup
{
public Startup(IConfiguration configuration) =>
Configuration = configuration;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PhoneAppDbContext>(options =>
options.UseSqlServer(Configuration["Data:PhoneAppDb:ConnectionString"]));
services.AddMvc();
services.AddMemoryCache();
services.AddSession();
services.AddControllersWithViews(mvcOtions =>
{
mvcOtions.EnableEndpointRouting = false;
});
services.AddMvc()
.AddRazorRuntimeCompilation();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "",
template: "{controller=SearchTicket}/{action=AddToCart}/{id?}");
routes.MapRoute(
name: "",
template: "{controller=SearchTicket}/{action=Index}/{id?}");
});
}
}
}
Model 1
namespace Phone1.Models.ViewModels
{
public class CartIndexViewModel
{
public Cart Cart { get; set; }
public string ReturnUrl { get; set; }
}
}
Model 2
using System;
using System.Collections.Generic;
using System.Linq;
namespace Phone1.Models
{
public class Cart
{
private List<CartLine> lineCollection = new List<CartLine>();
public virtual void AddItem(int quantity,int priceCart,DateTime dateFromCart)
{
CartLine line = lineCollection
.FirstOrDefault();
if (line == null)
{
lineCollection.Add(new CartLine
{
DateFromCart=dateFromCart,
PriceCart=priceCart,
Quantity = quantity
});
}
else
{
//line.Quantity += quantity;
}
}
public virtual void RemoveLine(int priceCart,DateTime dateFromCart) =>
lineCollection.RemoveAll();
public virtual int ComputeTotalValue() =>
lineCollection.Sum(e => e.PriceCart);
//* e.Quantity
public virtual void Clear() => lineCollection.Clear();
public virtual IEnumerable<CartLine> Lines => lineCollection;
}
public class CartLine
{
public int CartLineId { get; set; }
public DateTime DateFromCart { get; set; }
public int PriceCart { get; set; }
public int Quantity { get; set; }
}
}
All things add to cart, but <a class="btn btn-primary" href="#Model.ReturnUrl"><h3>Continue shopping</h3></a> does not work at all.It does not work even like link <a>.What is wrong?
There is no error message.
Controller
public ViewResult Index(string returnUrl)
{
return View(new CartIndexViewModel
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
public ActionResult AddToCart(string returnUrl,int priceCart,DateTime dateFromCart, int Tick,int Fli)
{//we are here after form post
Cart cart = GetCart();
cart.AddItem(1,priceCart,dateFromCart);
SaveCart(cart);
return RedirectToAction("Index", new { returnUrl });
}
We go to Index method with returnUrl

Related

Get data from Ajax in ASP.NET Core not working?

I'm new at ASP.NET Core, and this is how I get data from Ajax.
I have a View Model like this
public class RequestSearchDefaultModel
{
public string FromToDate { get; set; }
public int Status { get; set; }
public List<SelectListItem> StatusType { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public IEnumerable<RequestViewModel> requestViewModel { get; set; }
}
When I search the form, I use Ajax to get the data
function OpenSearch() {
var stt = $('#StatusDropDown').val();
var daterange = $('#daterange').val();
var url = "#Url.Action("Search","RequestApproval")";
var model = { FromToDate: daterange, Status: stt };
$.ajax({
type: "POST",
data: JSON.stringify(model),
url: url,
contentType: "application/json",
}).done(function (res) {
console.log("here");
$('#myTable').html(res);
})
}
This is controller
[HttpPost]
public async Task<IActionResult> Search([FromBody] RequestSearchDefaultModel m)
{
m.FromDate = DateTime.Parse(m.FromToDate.Substring(0, 10)).Add(new TimeSpan(00, 0, 0));
m.ToDate = DateTime.Parse(m.FromToDate.Substring(14)).Add(new TimeSpan(23, 59, 59));
var request = _headerService.Search();
m.requestViewModel = _mapper.Map<IEnumerable<RequestViewModel>>(request);
return PartialView("_RequestBody", m);
}
This is the view
<div class="card-body">
<div class="table-responsive" id="myTable">
#Html.Partial("_RequestBody")
</div>
</div>
And this is the partial view
#model RequestSearchDefaultModel
<table class="table table-striped">
<thead>
<tr>
<th>Seq.</th>
<th>Title</th>
<th>Status</th>
<th>Draft Date</th>
<th>Final Approval Date</th>
</tr>
</thead>
<tbody id="RequestBody">
#if (Model.requestViewModel == null)
{
}
else
{
foreach (var item in Model.requestViewModel)
{
<tr>
<td>#item.ID</td>
<td>#item.DocumentNo</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ID">#item.Title</a>
</td>
<td>#item.DraftDate</td>
</tr>
}
}
</tbody>
</table>
But I can't get the data, I don't know where I wrong, so please help. Thanks in advance.

Click event not working in Blazor while using JQuery Datatable

I have initialized Datatable in OnAfterRenderAsync and it's working fine
but onclick event doesn't work.
Grid.razor
<tbody>
#foreach (RecommendedActivityCreateViewModel model in activityList)
{
<tr>
<td><img src="#model.image_url" width="100" /></td>
<td>#model.title</td>
<td>#model.description</td>
<td>#model.created_at.ToString("dd-MMM-yyyy")</td>
<td nowrap="nowrap">
<button #onclick="(()=>EditData(model.Id))" data-toggle="modal" data-target="#AddEditEmpModal" class="btn btn-sm btn-clean btn-icon" title="Edit details">
<i class="la la-edit"></i>
</button>
<a class="btn btn-sm btn-clean btn-icon delete-link" data-url="api/RecommendedActivity/" data-id="#model.Id" title="Delete">
<i class="la la-trash"></i>
</a>
</td>
</tr>
}
</tbody>
GridModel.cs
public class GridModel : ComponentBase
{
[Inject]
protected HttpClient Http { get; set; }
protected async Task EditData(string id)
{
await Http.GetAsync($"api/RecommendedActivity/{id}");
}
}
While you say "I have initialized Datatable in OnAfterRenderAsync" the example below does that and if you copy, paste and run it you'll find nothing gets rendered. You've fetched the data after you've rendered the page. Get the data in OnInitializedAsync and it works.
You also say "and it's working fine but onclick event doesn't work." The EditData method should be in Grid.razor not GridModel which is where it appears to be in the code snippets provided.
The code below shows a simple working example (with GetData in OnInitializedAsync).
#page "/Test"
#foreach (var country in Countries)
{
<div>#country.Country <button class="btn-btn-dark" #onclick="() => OnClick(country.Id)">Edit</button></div>
}
#code {
class Model
{
public int Id { get; set; }
public string Country { get; set; }
}
private List<Model> Countries = new List<Model>();
protected Task OnClick(int id)
{
var x = id;
return Task.CompletedTask;
}
protected override Task OnInitializedAsync()
{
// GetData();
return base.OnInitializedAsync();
}
protected override Task OnAfterRenderAsync(bool firstRender)
{
GetData();
return base.OnAfterRenderAsync(firstRender);
}
protected void GetData()
{
Countries = new List<Model>()
{
new Model(){ Id=1, Country = "UK"},
new Model(){ Id=2, Country = "Spain"},
new Model(){ Id=3, Country = "Portugal"}
};
}
}

Link in partial Razor Page fires wrong OnGet

I am using a razor page to display an ItemT model and at the bottom I inserted a partial view to show all properties (which are not assigned to this model in a n:m relation).
The PageModel 'FreePropertiesToItemT' has two public properties:
public ItemT ItemT { get; set; } // the one Item to show
public IList<PropertyIndexViewModel> FreeProperties { get; set; } // all free properties
An OnGetAsync(int? id) Method is called which works fine. The Page shows all data correctly.
The view displays a link for every Property:
<a asp-page-handler="addProperty" asp-route-id="#item.PropertyID">add</a>
This creates the link:
add
This is the correct link (I think). The route, id value and the handler are correct because there is a second OnGet Method in the PageModel:
public async Task<IActionResult> OnGetaddPropertyAsync(int? id)
However, the link only calls OnGetAsync (and not OnGetaddProppertyAsync) every time and, of course, for every Property!
What am I missing?
Model of ItemT:
public class ItemT
{
[Key]
public int ItemTID { get; set; }
[Required]
[StringLength(100, MinimumLength = 1)]
[Display(Name = "ItemT")]
public string Title { get; set; }
public bool isActive { get; set; } = true;
public virtual ICollection<ItemTProperty> ItemTProperties { get; set; }
}
ViewModel of free properties:
public class PropertyIndexViewModel
{
[Key]
public int PropertyID { get; set; }
[Required]
[StringLength(100, MinimumLength = 1)]
public string Title { get; set; }
public bool DefaultsOnly { get; set; }
[Display(Name = "Unit")]
public string Unit { get; set; }
[Display(Name = "Valuetype")]
public string Valuetype { get; set; }
}
The Page to list one ItemT:
#page
#model Inventory.Areas.Inventory.Pages.ItemTs.FreePropertiesToItemTModel
#{
ViewData["Title"] = "FreePropertiesToItemT";
}
<h1>Free Properties</h1>
<div>
<h4>ItemT</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.ItemT.Title)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.ItemT.Title)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.ItemT.isActive)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.ItemT.isActive)
</dd>
</dl>
</div>
<div>
<a asp-page="./Edit" asp-route-id="#Model.ItemT.ItemTID">Edit</a> |
<a asp-page="./Index">Back to List</a>
</div>
<p></p>
<div>
#{
ViewData["FreeProperties"] = true;
}
<partial name="../Properties/_Properties.cshtml" model="Model.FreeProperties" />
</div>
The Partial which is loaded:
#using Inventory.DAL.ViewModels
#model IList<PropertyIndexViewModel>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model[0].Title)
</th>
<th>
#Html.DisplayNameFor(model => model[0].DefaultsOnly)
</th>
<th>
#Html.DisplayNameFor(model => model[0].Unit)
</th>
<th>
#Html.DisplayNameFor(model => model[0].Valuetype)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.DefaultsOnly)
</td>
<td>
#Html.DisplayFor(modelItem => item.Unit)
</td>
<td>
#Html.DisplayFor(modelItem => item.Valuetype)
</td>
<td>
#if (ViewBag.FreeProperties != null)
{
<a asp-page-handler="addProperty" asp-route-id="#item.PropertyID">add</a>
}
</td>
</tr>
}
</tbody>
</table>
And the c# code behind the page:
namespace Inventory.Areas.Inventory.Pages.ItemTs
{
public class FreePropertiesToItemTModel : PageModel
{
private readonly IUnitOfWork _uow;
public FreePropertiesToItemTModel(IUnitOfWork uow)
{
_uow = uow;
}
public ItemT ItemT { get; set; }
public IList<PropertyIndexViewModel> FreeProperties { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
ItemT = await _uow.ItemTRepo.getById((int)id);
if (ItemT == null)
{
return NotFound();
}
FreeProperties = await _uow.PropertyRepo.getFreePropertiesForItemT((int)id);
return Page();
}
public async Task<IActionResult> OnGetaddPropertyAsync(int? id)
{
if( id == null)
{
return NotFound();
}
if(ItemT == null) { return NotFound(); }
await _uow.ItemTRepo.addProperty(ItemT.ItemTID, (int)id);
await _uow.Commit();
return Page();
}
}
}
The issue is that your handler name error ,change it like below:
public async Task<IActionResult> OnGetAddPropertyAsync(int? id)
The first letter of handler name must be capitalized , otherwise handler=addProperty in the url is treated as a query-string parameter not a handler name.

How to combine two entities in one view?

I need to display the records of the student which is the Student Attempts.
It should look something like this.
https://www.dropbox.com/s/pmazbug2j8xwehe/Example.PNG (Click for image)
But this is the Question page which shows all the correct answers. For the Student Attempts page should be exactly like that only the answers/options are replaced by the answers they attempted so when it is correct, the word will be in green and the wrong ones will be in red.
For this to happen I have to retrieve 2 data from two different entities.
Below is the IQuestion table and QuestionContent is the attribute that holds the model answers and the StudentAttempts table and Answer is the attribute that holds the answers attempted by the students.
https://www.dropbox.com/s/f92f8zvk9qn1n8p/DB%20Tables.PNG (Click for image)
How do I combine those two attributes to display in a view?
StudentAttemptsController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using iStellarMobile.Models;
namespace iStellarMobile.Controllers
{
public class StudentAttemptsController : Controller
{
private istellarEntities db = new istellarEntities();
//
// GET: /StudentAttempts/
public ActionResult Index(int id)
{
var studentattempts = db.StudentAttempts.Include(s => s.activity).Include(s => s.task).Include(s => s.UserInfo).Where(s => s.StudentID == id);
return View(studentattempts.ToList());
}
//
// GET: /StudentAttempts/Details/5
public ActionResult Details(int id = 0)
{
StudentAttempt studentattempt = db.StudentAttempts.Find(id);
if (studentattempt == null)
{
return HttpNotFound();
}
return View(studentattempt);
}
//
// GET: /StudentAttempts/Create
public ActionResult Create()
{
ViewBag.ActivityID = new SelectList(db.activities, "ActivityID", "ActivityName");
ViewBag.TaskID = new SelectList(db.tasks, "TaskID", "TaskName");
ViewBag.StudentID = new SelectList(db.UserInfoes, "ID", "UserName");
return View();
}
//
// POST: /StudentAttempts/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(StudentAttempt studentattempt)
{
if (ModelState.IsValid)
{
db.StudentAttempts.Add(studentattempt);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ActivityID = new SelectList(db.activities, "ActivityID", "ActivityName", studentattempt.ActivityID);
ViewBag.TaskID = new SelectList(db.tasks, "TaskID", "TaskName", studentattempt.TaskID);
ViewBag.StudentID = new SelectList(db.UserInfoes, "ID", "UserName", studentattempt.StudentID);
return View(studentattempt);
}
//
// GET: /StudentAttempts/Edit/5
public ActionResult Edit(int id = 0)
{
StudentAttempt studentattempt = db.StudentAttempts.Find(id);
if (studentattempt == null)
{
return HttpNotFound();
}
ViewBag.ActivityID = new SelectList(db.activities, "ActivityID", "ActivityName", studentattempt.ActivityID);
ViewBag.TaskID = new SelectList(db.tasks, "TaskID", "TaskName", studentattempt.TaskID);
ViewBag.StudentID = new SelectList(db.UserInfoes, "ID", "UserName", studentattempt.StudentID);
return View(studentattempt);
}
//
// POST: /StudentAttempts/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(StudentAttempt studentattempt)
{
if (ModelState.IsValid)
{
db.Entry(studentattempt).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ActivityID = new SelectList(db.activities, "ActivityID", "ActivityName", studentattempt.ActivityID);
ViewBag.TaskID = new SelectList(db.tasks, "TaskID", "TaskName", studentattempt.TaskID);
ViewBag.StudentID = new SelectList(db.UserInfoes, "ID", "UserName", studentattempt.StudentID);
return View(studentattempt);
}
//
// GET: /StudentAttempts/Delete/5
public ActionResult Delete(int id = 0)
{
StudentAttempt studentattempt = db.StudentAttempts.Find(id);
if (studentattempt == null)
{
return HttpNotFound();
}
return View(studentattempt);
}
//
// POST: /StudentAttempts/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
StudentAttempt studentattempt = db.StudentAttempts.Find(id);
db.StudentAttempts.Remove(studentattempt);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
IQuestion.cs (Models)
namespace iStellarMobile.Models
{
using System;
using System.Collections.Generic;
public partial class IQuestion
{
public int ID { get; set; }
public Nullable<int> ActivityID { get; set; }
public Nullable<int> TaskID { get; set; }
public Nullable<int> CategoriesID { get; set; }
public Nullable<bool> Sentence { get; set; }
public string QuestionContent { get; set; }
public string ImageURL { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedOn { get; set; }
public string UpdateBy { get; set; }
public Nullable<System.DateTime> UpdateOn { get; set; }
public Nullable<int> SchoolID { get; set; }
public Nullable<int> DLevel { get; set; }
public Nullable<int> TagID { get; set; }
public virtual ActivityTask ActivityTask { get; set; }
public virtual Category Category { get; set; }
public virtual School School { get; set; }
public virtual Tag Tag { get; set; }
}
}
StudentAttempts.cs (Models)
namespace iStellarMobile.Models
{
using System;
using System.Collections.Generic;
public partial class StudentAttempt
{
public int ID { get; set; }
public Nullable<int> ActivityID { get; set; }
public Nullable<int> TaskID { get; set; }
public Nullable<int> StudentID { get; set; }
public string Answer { get; set; }
public string Score { get; set; }
public Nullable<int> Attempts { get; set; }
public string AttemptDate { get; set; }
public string CorrectAnswer { get; set; }
public virtual activity activity { get; set; }
public virtual task task { get; set; }
public virtual UserInfo UserInfo { get; set; }
}
}
Details.cshtml (StudentAttempts view)
<fieldset>
<legend>Classes</legend>
<div class="editor-label">
<h2> #Html.LabelFor(model => model.activity.ActivityName) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.activity.ActivityName)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.task.TaskName) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.task.TaskName)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.UserInfo.UserName) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.UserInfo.UserName)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.Answer) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Answer)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.Score) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Score)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.Attempts) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.Attempts)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.AttemptDate) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.AttemptDate)
</div>
<br />
<div class="editor-label">
<h2> #Html.LabelFor(model => model.CorrectAnswer) </h2>
</div>
<div class="display-field">
#Html.DisplayFor(model => model.CorrectAnswer)
</div>
</fieldset>
<br />
<p>
#Html.ActionLink("Edit", "/Edit/2",null, new { id=Model.ID, #class="classname" })
<span> </span>
#Html.ActionLink("Back", "/Index", null, new { #class="classname" })
</p>
You could just make a new class type (something like "StudentAttempsVM") that has a property for each of the classes you need (Details and Attempts). Then consolidate your Controller methods to build this object and pass it to your view.

Saving multiple records on submit click into differnt entities in MVC4. Not getting values from view in Controller

I am trying to save the class attendance for multiple students on click of submit button. I am able to create the blank records in the concern tables and then populate the data in view.
I have the following view model:
public class TeacherAttendanceModel
{
#region Required Properties
public long ScholarAttendanceId { get; set; }
public string Student { get; set; }
public bool Absent { get; set; }
public string AbsentComment { get; set; }
public bool Uniform { get; set; }
public bool Homework { get; set; }
public string HomeworkComment { get; set; }
public String UniformCommentSelected { get; set; }
public IEnumerable<String> UniformComment { get; set; }
#endregion
}
My Controller is as below.
public class TeacherAttendanceController : Controller
{
//
// GET: /TeacherAttendance/
public ActionResult Index()
{
long classId = Success.Business.Roles.Teacher.GetHomeRoomClassID(Convert.ToInt64(Session[GlobalVar.LOGGED_IN_ID]));
var classAttendanceStatus = Success.Business.Entities.ClassAttendance.GetClassAttendanceStatus(classId);
ViewBag.status = classAttendanceStatus;
var attendanceData = TeacherAttendance.CreateClassAttendance(classId);
return View(attendanceData);
}
[HttpPost]
public ActionResult Index(IEnumerable<TeacherAttendanceModel> teacherAttendanceModel)
{
try
{
if (ModelState.IsValid)
{
TeacherAttendance.SaveAttendance(teacherAttendanceModel);
}
}
catch (Exception e)
{
}
return View(teacherAttendanceModel);
}
}
Get Index is working fine. But I am not getting the TeacheAttendanceModel object in Post index. I get null object. I would be thank full to get any help in this regards. How to update the multiple records of attendance on submit click?
I am using the following View:
#foreach (var item in Model) {
<tr >
<td style="border-style:solid; border-color:darkslategray; border-width:thin;">
#Html.DisplayFor(modelItem => item.Student)
</td>
<td style="border-style:solid; border-color:darkslategray; border-width:thin;">
#Html.CheckBoxFor(modelItem => item.Absent, ViewBag.status == 2 ? new {disabled = "disabled"} : null)
#Html.TextBoxFor(modelItem => item.AbsentComment, ViewBag.status == 2 ? new {disabled = "disabled"} : null)
</td>
<td style="border-style:solid; border-color:darkslategray; border-width:thin;">
#Html.CheckBoxFor(modelItem => item.Uniform, ViewBag.status == 2 ? new {disabled = "disabled"} : null)
#Html.DropDownListFor(modelItem => item.UniformCommentSelected, new SelectList(item.UniformComment),item.UniformCommentSelected ?? "---Select---", ViewBag.status == 2? new {disabled = "disabled"} : null)
</td>
<td style="border-style:solid; border-color:darkslategray; border-width:thin;">
#Html.CheckBoxFor(modelItem => item.Homework, ViewBag.status == 2 ? new {disabled = "disabled"} : null)
#Html.TextBoxFor(modelItem => item.HomeworkComment, ViewBag.status == 2? new {disabled = "disabled"} : null)
</td>
</tr>
}
Model:
public class Test
{
public List<string> UniformComment { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new Test
{
UniformComment = new List<string>{ "one", "two", "three" }
};
return View(model);
}
[HttpPost]
public ActionResult Index(Test model)
{
return View(model);
}
View:
#using (Html.BeginForm())
{
for (var i = 0; i < Model.UniformComment.Count; i++)
{
#Html.TextBoxFor(x => Model.UniformComment[i])
}
<input type="submit" value="Save" />
}
Rendered html example:
<input id="UniformComment_0_" name="UniformComment[0]" type="text" value="one" />
<input id="UniformComment_1_" name="UniformComment[1]" type="text" value="two" />
<input id="UniformComment_2_" name="UniformComment[2]" type="text" value="three" />
The idea is iterate with for loop or create EditorTemplate and then you receive indexed items.
Added (Feel the difference):
View:
#using (Html.BeginForm())
{
foreach (var comment in Model.UniformComment)
{
#Html.TextBoxFor(x => comment)
}
<input type="submit" value="Save" />
}
Rendered html:
<input id="comment" name="comment" type="text" value="one" />
<input id="comment" name="comment" type="text" value="two" />
<input id="comment" name="comment" type="text" value="three" />
Use a IList instead of IEnumerable in the view and replace the foreach loop with a for loop.
Step 1:
Use
#model IList<TeacherAttendanceModel>
instead of
#model IEnumerable<TeacherAttendanceModel>
Step 2:
Use
#for (var i = 0; i < Model.Count; i++)
instead of
#foreach (var item in Model)
Refer How to pass IEnumerable list to controller in MVC including checkbox state? for more details.