asp.net core - form values return null - asp.net

Passing department and title models for use data in selectbox and passing employee model for save data from user. tring to pass values from partial view but in controller values return null.
partial view:
#model (List<Department> Departments, List<Title> Titles, Employee e)
<form class="g-3" asp-action="CreateEmployee" asp-controller="Employees" method="post">
<div class="row">
<div class="col-lg-6">
<div class="mb-3">
<label for="Name" class="form-label">İsim</label>
<input asp-for="e.Name" type="text" class="form-control" id="Name">
<div class="invalid-feedback">
İsim alanı boş bırakılamaz.
</div>
</div>
</div>
</div>
<button type="submit">Tek Form</button>
</form>
controller:
public IActionResult CreateEmployee()
{
HR_ManagementContext context = new HR_ManagementContext();
var departments = context.Departments.ToList();
var titles = context.Titles.ToList();
var models = (departments, titles, new Employee());
return View(models);
}
[HttpPost]
public IActionResult CreateEmployee(Employee employee)
{
return RedirectToAction("CreateEmployee");
}

Set the name attribute in the input tag:
<input asp-for="e.Name" type="text" class="form-control" id="Name", name="employee.Name">
The second solution is to use model name item3 generated by the MVC:
[HttpPost]
public IActionResult CreateEmployee(Employee item3)
{
return RedirectToAction("CreateEmployee");
}

Thx #Jackdaw his answer also working too.
I found an alternative
in Controller you can bind model:
public IActionResult CreateEmployee([Bind(Prefix = "Item3")]Employee employee)
{
return RedirectToAction("CreateEmployee");
}
Item3 is the prefix of tuple model.
#model (List<Department> Departments, List<Title> Titles, Employee e)
Department = Item1
Titles = Item2
Employee = Item3

Related

Select dropdown list doesn't save selected option - asp.net core web app

