Edit view not being populated with objects data - razor

I am quite new to ASP .Net, and could use some help... I have an ASP .Net Core 1.1 web app. In it, I have an "Edit" view for editing a simple object, which a corresponding controller calls when routed to it. This is the view:
#model InspectionsTestClient.Models.Property
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
#Html.ValidationSummary();
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Property</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="UnitNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="UnitNumber" class="form-control" />
<span asp-validation-for="UnitNumber" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="BuildingName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="BuildingName" class="form-control" />
<span asp-validation-for="BuildingName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Street" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Street" class="form-control" />
<span asp-validation-for="Street" class="text-danger"></span>
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
This is the controller which calls that view:
// GET: Property/Edit/5
public ActionResult Edit(int id)
{
return View();
}
And this is the model:
namespace InspectionsTestClient.Models
{
//[Table("property")]
public class Property
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int? Id { get; set; }
[MaxLength(10, ErrorMessage = "Unit number too long")]
[Display(Name = "Unit #")]
public string UnitNumber { get; set; }
[MaxLength(45, ErrorMessage = "BuildingName name too long")]
public string BuildingName { get; set; }
[MaxLength(45, ErrorMessage = "Street too long")]
public string Street { get; set; }
}
}
So when I navigate to that page, the controller fires up, and returns the Edit view. I have confirmed the parameter "id" is populated. When the Edit view loads in the browser, however, all the input textboxes are empty. I would expect them to be pre-populated with the values for the object in question. What am I missing?

The issue you are experiencing is happening because you are not returning that object to the view.. actually in your case you're not even going out to the db to get the object.
You need to edit you Edit action to something like this:
// GET: Property/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var object = db.TableName.Find(id);
// db = connectionstring
// TableName = database table that holds the object that you want to return
if (object == null)
{
return HttpNotFound();
}
return View(object);
}
Let me know if this helps

public class PropertyController
{
private readonly ApplicationDbContext _dbContext;
public PropertyController(ApplicationDbContext dbContext){
_dbContext = dbContext;
}
//GET: Property/Edit/5
public async Task<IActionResult> Edit(int id)
{
var property = await _dbContext.Property.FirstOrDefaultAsync(p => p.Id == id);
return View(property);
}
}
If you don't pull the data from the database and send it to the view of course it will always be blank. Edit(int id) there will be 2, both slightly different from the other.
[HttpPost]
[ValidateAntiForgeryToken]
//Post: Property/Edit/5
public async Task<IActionResult> Edit(int id, [Bind("Id", "UnitNumber", "BuildingNumber", "Street")] Property property)
{
if(ModelState.IsValid){
}
else{
}
}
not everyting is present but that is part of your adventure.

Related

i got this 'FormatException: Input string was not in a correct format.' in my view when take user token for reset password

