My code is similar to:
class StudentsViewModel:
public class StudentsViewModel
{
public List<Student> Students { get; set; }
public Student SelectedStudent { get; set; }
public string DisplayMode { get; set; }
}
StudentsController:
[HttpPost]
public ActionResult New(int? page, int? SelectedGroup)
{
// some code
StudentsViewModel model = new StudentsViewModel();
model.Students = db.Students.ToList().ToPagedList(pageNumber, pageSize);
model.SelectedStudent = null;
model.DisplayMode = "WriteOnly";
ViewBag.IDGroup = new SelectList(db.Groups, "IDGroup", "Name");
return View("Index", model);
}
View: Index
<form method="post">
<input type="submit" value="Add Student" formaction="/Students/new" class="btn btn-default" />
//some code
#{
if (Model.SelectedStudent != null)
{
if (Model.DisplayMode == "ReadWrite")
{
Html.RenderPartial("_EditStudent", Model.SelectedStudent);
}
}
if (Model.DisplayMode == "WriteOnly")
{
Html.RenderPartial("_InsertStudent", new StudentList.Models.Student());
}
}</form>
Partial View:
_InsertStudent.cshtml
<div class="form-group">
#Html.DropDownList("IDGroup", String.Empty)
#Html.ValidationMessageFor(model => model.IDGroup)
</div>
I have very big problem because my DropDownList doesn't work... Now I display _InsertStudent when I click on button but it doesn't work... If i have
Html.RenderPartial("_InsertStudent", new StudentList.Models.Student());
directly (without button) it works...
Related
It's supposed to validate and then go to the next view. However, it skips validation entirely and instead reloads the page. I think the issue is with the button itself on the view, I have also tried changing the anchor tag to a submit button, but that just brings me back to the index page. Any help would be appreciated.
My Controller
namespace Trip_Log.Controllers
{
public class TripController : Controller
{
private TripLogContext context { get; set; }
public TripController(TripLogContext ctx) => context = ctx;
public RedirectToActionResult Cancel()
{
TempData.Clear();
return RedirectToAction("Index", "Home");
}
[HttpGet]
public IActionResult Add(string id = "")
{
var vm = new TripViewModel();
if (id == "page2")
{
var accomodation = TempData[nameof(Trip.Accommodation)]?.ToString();
if (string.IsNullOrEmpty(accomodation))
{
vm.PageNumber = 3;
var destination = TempData[nameof(Trip.Destination)].ToString();
vm.Trip = new Trip { Destination = destination };
return View("Add3", vm);
}
else
{
vm.PageNumber = 2;
vm.Trip = new Trip { Accommodation = accomodation };
TempData.Keep(nameof(Trip.Accommodation));
return View("Add2", vm);
}
}
else if (id == "page3")
{
vm.PageNumber = 3;
vm.Trip = new Trip { Destination = TempData.Peek(nameof(Trip.Destination)).ToString() };
return View("Add3", vm);
}
else
{
vm.PageNumber = 1;
return View("Add1", vm);
}
}
[HttpPost]
public IActionResult Add(TripViewModel vm)
{
if(vm.PageNumber == 1)
{
if (ModelState.IsValid)
{
TempData[nameof(Trip.Destination)] = vm.Trip.Destination;
TempData[nameof(Trip.Accommodation)] = vm.Trip.Accommodation;
TempData[nameof(Trip.StartDate)] = vm.Trip.StartDate;
TempData[nameof(Trip.EndDate)] = vm.Trip.EndDate;
return RedirectToAction("Add", new { id = "page2" });
}
else
{
return View("Add1", vm);
}
}
else if(vm.PageNumber == 2)
{
TempData[nameof(Trip.AccommodationPhone)] = vm.Trip.AccommodationPhone;
TempData[nameof(Trip.AccommodationEmail)] = vm.Trip.AccommodationEmail;
return RedirectToAction("Add", new { id = "page3" });
}
else if(vm.PageNumber == 3)
{
vm.Trip.Destination = TempData[nameof(Trip.Destination)].ToString();
vm.Trip.Accommodation = TempData[nameof(Trip.Accommodation)].ToString();
vm.Trip.StartDate = (DateTime)TempData[nameof(Trip.StartDate)];
vm.Trip.EndDate = (DateTime)TempData[nameof(Trip.EndDate)];
vm.Trip.AccommodationPhone = TempData[nameof(Trip.AccommodationPhone)].ToString();
vm.Trip.AccommodationEmail = TempData[nameof(Trip.AccommodationEmail)].ToString();
context.Trips.Add(vm.Trip);
context.SaveChanges();
TempData["message"] = $"Trip to {vm.Trip.Destination} added";
return RedirectToAction("Index", "Home");
}
else
{
return RedirectToAction("Index", "Home");
}
}
}
}
My view
#model TripViewModel
#*
*#
#{
}
<h4>Add Trip Destination and Dates</h4>
<form asp-action="Add" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Trip.Destination">Destination</label>
<input asp-for="Trip.Destination" class="form-control">
<hr />
</div>
<div class="form-group">
<label asp-for="Trip.Accommodation">Accommodation</label>
<input asp-for="Trip.Accommodation" class="form-control">
<hr />
</div>
<div class="form-group">
<label asp-for="Trip.StartDate">Start Date</label>
<input asp-for="Trip.StartDate" class="form-control">
<hr />
</div>
<div class="form-group">
<label asp-for="Trip.EndDate">End Date</label>
<input asp-for="Trip.EndDate" class="form-control">
<hr />
</div>
<a class="btn btn-outline-dark" asp-controller="Trip" asp-action="Add">Next</a>
<a class="btn btn-outline-secondary " asp-controller="Trip" asp-action="Cancel">Cancel</a>
</form>
My model
namespace Trip_Log.Models
{
public class Trip
{
public int TripId { get; set; }
[Required(ErrorMessage = "Please enter a destination")]
public string Destination { get; set; }
[Required(ErrorMessage = "Please enter a start date")]
public DateTime StartDate { get; set; }
[Required(ErrorMessage = "Please enter an end date")]
public DateTime EndDate { get; set; }
public string Accommodation { get; set; }
public string AccommodationPhone { get; set; }
public string AccommodationEmail { get; set; }
public string ThingToDo1 { get; set; }
public string ThingToDo2 { get; set; }
public string ThingToDo3 { get; set; }
public string ThingsToDo { get { return ThingToDo1 + "\n" + ThingToDo2 + "\n" + ThingToDo3; }
}
}
TripViewModel
public class TripViewModel
{
// Used to shape multiple entities from one or more models into a single object
//
public Trip Trip { get; set; }
public int PageNumber { get; set; }
}
First, seens like you posted the wrong model since in your controller you expected to receive TripViewModel and the model you showed is Trip.
Second, the validation goes to the top of the property, like this:
[Required(ErrorMessage = "Please enter an end date")]
public DateTime EndDate { get; set; }
You can try to replace anchor tag with button like this:
<input type="submit" value="submit" />
And then make sure you load jquery.validate.min.js and jquery.validate.unobtrusive.min.js,then when you click the button,form will be validated and go to action Add.
The reason it didn't work is because I was missing the hidden input field stating the page number.
<input type="hidden" asp-for="PageNumber" />
The next button is also needs to be like so, since as another user pointed out anchors use get.
<button class="btn btn-outline-dark" type="submit">Next</button>
Both the validation and redirects started working with these two changes applied to the View.
I have a problem, i new with asp.net core and i try to build Login page (after i finish to build sign up page that add new row to db with the correct information).
my problem is when i click on login button with the wrong details so i don't see the error message (LoginError) only after i click on login button again i see the LoginError message (from TempData), why?
is the right way? if not i will happy to try another way.
Login cshtml page:
#page
#model AutomationTool.Pages.Login.IndexModel
#{
ViewData["Title"] = "Index";
}
<h1>Login</h1>
<form method="post">
<div class="form-group">
<label asp-for="user.UserEmail"></label>
<input asp-for="user.UserEmail" class="form-control" />
<span class="text-danger" asp-validation-for="user.UserEmail"></span>
</div>
<div class="form-group">
<label asp-for="user.Password"></label>
<input asp-for="user.Password" class="form-control" />
<span class="text-danger" asp-validation-for="user.Password"></span>
</div>
<div>
#Model.LoginError
</div>
<div>
#Model.Message
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
Login cshtml.cs page:
namespace AutomationTool.Pages.Login
{
public class IndexModel : PageModel
{
private readonly IUserData userData;
[BindProperty]
public User user { get; set; }
[TempData]
public string Message { get; set; }
[TempData]
public string LoginError { get; set; }
public IndexModel(IUserData userData)
{
this.userData = userData;
}
public IActionResult OnGet()
{
return Page();
}
public IActionResult OnPost()
{
ModelState.Remove("User.Id");
ModelState.Remove("User.FirstName");
ModelState.Remove("User.LastName");
if (!ModelState.IsValid)
{
TempData["Message"] = "All fields required!";
return Page();
}
if (!userData.VerifyLogin(user.UserEmail, user.Password))
{
TempData["LoginError"] = "Something wrong try again!";
return Page();
}
else
{
return RedirectToPage("/Index");
}
}
}
}
thanks!
Here your Message and LoginError parameters have been read many times instead of once, so you should use [BindProperty] or [ViewData] instead of [TempData] to bind these two parameters.
The difference between them, you can refer to this.
Chang your code like this:
public class IndexModel : PageModel
{
private readonly IUserData userData;
[BindProperty]
public User user { get; set; }
[BindProperty]//[ViewData]
public string Message { get; set; }
[BindProperty]//[ViewData]
public string LoginError { get; set; }
public IndexModel(IUserData userData)
{
this.userData = userData;
}
public IActionResult OnGet()
{
return Page();
}
public IActionResult OnPost()
{
ModelState.Remove("User.Id");
ModelState.Remove("User.FirstName");
ModelState.Remove("User.LastName");
if (!ModelState.IsValid)
{
Message = "All fields required!";
return Page();
}
if (!userData.VerifyLogin(user.UserEmail, user.Password))
{
LoginError = "Something wrong try again!";
return Page();
}
else
{
return RedirectToPage("/Index");
}
}
}
Here is the test result:
PeriodFrom = 05/10/2016
PeriodTo = 06/10/2016
Above properties date format is dd/mm/yyyy as you can see from the below screen shot.
However when i click on the submit button, the values are copied to a view model.
PeriodFrom becomes 10/05/2016 and PeriodTo becomes 10/05/2016
The 10 becomes the day and the 5 becomes the month. Not sure why this is happening. Could someone please advise ?
Startup
var supportCultures = new[]
{
new CultureInfo("en-GB")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-GB"),
SupportedCultures = supportCultures,
SupportedUICultures = supportCultures
});
View
<form asp-controller="BragManagement" asp-action="Export" method="get" role="form">
<input type="hidden" asp-for="#Model.PeriodFrom" />
<input type="hidden" asp-for="#Model.PeriodTo" />
<input type="hidden" asp-for="#Model.BragValueTitle" />
<button type="submit" class="btn btn-pink">Export</button>
</form>
Method
[HttpGet]
public IActionResult Export(UserVoteDetailSearchViewModel model)
{
var result = _userRepository.GetAllUserVoteDetails(model);
_reportService.GenerateReport(result);
return View();
}
View model
public class UserVoteDetailSearchViewModel
{
public DateTime? PeriodFrom { get; set; }
public DateTime? PeriodTo { get; set; }
public string BragValueTitle { get; set; }
public List<UserVoteDetail> UserVoteDetailList { get; set; }
}
I have created an editor template base on this article ASP.NET MVC: Annotated for Input by Dino Esposito
Everything works fine until i press the submit button. I find out that my POST function return model is NULL, its like the model is not bind to the view. I have been trying all trick that I know and I found from the internet but I still can't fix it.
This is my controller
// GET: /Asset/New
public ActionResult New()
{
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name");
return View(new AssetViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New(AssetViewModel vm)
// vm.asset should contain new value but currently return null
{
if (ModelState.IsValid)
{
db.Assets.Add(vm.asset);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name", vm.asset.typeID);
return View("New", vm);
}
this is my view
#using (Html.BeginForm("New","Asset","POST")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(m=>m.asset, "InputTemplate" )
// note : the code works if i don't use my own template ==> #Html.EditorFor(m=>m.asset)
<div class="form-actions btn pull-right">
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-sm"})
<button type="reset" class="btn btn-sm" value="Index">
Reset
</button>
<button type="submit" class="btn btn-sm btn-success">
<i class="glyphicon glyphicon-plus"></i>
Tambah
</button>
</div>
}
and this is my InputTemplate
#inherits System.Web.Mvc.WebViewPage
#if (Model == null)
{
<span>#ViewData.ModelMetadata.NullDisplayText</span>
}
else
{
foreach (var prop in ViewData
.ModelMetadata
.Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.DisplayName != null) { // only display prop not of ComplexType
// note : using bootstrap for css styling
<div class="form-group col-xs-6">
<label class="col-xs-4 control-label text-right">
<span style="color:red"> #(prop.IsRequired ? "*" : "") </span>
<span>#prop.GetDisplayName()</span>
</label>
<div class="col-xs-8">
#if(prop.IsReadOnly)
{
<span class="readonly-field">#Html.Display(prop.PropertyName)</span>
}
else if (prop.TemplateHint == "DropDown")
{
<span>#Html.DropDownList(prop.PropertyName,(IEnumerable<SelectListItem>) ViewData[prop.PropertyName], new { #class = "form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName)</span>
}
else
{
<div class="editor-field">
<span>#Html.Editor(prop.PropertyName, new { #class = "text-box single-line form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName, new { #class = "label-danger" } )</span>
</div>
}
</div>
</div>
} // if
} // foreach
}
This is my viewmodel
using System;
using SIGMA.Models;
namespace SIGMA.ViewModels
{
public class AssetViewModel
{
public AssetViewModel()
{
asset = new Asset();
}
public Asset asset { get; set; }
}
}
This is my model
public class Asset
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[DisplayName("No. Siri")]
[StringLength(45)]
public string serial_num { get; set; }
[DisplayName("Model")]
[Required(ErrorMessage = "Model perlu diisi!")]
[StringLength(45)]
public string model { get; set; }
[DisplayName("Harga Seunit")]
[RegularExpression(#"^\d{0,6}(\.\d{2})?$", ErrorMessage = "Sila gunakan format harga yang betul.")]
public float? unit_cost { get; set; }
[UIHint("DropDown")]
[DisplayName("Jenis Aset")]
[Required(ErrorMessage = "Jenis aset perlu dipilih!")]
[DisplayFormat(NullDisplayText = "Belum didaftar")]
public int? typeID { get; set; }
public virtual Ref_Asset_Type type { get; set; }
}
Sorry guys for the trouble.. i think i solve it.
My biggest mistake is using reserved word 'model' and 'type' as my property name. This some how cause problem to asp.net in interpreting my model using the user define editor template.
Once I change my property name - model to model_name and type to asset_type, i can see the my entry in my return model already.
Thanks to all
.... spends the whole day and night for this silly mistake but the lesson learn is worth it
I have a partial view for contact. Currently the index view shows this partial view for contact details. There is a save button inside the partial view to save the edited data. There is a validation for age while saving the edited data. This much is working fine.
Whenever user edit age and save it, I need to show the corresponding horoscope prediction on the main view. How do we achieve it?
public class ContactEntity
{
public int ContactID { get; set; }
public string ContactName { get; set; }
[Range(18, 50, ErrorMessage = "Must be between 18 and 50")]
public int ContactAge { get; set; }
}
public class AgeHoroscope
{
public int Age { get; set; }
public string HoroscopePrediction { get; set; }
}
//Home Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class HomeController : Controller
{
List<AgeHoroscope> horoList = new List<AgeHoroscope>()
{
new AgeHoroscope{Age=16,HoroscopePrediction="You are confused"},
new AgeHoroscope{Age=26,HoroscopePrediction="You are very brilliant"},
new AgeHoroscope{Age=27,HoroscopePrediction="You are practical"}
};
public ActionResult Index()
{
AgeHoroscope selectedHoro = horoList[1];
return View(selectedHoro);
}
}
}
//Contact Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class ContactController : Controller
{
public PartialViewResult MyContactDetailEdit()
{
Thread.Sleep(500);
return PartialView(GetContact());
}
[HttpPost]
public PartialViewResult MyContactDetailEdit(string conatcclick)
{
//Save to database
Thread.Sleep(500);
return PartialView(GetContact());
}
private ContactEntity GetContact()
{
ContactEntity contactEntity = new ContactEntity();
contactEntity.ContactID = 1;
contactEntity.ContactName = "Lijo";
contactEntity.ContactAge = 26;
return contactEntity;
}
}
}
//Index.cshtml
#model MYContactEditPartialViewTEST.AgeHoroscope
#{
ViewBag.Title = "Index";
}
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<h2>
Index</h2>
<div>
<a>Your age is <b>#Html.DisplayFor(x => x.Age) </b>and the prediction is <b>" #Html.DisplayFor(x => x.HoroscopePrediction)
" </b></a>
<br />
</div>
<div style="border: 3px solid Teal">
#Html.Action("MyContactDetailEdit", "contact")
</div>
// MyContactDetailEdit.cshtml
#model MYContactEditPartialViewTEST.ContactEntity
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<h3>MyContactDetailEdit PARTIAL</h3>
<div>
#Html.HiddenFor(x => x.ContactID)
<br />
<div style="font-weight:bold">
Name:
<br />
</div>
#Html.DisplayFor(x => x.ContactName)
<br />
<br />
<div style="font-weight:bold">
Age
<br />
</div>
#Html.EditorFor(x => x.ContactAge)
#Html.ValidationMessageFor(model => model.ContactAge)
<br />
<br />
</div>
<input type="submit" id="saveButton" value="Save" />
}
READING
ASP.Net MVC Passing multiple parameters to a view
ASP.Net MVC 3 RC2, Partial Views Form Handling
I would like just use jQuery to do ajax post and then change the parent view client side directly
you'll need to create a new ViewModel to do this. This ViewModel (IndexViewModel.cs) would look something like this (I'm guessing at this):
public class IndexViewModel
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public int ContactAge { get; set; }
public string HoroscopePrediction { get; set; }
}
you'd then use it in your controller index action (and view):
#model MYContactEditPartialViewTEST.IndexViewModel
the idea being that you'd populate the HoroscopePrediction in a join between ContactEntity and AgeHoroscope (or via Linq etc) and thus show each line in the index as a complete object (showing contact and horoscope).
As data is posted to "HomeController" and "Index" action, so changes are reflected when you change age in View.
Try to modify the home controller as follows,then it will work as expected.
1) Instead of having a list of AgeHoroscope, we can have a dictionary of age and prediction.
2) Create two Index Action for HttpGet and HttpPost as follows.
public class HomeController : Controller
{
Dictionary<int, string> AgePred = new Dictionary<int, string>()
{
{16,"You are confused"},
{26,"You are very brilliant"},
{27,"You are practical"}
};
[HttpGet]
public ActionResult Index()
{
AgeHoroscope selectedHoro = new AgeHoroscope() { Age = 26 };
selectedHoro.HoroscopePrediction = AgePred[selectedHoro.Age];
return View(selectedHoro);
}
[HttpPost]
public ActionResult Index(AgeHoroscope model,ContactEntity entity)
{
model.Age = entity.ContactAge;
model.HoroscopePrediction = AgePred[entity.ContactAge];
return View(model);
}
}