I'm trying to save data on a table but for some reason the Select element of Html always saves the first DateTime option item instead of saving the one I selected.
Here I select the option corresponding to the date highlighted but when I save the information the first option (22-01-08) is the one that it´s saved on the database table
My View Model:
public class BookNowViewModel
{
public string FilmeName { get; set; }
public DateTime FilmeDate { get; set; }
public string seatNum { get; set; }
public int Price { get; set; }
public int FilmeId { get; set; }
}
My Controller where i set the functions do save the data retrieved from the view to the "Cart" table:
[HttpGet]
public IActionResult BookNow(int Id)
{
BookNowViewModel vm = new BookNowViewModel();
var item = _context.Filme.Where(a => a.Id == Id).FirstOrDefault();
var it = _context.Sessao.Where(n => n.FilmeId == Id).FirstOrDefault();
vm.FilmeName = item.Name;
vm.FilmeDate = it.Date;
vm.FilmeId = Id;
vm.Price = Convert.ToInt32(item.Price);
ViewBag.FilmeDate = _context.Sessao.Where(a => a.FilmeId == Id)
.Select(i => new SelectListItem
{
Value = i.Id.ToString(),
Text = i.Date.ToString()
}).ToList();
return View(vm);
}
[HttpPost]
public async Task<IActionResult> BookNow(BookNowViewModel vm,int Id)
{
List<Cart> carts = new List<Cart>();
string seatNum = vm.seatNum.ToString();
int filmeId = vm.FilmeId;
var filme = _context.Filme.Where(a => a.Id == Id).FirstOrDefault();
var sessao = _context.Sessao.Where(n => n.FilmeId == Id).FirstOrDefault();
string[] seatNumArray = seatNum.Split(",");
count = seatNumArray.Length;
if (checkSeat(seatNum, filmeId) == false)
{
foreach (var item in seatNumArray)
{
carts.Add(new Cart
{
Price = Convert.ToInt32(filme.Price),
MovieId = vm.FilmeId,
UserId = _userManager.GetUserId(HttpContext.User),
Date = sessao.Date,
seatNum = item
});;
}
foreach (var item in carts)
{
_context.Cart.Add(item);
await _context.SaveChangesAsync();
//_context.SaveChanges();
}
TempData["Sucess"] = "Seat Booked, See your Cart";
}
else
{
TempData["seatnummsg"] = "Please Change you seat number";
}
return RedirectToAction("Index");
}
My View :
div class="col-md-4">
<form asp-action="BookNow" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FilmeName" class="control-label"></label>
#Model.FilmeName
<span asp-validation-for="FilmeName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FilmeDate" class="control-label"></label>
<select name="ok" id="FilmeDate" asp-for="FilmeDate" class="form-control" asp-items="ViewBag.FilmeDate"></select>
</div>
<div class="form-group">
<label asp-for="seatNum" class="control-label"></label>
<input asp-for="seatNum" class="form-control" />
<span asp-validation-for="seatNum" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FilmeId" class="control-label"></label>
<input asp-for="FilmeId" class="form-control" />
<span asp-validation-for="FilmeId" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Add to Cart" class="btn btn-default btn-success text-white" />
</div>
</form>
I can see a couple of issues here.
The <select> element has the wrong name attribute. You can remove name="ok" (and the id) as the tag-helper asp-for will automatically set the name and id attributes. It should correctly bind to the FilmeDate property if you change it to:
<select asp-for="FilmeDate" class="form-control" asp-items="ViewBag.FilmeDate"></select>
You're populating the ViewBag with dates, but you're assigning the value to the Id not the Date. Use the date in the value field too:
...
.Select(i => new SelectListItem
{
Value = i.Date.ToString(),
Text = i.Date.ToString()
}
However, another problem is that you're not using the value from the viewmodel when saving to the database. It looks like you're saving a value which you just read from the database: Date = sessao.Date. You should use the value from the ViewModel: Date = vm.FilmeDate.
...
// only 1 for loop required
foreach (var item in seatNumArray)
{
var cart = new Cart
{
Price = Convert.ToInt32(filme.Price),
MovieId = vm.FilmeId,
UserId = _userManager.GetUserId(HttpContext.User),
Date = vm.FilmeDate, // use the value selected the viewmodel
seatNum = item
};
_context.Cart.Add(cart);
}
// save changes after adding all items
await _context.SaveChangesAsync();
You only need a single loop and you can save changes after adding all items too. Since you're no longer using sessao in the Post method it can be removed.
Aside: if you're checking for seat availability for a particular film in checkSeat(seatNum, filmeId), you may also need to consider the film date too.

Model is null in view on foreach

I have added a list to my view model but when I access it in a foreach loop in the view it throws:
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_MyActivationCampaign_Campaign.ExecuteAsync() in Campaign.cshtml
+ foreach(var dp in Model.DpRestrictedList)
This is the list I have added:
public List<DpRestricted> DpRestrictedList { get; set; } = new List<DpRestricted>()
{
new DpRestricted(){DpId = 1, Name = "Post Restricted" },
new DpRestricted(){DpId = 2, Name = "Unrestricted" },
new DpRestricted(){DpId = 3, Name = "Customer Restricted" }
};
}
public class DpRestricted
{
public int DpId { get; set; }
public string Name { get; set; }
}
and I am trying to loop over it like this:
<div class="row">
<fieldset>
<legend>Delivery Methods</legend>
<div id="radio">
#*<input type="radio" id="new-method">
<label for="new-method">New Method</label>
<input type="radio" id="dm-101" checked="checked">
<label for="dm-101">DM_101</label>
<input type="radio" id="delivery-method-2">
<label for="delivery-method-2">Delivery Method 2</label>*#
#{
foreach(var dp in Model.DpRestrictedList)
{
#Html.RadioButtonFor(model => model.DeliveryPointRestrictionId, dp);
}
}
</div>
</fieldset>
</div>
Using statement and example:
#model WorkstreamX.Web.Core.ViewModels.ActivationCampaignViewModel
...
<div class="col-md-4">
<label for="headline">Campaign</label>
#Html.EditorFor(model => model.CampaignName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CampaignName)
</div>
The above is the using statement in the view and an example of how it is already being used elsewhere in it. When I check it is not just the list that is null but the Model in the loop statement is also null. Is it a case of me needing to new up the view model in the controller at this point? That is what I am about to try I just wanted to state this question and maybe find out why this is happening. Any advice here greatly appreciated.
[edit] How I fixed this issue:
I added an argument to my view:
before return View();
after return View(new ActivationCampaignViewModel());
I still don't quite understand the why of this as I appeared to have a model before. I am assuming that because I didn't call the constructor the list wasn't constructed and made it all fall over.
Your code should be like the below one.
Public ActionResult GetEmployee()
{
var employee = GetEmployee();
return View(employee);
}
#model IEnumerable<Appname.ViewModel.Employee>
#{
foreach(var data in Model) {}
}
How I fixed this issue:
I added an argument to my view:
before return View();
after return View(new ActivationCampaignViewModel());
I still don't quite understand the why of this as I appeared to have a model before. I am assuming that because I didn't call the constructor the list wasn't constructed and made it all fall over.