i have no int or double or convert any thing to int or somthing like that .
i just want to reset the users password . and when i want to take user token , everythings in my actionmethod is good . but i have error on my view !!!!
my viewmodel :
[Display(Name ="email")]
[Required(ErrorMessage = "required ... !")]
[EmailAddress(ErrorMessage = "required .")]
[MinLength(10, ErrorMessage = "email invalid")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Display(Name = "new password")]
[Required(ErrorMessage = "required ... !")]
[DataType(DataType.Password)]
[MinLength(8, ErrorMessage = "invalid")]
[MaxLength(30,ErrorMessage ="invalid")]
public string Password { get; set; }
[Display(Name = "confirmpassword")]
[Required(ErrorMessage = "required")]
[DataType(DataType.Password)]
[MinLength(8, ErrorMessage = "invalid")]
[MaxLength(30, ErrorMessage = "invalid")]
[Compare("Password",ErrorMessage ="invalid")]
public string ConfirmPassword { get; set; }
public string Code { get; set; }
and this is my actionmethod :
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("ForgetPassword")]
public async Task<IActionResult> ForgetPasswordAsync(ForgetPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, "error ... !");
}
else
{
if(!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty, " check your email ");
}
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callBackURL = Url.Action("ResetPassword", "Account", values: new { code }, protocol: Request.Scheme);
await _emailSendr.SendEmailAsync(model.Email, "resetpassword", $"<p style='font-family:tahoma;font-size:14px;font-wight:900;'>click on that<a style='color:highlight;' href='{HtmlEncoder.Default.Encode(callBackURL)}' >click me !</a></p>");
return RedirectToAction("ForgetPasswordConfirmation");
}
}
return View(model);
}
[HttpGet]
public IActionResult ForgetPasswordConfirmation()
{
return View();
}
[HttpGet]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
return NotFound();
}
else
{
var model = new ResetPasswordViewModel { Code = code };
return View(model);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("ResetPassword")]
public async Task<IActionResult> ResetPasswordAsync(ResetPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, "not found ");
}
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation");
}
else
{
foreach(var item in result.Errors)
{
ModelState.AddModelError(string.Empty, item.Description);
}
}
}
and this is my html codes in view :
#model Platform.Models.ViewModels.ClientSideViewModels.ResetPasswordViewModel
#{
Layout = null;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie-edge" />
<title>somthing</title>
<link rel="stylesheet" href="~/css/styles.css" />
<link href="~/vendor/font-awesome/css/fontawesome-all.min.css" rel="stylesheet" />
<script src="~/lib/jquery/dist/jquery.min.js"></script>
</head>
<body>
<div class="page-wrapper flex-row align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card p-4">
<div class="card-header text-center text-uppercase h4 font-weight-light">
reset password
</div>
<hr />
<form asp-action="ResetPassword" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Code" type="hidden" />
<div class="card-body py-2">
<div class="form-group">
<label class="form-control-label" asp-for="Email"></label>
<input type="email" class="form-control" asp-for="Email" placeholder="email" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="form-control-label" asp-for="Password"></label>
<input type="password" class="form-control" asp-for="Password" placeholder="enter password" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label class="form-control-label" asp-for="ConfirmPassword"></label>
<input type="password" class="form-control" asp-for="ConfirmPassword" placeholder="password again" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-warning btn-block">change password</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
</body>
</html>
I do not know why this is happening, I really do not find any reason for it
I think you need to change your ResetPassword like this:
[HttpGet]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
return NotFound();
}
else
{
var model = new ResetPasswordViewModel
{
Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code))
};
return View(model);
}
}

Input type number strange behaviour

I'm building a fruit and vegetables e-commerce app. I have made a system for users to add items to cart by entering values in an <input type="number"> field, within a form.
The problem I'm having is that when I enter "1.2" for example, my server receives the value "12". But when I enter the value "1", my server just receives the value "1". This really bugs me. Does anyone know why this happens?
Thanks in advance.
Some data for context: my backend is build in Asp.Net Core 3.x. The backend endpoint looks like this:
[HttpPost]
public ActionResult UpdateShoppingCart(int productId, float amount)
{
Console.WriteLine(amount);
var selectedProduct = _productRepository.Products.SingleOrDefault(p => p.Id == productId);
float productCount = 0;
if(selectedProduct != null)
{
productCount = _shoppingCart.UpdateCart(selectedProduct, realAmount);
}
return Redirect(Request.Headers["Referer"].ToString());
}
The html part looks like this
<div class="text-center">
<div class="float-left">
<p>Cantidad:</p>
</div>
<div class="float-right">
<form method="post" class="form-inline" asp-controller="ShoppingCart" asp-action="UpdateShoppingCart">
<input type="hidden" name="productId" value="#Model.Product.Id"/>
<input name="amount" type="number" class="form-control h-auto input-add-to-cart" data-id="#Model.Product.Id" min=0 step="0.1" value="#(Model.ShoppingCartItem != null ? (Model.ShoppingCartItem.Amount).ToString(new CultureInfo("en-US")) : (0).ToString())"/>
<button type="submit" id="update-button-#Model.Product.Id" disabled class="ml-1 btn btn-sm btn-outline-warning"><i class="material-icons material-icons-actual-font" disabled>shopping_cart</i>Actualizar</button>
</form>
</div>
</div>
UPDATE:
The code for the ShoppingCartItem model is the following:
public class ShoppingCartItem
{
public int Id { get; set; }
public Product Product { get; set; }
public int ProductId { get; set; }
public float Amount { get; set; }
public string ShoppingCartId { get; set; }
}
SECOND UPDATE:
Could it be that i'm setting a culture in the thread that uses the comma as a dot?
In the Configure method of Startup, i'm setting
var cultureInfo = new CultureInfo("es-CL");
cultureInfo.NumberFormat.CurrencySymbol = "$";
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
Ok, that was it.
The problem was that my Browser was setting the decimal separator as a dot (for example, 4.7) and my backend was expecting a comma (for example, 4,7) so that confused my application.
The culprit was what was posted on my second update, that was
var cultureInfo = new CultureInfo("es-CL");
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;

