Asp.MVC RenderAction for part of the page doesn't work as I expect - asp.net-mvc

Ok I mess my page really bad and I need good help here.
I have a login page with Login and Register partial views.
RegisterView has it's own ViewModel class and it makes me problem.
I render Register partial view by using "RenderAction" helper.
Biggest problem is validation. When I don't enter anything in register fields and click submit register partial view is not updated inside it's parrent LoginView but return me only RegisterView. In other words my validation works but not where I want it to work.
LogOn.cshtml (this one contains register partial view)
<div id="regstrationForm">
#{Html.RenderAction("RegisterUser", "Account");}
</div>
Register (Partial View)
#using (#Ajax.BeginForm("RegisterUser", "Account", new AjaxOptions { UpdateTargetId = "reg" }))
{
<table id="reg">
...
<tr>
<td>
#Html.TextBoxFor(u => u.Username, new { #class = "registrationTextFields", placeholder = "Email" })
</td>
</tr>
<tr>
<td>
#Html.TextBoxFor(p => p.Password, new { #class = "registrationTextFields", placeholder = "Password" })
</td>
</tr>
<tr>
<td align="right">
<input class="signUpButton" type="submit" value="Sign up" />
</td>
</tr>
<tr>
<td>
#Html.ValidationMessage("myerrorsummary")
</td>
</tr>
</table>
This is HttpPost controller method when user click on sign up button.
Here I tried to return "PartialView()" and it turns my input fields to red css style but not display validation information bellow those fields.
[HttpPost]
public ActionResult RegisterUser(RegisterViewModel logOnViewModel)
{
if (ModelState.IsValid)
{
MembershipCreateStatus result;
try
{
...
}
else
{
ModelState.AddModelError("myerrorsummary", "The input is not valid");
ViewBag.CountryList = countryRepository.GetAllCountries();
ViewBag.CityList = cityRepository.GetAllCitiesByCountryId(1);
return View(logOnViewModel);
}
}

I suspect that you forgot to include the following script in your main view:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
This is what makes Html helpers such as Ajax.BeginForm and Ajax.ActionLink to perform AJAX requests instead of normal.
You might also take a look at the following article which explains in more details about how those helpers work in ASP.NET MVC 3.

Related

using the same partial view with different buttons

I have the following partial view, which lists users in a table. Each row has an Enroll button, which enrolls the user to the selected course.
I need almost the same view for another task. However, I need to add users to Discussions (instead of enrolling them to a course). I know I can create another view and change the Enroll buttons to Add buttons.
However, I wonder if there is a more effective way of doing this. My approach does not seem to be easy to maintain.
#model IEnumerable<ApplicationUser>
<h4>Search results:</h4>
<table class="table-condensed" style="font-size:smaller">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
<input class="btn_Enroll" data-userid="#item.Id" value="Enroll" type="button" />
</td>
</tr>
}
</table>
<script>
$(".btn_Enroll").click(function () {
//code for enrolling
var course_id = $("#hdn_SelectedCourseId").val();
})
</script>
One way to do it is by setting an attribute of your calling action method that will render this view
<table class="table-condensed" style="font-size:smaller" data-module="#ViewData["module"]"></table>
and then use it in your JS code
<script>
$(".btn_Enroll").click(function () {
//code for enrolling
var course_id = $("#hdn_SelectedCourseId").val();
var moduleType = $(this).closest("table").attr("data-module");
if (moduleType === "enroll")
{
//Do enrollment
}
else if (moduleType === "discussion")
{
//discuss here
}
})
For example on home page you have links like
#Html.ActionLink("enrollment", "Index", new { module = "enroll" })
#Html.ActionLink("Discussion", "Index", new { module = "discussion" })
and your ApplicationUserController has index action like this
public ActionResult Index(string module)
{
ViewData["module"] = module;
return View();
}
However if scope of project or requirements can change for enrollment and/or discussion then better to keep then separate to avoid complexity of code in single page as well as in single JS code.

HTTP POST Request not Working in ASP.NET MVC 4

I have created a simple MVC application and have created html table in view. When i click on hyperlink under this table it does not take me to the [HttpPost] method and goes to [HttpGet] default method. Please take a look on my table placed in view portion of my mvc application.
#model Mvc.Affiliates.Models.Products
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Details</h2>
<div style="height: 200px; width: 500px">
<h1>This is Content page </h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<table border="1" style="width:550px;">
<tr>
<th>Job Id</th>
<th>Job Name</th>
<th>Create Date</th>
</tr>
#foreach (var item in Model.JobList)
{
<tr>
<td width="50px">#item.JobId</td>
<td width="200px">#item.JobName</td>
<td width="200">#item.CreateDate</td>
</tr>
}
</table>
<br />
<table border="1" style="width: 550px; ">
#{
int i = Model.JobList.Count;
i = i / 10;
i = i + 1;
<tr>
<td width="450">
#for(int n = 1; n <= i; n++)
{
#Html.ActionLink(n.ToString(), "Index", "Home", new { id = n});
#Html.Raw(" ");
}
</td>
</tr>
}
</table>
}
</div>
So my above view #Html.ActionLink() is not working well. Please anyone help that how can i force my ActionLink to go into [HttpPost] method.
EDIT:
I have pasted complete view above. I am actually creating gridview with paging and when i click on page number (whcih is an ActionLink in numeric values) i need to run [HttpPost] method, thanks.
#Html.ActionLink(n.ToString(), "Index", "Home", new { id = n}) is a get request
Your method is expecting id
So Better edit like:
[HttpGet]
public ActionResult Index(int id)
{
return View();
}
You can't post by doing this.
Action link is GET Method.
Even if you manage to make it to be POST method, right now your action link Does Post nothing / not the MyProducts model you want it to post.
Solution:
Reconsider your view design
Using ajax ( jquery ) to post it. Below is some snippet:
$.ajax({
type: "POST",
datatype: "Json",
url: '/Home/Index",
data: #yourmodel
});
EDIT: Modify the OP View for clear explanation:
If you plan to use Html.BeginForm, then instead of #Html.ActionLink, you should use <input type="submit" />.
By this way, it will appear as a button, instead of a link.
It will send a post that contain Products object to your server.
If you plan to use Ajax, you don't need the Html.BeginForm to post. I suggest you read this post to understand clearly: http://www.mikesdotnetting.com/article/220/posting-data-with-jquery-ajax-in-asp-net-razor-web-pages