Pass parameter form MVC to Stimulsoft report

The View code is as follows:
#using Stimulsoft.Report.Mvc;
#using Stimulsoft.Report;
#{
ViewBag.Title = "ListPouyaProject";
Layout = "~/Views/Shared/_mainView.cshtml";
}
<section class="content">
<!-- Default box -->
<div class="box">
<div class="box-body">
<div class="form-group">
Start Date: <input type="text" id="date1" name="date1" onclick="PersianDatePicker.Show(this, '1392/03/22');" />
End Date : <input type="text" id="date2" name="date2" onclick="PersianDatePicker.Show(this, '1397/03/22');" />
</div>
<div class="form-group">
#Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
Actions =
{
GetReport = "Report4_ListPouyaProject",
ViewerEvent = "ViewerEvent"
}
})
</div>
</div>
</div>
</section>
The Controller code is as follows:
public ActionResult Report4_ListPouyaProject()
{
var report = new StiReport();
report.Load(Server.MapPath("~/Content/Reports/ListPouyaProject.mrt"));
return StiMvcViewer.GetReportResult(report);
}
public ActionResult ListPouyaProject()
{
return View();
}
public ActionResult ViewerEvent()
{
return StiMvcViewer.ViewerEventResult();
}
I want to pass the date1 and date2 variables to the controller from view.
To do this, we need to add the following commands to the contoroller :
report.CompiledReport.DataSources["spm_report_4_ListPouyaProject"].Parameters["StartDate"].ParameterValue = DateTime.Parse(date1);
report.CompiledReport.DataSources["spm_report_4_ListPouyaProject"].Parameters["EndDate"].ParameterValue = DateTime.Parse(date2);
How to pass the parameters date1 and date2 from view to controller?
First, you need to add the StiMvcViewer component to the view page. Also, you need to pass the StiMvcViewerOptions object to the constructor. The minimum required options are two actions - GetReport and ViewerEvent, they are located in the Actions options group.
#using Stimulsoft.Report.MVC;
#Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
Actions =
{
GetReport = "GetReport",
ViewerEvent = "ViewerEvent"
}
})
<div style="width: 150px;">
#Html.ActionLink("Simple List", "Index", new { id = "1" })
<br />Report Snapshot
</div>
and in controoller :
public ActionResult GetReport(int? id)
{
// Create the report object
StiReport report = new StiReport();
switch (id)
{
// Load report snapshot
case 1:
// Load report
// Load report snapshot
report.LoadDocument(Server.MapPath("~/Content/Reports/SimpleList.mdc"));
break;
}
// Load data from XML file for report template
if (!report.IsDocument)
{
DataSet data = new DataSet("Demo");
data.ReadXml(Server.MapPath("~/Content/Data/Demo.xml"));
report.RegData(data);
}
return StiMvcViewer.GetReportResult(report);
}
public ActionResult ViewerEvent()
{
return StiMvcViewer.ViewerEventResult();
}

dropdownlistfor yields error ,{"Object reference not set to an instance of an object."} , when I click submit button