View page return null pointer exception

when im trying to access the signUp, as i see in the debug, there is a problem when the code get to the view.
im getting run time exception "System.Web.Mvc.WebViewPage.Model.get returned null."
Please HELP
here is the full failure :
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Web.Mvc.WebViewPage.Model.get returned null.
happen here :
#{
ViewBag.Title = "SignUp";
}
SignUp.cshtml
<body>
<div class="signup-form">
<form class="signup-form" action="SignupSubmit">
<div class="col-md-8 order-md-1">
<h2>SignUp</h2>
<h3>Create an account</h3>
<h4 class="mb-3">Please complete your details : </h4>
<div class="row">
<div class="col-md-4 mb-3">
<label for="firstName">Id number</label>
<input type="text" class="form-control" name="userid" id="idnum" value="#Model.userid"> #Html.ValidationMessageFor(u => u.userid)
<div class="invalid-feedback">
Valid id number is required.
</div>
</div>
<div class="col-md-4 mb-3">
<label for="firstName">First name</label>
<input type="text" class="form-control" name="firstName" id="firstName" value="#Model.firstName"> #Html.ValidationMessageFor(u => u.firstName)
<div class="invalid-feedback">
Valid first name is required.
</div>
</div>
<div class="col-md-4 mb-3">
<label for="lastName">Last name</label>
<input type="text" class="form-control" name="lastName" id="lastName" value="#Model.lastName"> #Html.ValidationMessageFor(u => u.lastName)
<div class="invalid-feedback">
Valid last name is required.
</div>
</div>
</div>
<div class="mb-3">
<label for="email" class="col-sm-2 col-form-label">Email </label>
<input type="email" class="form-control" name="email" id="inputEmail" placeholder="you#example.com" value="#Model.email"> #Html.ValidationMessageFor(u => u.email)
<div class="invalid-feedback">
Please enter a valid email address for shipping updates.
</div>
</div>
<div class="mb-3">
<label for="inputPassword" class="col-sm-2 col-form-label">Password</label>
<input type="password" class="form-control" name="password" id="inputPassword" placeholder="Password" value="#Model.password"> #Html.ValidationMessageFor(u => u.password)
<div class="invalid-feedback">
Please enter a valid password with numbers and letters.
</div>
</div>
<label class="checkbox-inline"><input type="checkbox" required="required"> I accept the Terms of Use & Privacy Policy</label>
<hr class="mb-4">
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
#Html.ActionLink("Already have an account? Login here. ", "SignIn", "User", new { area = "" }, new { #class = "navbar-brand" })
</div>
</form>
</div>
UserController.cs
public ActionResult SignUp()
{
return View(new User());
}
public ActionResult SignupSubmit(User user)
{
if (ModelState.IsValid)
{
AddUserToDB(user);
}
else
{
return View("SignUp");
}
TempData["Falied"] = "You can now connect with your details";
return RedirectToAction("SignIn", "User");
}
[HttpPost]
public bool AddUserToDB(User u)
{
try
{
UserDal dal = new UserDal();
dal.users.Add(u);
dal.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var errors in ex.EntityValidationErrors)
{
foreach (var validationError in errors.ValidationErrors)
{
// get an error message
string errorMessage = validationError.ErrorMessage;
Trace.TraceInformation("Property: {0} Error: {1}",
validationError.PropertyName,
validationError.ErrorMessage);
}
}
return false;
}
return true;
}
User.cs
public class User
{
[Key]
[Required]
[RegularExpression("^[0-9]{9}$", ErrorMessage = "ID must be with 9 numbers")]
public string userid { get; set; }
[Required]
[RegularExpression("^[a-z]+$", ErrorMessage = "First Name must be only Characters")]
public string firstName { get; set; }
[Required]
[RegularExpression("^[a-z]+$", ErrorMessage = "Last Name must be only Characters")]
public string lastName { get; set; }
[Required]
[RegularExpression(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$", ErrorMessage = "Email must conatain characters seperate with #")]
[StringLength(100, MinimumLength = 4, ErrorMessage = "Email must be with at least 4 characters or Maximum 50 caracters")]
public string email { get; set; }
[Required]
[RegularExpression(#"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$", ErrorMessage = "Password must conatain eight characters, at least one letter and one number")]
[StringLength(8, MinimumLength = 8, ErrorMessage = "Password must be with 8 Characters")]
public string password { get; set; }
public string permission { get; set; }
public float totalHoures { get; set; }
}
the issue was that user was not sending here ...
else {
return View("SignUp");
}
so i changed the code to
return View("SignUp",user);
and now it working as expected.
my view is strongly typed view, and i just want to see the errors messages next the text box which are not passed the validation successfully.

How to check if item is selected in a dropdownList and enable/disable a textbox if a listitem is selected/not selected

I have a page where i have created a form of sorts.
I have 2 dropdownlists(profilelist & salarylist).
I have 3 textboxes in this form. What i want to do:
I have 2 boxes where i create a new profile and a new salarygroup and the new profile is added to the profillist amd the salarygroup is added to the salarylist.
Now I want the third box to be disabled UNTIL an item in both the salarylis and profillist is selected. once items are selected the textbox should be enabled.
My view:
#model KUMA.Models.EmployeeCardAdminModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row bgwhite">
<div class="twelve columns">
<h2>Administration KUMA</h2>
<div class="row bgwhite">#using (Html.BeginForm("Index", "Admin"))
{
<div class="three columns">
#Html.DropDownList("UserId", (SelectList)ViewBag.UserId, "--Välj anställd--")
</div>
<div class="three columns" style="margin-right:457px !important;">
#Html.DropDownList("Salaryid", (SelectList)ViewBag.Salaryid, "--Välj LöneGrupp--")
<input style="float:left;" type="submit" value="Knyt" />
</div>
}
#using (Html.BeginForm("Kompetens", "KumaAdmin"))
{
<div class="three columns" style="margin-right: 627px;">
<h6>Kompetenser</h6>
<div style="width:456px;"> #Html.ListBox("kompetensId", (SelectList)ViewBag.KomId, new { placeholder = "Kompetenser" })</div><br/>
#Html.TextBoxFor(mm => mm.Kompetens, new { placeholder = "Ange Kompetens" })
#*#Html.TextBoxFor(mm => mm.KompetensTest, new { placeholder = "Kompetens" })
#Html.TextAreaFor(mm => mm.KompetensTest, new { placeholder = "Kompetens", rows="5", cols="80" })*#
<input type="submit" style="margin-right: 205px;" value="Skapa"/><br/><br/>
</div>
}
#using (Html.BeginForm("Index", "KumaAdmin"))
{
<div class="three columns" style="margin-right: 627px;">
#* <input name="profileTxtBox"type="text" style="width:97px; height:28px;" value="" />*#
#Html.TextBoxFor(mm => mm.Profile, new { placeholder = "Ange Profil" })
#Html.TextBoxFor(mm => mm.SalaryGroup, new { placeholder = "Ange LöneGrupp" })
<input type="submit" value="Skapa"/>
</div>
}
#* <div class="one columns" style=" margin-left: 100px;margin-right: 164px; margin-top: -33px;">
<input name="profileTxtBox"type="submit" style="width:100px;" value="Add" />
</div>*#
<div class="five columns"></div>
</div>
</div
>
Controller:
public class AAdminController : Controller
{
static List<Employee> list = new List<Employee>();
//EmployeeCardAdminModel employee = new EmployeeCardAdminModel();
//
// GET: /Admin/
//[Authorize(Roles = "Admin")]
[HttpGet]
public ActionResult Index()
{
ViewBag.UserId = new SelectList(list, "Id", "Profile");
ViewBag.Salaryid = new SelectList(list, "Id", "SalaryGroup");
ViewBag.KomId = new SelectList(list, "Id", "Kompetens");
ModelState.Clear();
return View("Index");
}
[HttpPost]
// submit for profile & salary box
public ActionResult Index(Models.EmployeeCardAdminModel e)
{
if (string.IsNullOrEmpty(e.Profile) == false && string.IsNullOrEmpty(e.SalaryGroup) == false)
{
// adda a new employye to the list and set the values from the parameter to the model
list.Add(new Employee
{
Id = e.Id + 1,
Profile = e.Profile,
SalaryGroup = e.SalaryGroup
});
}
return (Index());
}
[HttpPost]
// submit for knowledge box
public ActionResult Kompetens(Models.EmployeeCardAdminModel e)
{
if (string.IsNullOrEmpty(e.Kompetens) == false)
{
// adda a new employye to the list and set the values from the parameter to the model
list.Add(new Employee
{
Kompetens = e.Kompetens
});
}
return (Index());
}
And finally my model(note that the emplyee class is the same as my model, with the same properties but ive read that for best practice it is best to separate these.):
public class EmployeeCardAdminModel
{
public string Profile { get; set; }
public int Id { get; set; }
public string SalaryGroup { get; set; }
public string Kompetens { get; set; }
}
the way i would normaly do this is to call the desired lists and check if the selected index is larger than null but the problem is i don't know how to access the list from the controller in the correct way so i can get access to the items in it. also how can i get an id on the textboxes? I need this to be able to disable/enable the correct textbox.
Im pretty new to mvc and i learn by doing projects so all advice is appreciated.
Thank you!
Well after some time I realized that there wasn't a good way of doing this without script.
So i solved it with jquery like this:
$(function () {
$(".list select").change(function () {
if ($(".list1 select").val().length == 0 || $(".list2 select").val().length == 0) {
$(".kompetensbox input").attr('disabled', 'disabled');
}
else {
$(".kompetensbox input").removeAttr('disabled');
}
})
});
view changes (added css classes):
<div class="three columns list list1">
#Html.DropDownList("UserId", (SelectList)ViewBag.UserId, "--Välj profilgrupp--")
</div>
<div class="three columns list list2" style="margin-right:457px !important;">
#Html.DropDownList("Salaryid", (SelectList)ViewBag.Salaryid, "--Välj LöneGrupp--")
<input style="float:left;" type="submit" value="Knyt" />
</div>
Hope it helps others that attempt the same.

ASP.NET MVC Model list binding

Here is my model:
public class Items
{
public string Foo { get; set; }
public string Bar { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new List<Items>
{
new Items
{
Foo = "foo",
Bar = "bar"
},
new Items
{
Foo = "ai",
Bar = "ia"
},
new Items
{
Foo = "one",
Bar = "two"
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(List<Items> model)
{
return View(model);
}
View (Index):
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
<div onclick="$(this).remove();">
#Html.TextBoxFor(model => model[i].Foo) <br/>
#Html.TextBoxFor(model => model[i].Bar)
</div>
}
<div>
<input type="submit"/>
</div>
}
I delete second pair:
<div onclick="$(this).remove();">
<input name="[0].Foo" type="text" value="foo"> <br>
<input name="[0].Bar" type="text" value="bar">
</div>
<div onclick="$(this).remove();">
<input name="[2].Foo" type="text" value="one"> <br>
<input name="[2].Bar" type="text" value="two">
</div>
When posting, i get only first pair ("foo" and "bar"). It's because third pair has index "2". I want to get both pairs(Not using FormCollection. I want it to bind automatically). In reality, I have many other inputs on form, so i don't want to reload and reattach indices to each input. Can you help me?
This may be helpful to you....
need to place Hidden field on each item...
MVC3 Non-Sequential Indices and DefaultModelBinder
I found solution, thanks to Amit Prajapati:
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
var identifier = Guid.NewGuid();
<div onclick="$(this).remove();">
#Html.Hidden("Index", identifier)
#Html.TextBox("[" + identifier + "].Foo")
<br/>
#Html.TextBox("[" + identifier + "].Bar")
</div>
}
<div>
<input type="submit" />
</div>
}