Issue with mvc, partial view dispaying

I have a question about partial view. I want to display in header Login form which i created. In HomeController I have 2 actions: one is Login and other is Login with httppost method.
In partial view (_Layout.cshtml) I have a code - only send footer div:
<td style="text-align:center">
<h3>Bookstore</h3>
#Html.Partial("_LoginPartial")
</td>
In Login view I have:
#using(Html.BeginForm("Login", "Home", FormMethod.Post)){
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<tr>
<td>#Html.LabelFor(a=>a.Username)</td>
<td>#Html.TextBoxFor(a=>a.Username)</td>
<td>#Html.ValidationMessageFor(a=>a.Username)</td>
</tr>
<tr>
<td>#Html.LabelFor(a=>a.Password)</td>
<td>#Html.PasswordFor(a=>a.Password)</td>
<td>#Html.ValidationMessageFor(a=>a.Password)</td>
</tr>
<tr>
<td>
<input type="submit" value="Login" />
</td>
</tr>
</table>}
Controller
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Users u)
{
if (ModelState.IsValid) {
using (DatabaseLoginEntities dl = new DatabaseLoginEntities()) {
var v = dl.Users.Where(a => a.Username.Equals(u.Username) && a.Password.Equals(u.Password)).FirstOrDefault();
if (v != null) {
Session["LogedUserId"] = v.UserAccountID.ToString();
Session["LogedUserFullName"] = v.FullName.ToString();
return RedirectToAction("AfterLogin");
}
}
}
return PartialView("_LoginPartial", u);
}
When press Login button, mvc switches me to separate page in which Login form is shown. I don't want that to happen. It must stay in header. Functionality is ok but I have issue how to show that only in header. Has anyone have idea where I'm wrong?
you must use ajax
#using (Ajax.BeginForm("Login", "Home",
new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
,
UpdateTargetId = "div_id"
}
)){
<table>
<tr>
<td>#Html.LabelFor(a=>a.Username)</td>
<td>#Html.TextBoxFor(a=>a.Username)</td>
<td>#Html.ValidationMessageFor(a=>a.Username)</td>
</tr>
<tr>
<td>#Html.LabelFor(a=>a.Password)</td>
<td>#Html.PasswordFor(a=>a.Password)</td>
<td>#Html.ValidationMessageFor(a=>a.Password)</td>
</tr>
<tr>
<td>
<input type="submit" value="Login" />
</td>
</tr>
</table>
}

Data not loading on partial view, MVC