I am trying to create sub category for categories. User first select the categories from dropdownlist and then type the subcategory name and clicks submit. Even though dropdownlist elements are properly fill the dropdown list. When I click submit button It creates error. How can I solve this?
My View:
#model CETAPPSUGG.Models.CategorySubCategoryModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.selectedId, new { id = "3" });
// #Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SubCatagories</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SubCategory.SubCategoryName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SubCategory.SubCategoryName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SubCategory.SubCategoryName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
Upper cat: <div class="col-md-10">
#Html.DropDownListFor(Model => Model.Categories, Model.categoryList)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
My Controller:
public ActionResult Create()
{
var categories = db.Categories.ToList();
CategorySubCategoryModel deneme = new CategorySubCategoryModel();
var list = new List<SelectListItem>();
deneme.Categories = categories;
foreach (Categories c in categories)
{
list.Add(new SelectListItem() { Text = c.CategoryName, Value = c.Id.ToString() });
}
deneme.categoryList = list;
return View(deneme);
}
// POST: SubCatagories/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
// [ValidateAntiForgeryToken]
public ActionResult Create( CategorySubCategoryModel model)
{
string strDDLValue = model.selectedId;
SubCatagories newSubCategory = new SubCatagories();
Categories cat = new Categories();
cat = db.Categories.Find(Convert.ToInt32(strDDLValue));
// cat = db.Categories.Find(Convert.ToInt32(strDDLValue));
newSubCategory.SubCategoryName = model.SubCategory.SubCategoryName;
newSubCategory.UpperCategory = Convert.ToInt32(strDDLValue);
newSubCategory.Categories = cat;
db.SubCatagories.Add(newSubCategory);
db.SaveChanges();
return View();
}
My Model
namespace CETAPPSUGG.Models
{
public class CategorySubCategoryModel
{
SubCatagories SubCatagories { get; set; }
public IEnumerable<Categories> Categories { get; set; }
public IEnumerable<SubCatagories> SubCategories { get; set; }
public IEnumerable<SelectListItem> categoryList { get; set; }
public SubCatagories SubCategory { get; set; }
public string selectedId;
}
}
It creates error in view
You have a bunch of problems here.
Your primary problem is that you are not passing a model back to the View on post, thus the model is null. So, when you attempt to dereference items from the model in the View, a null reference is generated.
First, you are using selectedId but do not set this anywhere. It doesn't get set by magic. What you probably want is #Html.DropDownListFor(model => model.selectedId, Model.categoryList) (note the lowercase m in model in the first parameter, and uppercase M in the second)
Second, don't use a Model in your lambda in the DropDownListFor, use the lowercase model, because uppercase Model is reserved for the actual Model instance. If you want to reference the Model instance, then do something like DropDownListFor(_ => Model.Foo, Model.Foos). Note that I replaced the Model before the lambda with an underscore or some other value that is not Model. Frankly i'm surprised this even works, but there's probably a scoping rule here that overrides the outer Model. Avoid this because it can cause you confusion down the road.
Third, you are passing an IEnumerable to the DropDownListFor as the selected item variable, this won't work on a number of levels. This needs to be a single string value in most cases (sometimes a numerical one, but always a single more basic type that can have ToString() called on it and get a sensible string since DropDownListFor can't display complex objects).
Fourth, You also need to re-populate your DropDownListFor in the Post action, because the contents of a dropdownlist are not posted back, and thus will be null in the model. This, along with the SubCategory derefences in your view are ultimately what is generating the Null Reference exception.
You also need to pass the model back to your view in the Post, but as stated above, it needs to be re-initialized with the Categories as well as SubCategories.
There are probably more problems here, but fix these and you should be on your way.

How to show image from H2 database to Thymeleaf?

I'm doing spring boot, using H2 database, thymeleaf view.
I have a form to upload image to save into H2 database(byte[] image),
In thymeleaf, how to show image? anyone tell me the solution?
controller:
#RequestMapping(value = "user/new", method = RequestMethod.GET)
public String newBeans(Model model) {
model.addAttribute("usersss", new Beans());
return "userform";
}
#RequestMapping(value = "user", method = RequestMethod.POST)
public String saveUser(Beans beans) {
RepositoryUser.save(beans);
return "redirect:/users";
}
form:
<form>
<label>Avatar:</label>
<input type="file" th:field="${usersss.Avatar}"/>
<button type="submit">Submit</button>
</form>
shows:
<form>
<label>Avatar:</label>
<p>
?????????
</p>
</form>
Although there are many different ways to do this,here is some sample code which you can use for the same :
#RequestMapping(value = "/user/avatar/{userId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<InputStreamResource> downloadUserAvatarImage(#PathVariable Long userId) {
UserObject userAvatar = RepositoryUser.findUserAccountAvatarById(userId);//Could be a handle to a file stream as well,which could be incorporated accordingly
return ResponseEntity.ok()
.headers("Content-Disposition", "inline;filename=\""
+ userAvatar.getUserName() + "\"")
.contentLength(userAvatar.getImageBlob().getLength())
.contentType(MediaType.parseMediaType(userAvatar.getImageBlob().getContentType()))
.body(new InputStreamResource(userAvatar.getImageBlob().getBinaryStream()));
}
And then in your thymeleaf :
<form>
<label >Avatar :</label>
<p>
<img class="picture" th:src="#{'/user/avatar/'+${userId}}" />
</p>
</form>
Hope this helps.

Resources