I am doing work on form where user can enter a customer record....View is scaffold with Create controller.
On 'Create' View, user can enter 'engineNo' to check its details which passes to another action "CheckRecord",,it can be seen from view...
<form>
<input type="text" id="enginNo" />
<input type="button" value="search" id="btnSearch" />
</form>
#using (Html.BeginForm("Index","Home",FormMethod.Get))
{
#Html.AntiForgeryToken()
<div id="info">
#{Html.RenderAction("CheckRecord","Sales");}
</div>
some create fields
}
The Create and "CheckRecord" actions are,,
public ActionResult Create()
{
ViewBag.CustomerId = new SelectList(db.CustomersDMs, "CustomerId", "Name");
ViewBag.SMClientBranchId = new SelectList(db.SMClientBranchesDMs, "SMClientId", "Name");
ViewBag.EngineNumber = new SelectList(db.StockDMs, "EngineNumber", "ChasisNumber");
return View();
}
public ActionResult CheckRecord(string enginNo)
{
var results = db.StockDMs.Where(c=>c.EngineNumber ==enginNo);
return PartialView("_part",results);
}
And my partialview,,,
#model IEnumerable<SM.CRM.AutosLoan.Models.Core.DomainModels.StockDM>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.AutoCompanyBrand.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.SMClientBranch.Name)
</td>
}
My problem is, the partial view is rendered correctly but the Model of partial view doesn't have value,,,Why is that, i am doing something wrong...Please help,,,Thanks for your time
(Posting this as answer since I mentioned it in comments and that's not the correct place)
Your action CheckRecord(string enginNo) takes an argument of enginNo, but you're calling it without any argument. That in turn means your db lookup will most likely not return any results, unless you get results on..
var results = db.StockDMs.Where(c => c.EngineNumber == null);
Make sure the action gets a valid argument, for example:
#{ Html.RenderAction("CheckRecord", "Sales", new { enginNo = "abc123" }); }

Asp.net MVC Razor more than one form on a page

Yo
I have a registration page on my site - at the top of the page is a login form for existing users. In the main area there is the registration form.
The login are is a partial view with #model ViewModels.LoginViewModel
The registration are is also a partial with #model ViewModels.RegViewModel
The main page which houses these partials is a view with #model ViewModels.RegPageViewModel
This viewmodel looks like:
public class RegViewModel
{
public RegisterVm RegisterVm { get; set; }
public LoginVm LoginVm { get; set; }
}
When I submit the registration part of the page (it's action is register/capture - the receiving action expects a RegisterVm) to it's controller it complains about being passed the wrong viewmodel
What's the deal with subviews and their viewmodel? Is there a standard approach to dealing with this?
Should I have one submit URL for this page which figures out if it's a login request or a register request and then handles the post accordingly? That seems messy to me though...
http://monobin.com/__d33cf45a4 - RegisterVm.cs (LoginVm.cs is pretty much the same as this)
http://monobin.com/__m69132f76 - RegPageVm.cs
Register.cshtml:
#model xxxx.ViewModels.RegPageVm
#{
View.Title = "Register";
Layout = "~/Views/Shared/_BareBones.cshtml";
}
<link rel="stylesheet" href="#Url.Content("~/Public/Css/signup.css")" type="text/css" />
<div id="sign-up-container">
<div id="sign-up-box">
<div id="sign-up-box-left">
<img src="#Url.Content("~/Public/Images/Signup_176x81.png")" />
</div>
<div id="sign-up-box-right">
#Html.Partial("_Register")
</div>
</div>
</div>
<div class="clear">
</div>
_Register.cshtml:
#model xxxx.ViewModels.RegisterVm
#using (Html.BeginForm("Capture", "Register", FormMethod.Post))
{
<table class="sign-up-box-inner">
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Email)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.Email, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Password)
</td>
<td class="field-area">
#Html.PasswordFor(x => x.Password, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.UserName)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.UserName, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td colspan="2">
<input type="image" src="../../Public/Images/Submit_150x47.png" class="submit-button" />
</td>
</tr>
</table>
#Html.AntiForgeryToken()
}
And finally RegisterController.cs:
public class RegisterController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Capture(RegisterVm registerVm)
{
if (!ModelState.IsValid)
{
return View("index", new RegPageVm()
{
LoginVm = new LoginVm(),
RegisterVm = registerVm
});
}
return RedirectToAction("index", "Event");
}
}
w://
You need to ensure that the form elements (like the textbox etc) should have the same id as the RegisterVM and LoginVM properties. Your theory is right but I think you might be making a mistake in the naming convention of MVC.
If you can share your view code + the VM classes, then we'll be able to help better.
EDIT:
Looking at your code I think you should be passing the view model to your partial view. Like for example the following line believe should be like this >
#Html.Partial("_Register", Model.RegisterVm)
According to your answer to nEEbz:
You are using:
Html.TextBoxFor(x=>x.LoginVM.Email) // i guess
this would turn into <input name="LoginVM.Email" ...>
Notice the LoginVM. part
Your login action probably looks like:
public ActionResult Login(LoginVM model) { }
so it expect field names like Email and Password, not LoginVM.Email and LoginVM.Password.
So you could could use Html.Textbox instead (so that the field name doesn't get autocreated).

Resources