MVC - view variable? - model-view-controller

Using an MVC pattern say I have a view and a controller:
Controller
User
View
User
login
logout
dashboard
The user controller has the following actions:
loginAction
logoutAction
dashboardAction
The login view has a simple login form, now my question:
Where should the form get its action url from?
Should this be hardcoded in the view such as:
<form action="/post.php" method="post">
It doesnt seem correct that the controller should tell the view, so where else could this go?

The controller tells the view everything it needs, and the view displays it. The view has no knowledge of the controller.
#using (Html.BeginForm("Login", "Account", FormMethod.Post, new { #class = "form-signin", ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<h2 class="form-signin-heading">Please sign in</h2>
<br />
#Html.TextBoxFor(m => m.UserName, new { #class = "input", type = "text", placeholder = "Username" })
<br />
#Html.PasswordFor(m => m.Password, new { #class = "input", type = "password", placeholder = "Password" });
<br /><br />
<button type="submit">Sign in</button>
}
In that login form, the link to the method on the controller is ("Login", "Account") where 'Login' is the method name and 'Account' is the controller name.

Related

ASP.net MVC 5 partial view Ajax POST not updating just the partial

I have a partial view that is not updating just the partial, it redirects to the action for the entire page.
In the partial view, _registerAccount.cshtml, that contains a post request to register, the request is made via Ajax in a view named _registerAccount as so:
#model LoginDemo.Models.LdapAccountModel
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
}))
{
#Html.ValidationSummary()
#Html.LabelFor(x => Model.Email) #Html.TextBoxFor(x => Model.Email, new { id = "reg-ytu-email" })
<br />
#Html.LabelFor(x => Model.Password) #Html.PasswordFor(x => Model.Password, new { id = "reg-pw" })
<input type="submit" value="Register" class="btn" />
}
In the parent page, Register.cshtml I have:
#model LoginDemo.Models.RegisterModel
...
<div class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
In the Account Controller the ajax request goes to the RegisterAccount action:
[HttpPost]
public async Task<ActionResult> RegisterLdapAccount(LdapAccountModel model)
{
if (model.exists()) // pseudo code
{
return Json(new {foo: "bar"}); // return address to redirect to
}
else
{
ModelState.AddModelError("", "You must have a valid account.");
return PartialView(model); // return error
}
}
The problem I have is that whatever gets returned wipes out the entire page as opposed to updating just the partial within the parent page. That is, if successful the JSON return only returns the JSON, if failed the partial view return only returns the partial.
n.b. I have <add key="UnobtrusiveJavaScriptEnabled" value="true" /> in my web.config.
Amend the following code as follows:
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "updatearea",
Amend the div to add the id:
<div id="updatearea" class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
Now make sure you have unobtrustive ajax as a script on the page if you don't already.
<script type="text/javascript" src="#Url.Content("/scripts/jquery.unobtrusive-ajax.min.js")"></script>
To add this script it must be in the scripts folder for your project.
Amend the controller so that you are loading the correct partial view, if you don't state the name of the partial view the partial view loaded will be whatever matches the name of the action, if no partial view matches the name of the action no partial view will be loaded. So explicitly state which partial view you want to load like this:
return PartialView("_RegisterAccount", model)

Should I be using Ajax forms in MVC partial views for adding new data in real time?

I want to know if there is a better way to accomplish what I am doing or if my current approach is ok. My current approach is giving me a little trouble so I need to see what I can do about it all.
In my MVC web application, I have dropdown lists which are searchable (handled by KendoUI Widgets) and I allow the user to add missing data to the database table which serves those dropdown lists.
Example of Widget
#(Html.Kendo().DropDownList()
.Name("Manufacturer")
.Filter("contains")
.OptionLabel("-- Select --")
.DataTextField("ManufacturerName")
.DataValueField("ManufacturerName")
.NoDataTemplate("No Data Add Manufacturer")
.DataSource(source => {
source.Read(read => {
read.Action("GetManufacturers", "Cars");
}).ServerFiltering(false);
}))
The data is added via an ajax form in a partial view which is displayed using a bootstrap 4.0 modal trigger by a button in the no data template (see above example).
These dropdown lists appear in both Create and Edit views, in the Create view they work fine and as expected but within the Edit views, they have dictionary errors.
Create View
#model MyProject.Models.Cars
#using (Ajax.BeginForm("Create", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "NotifySuccess",
OnFailure = "NotifyFailure"
},
new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
...Form goes here with widgets etc
}
#Html.Partial("_Manufacturer")
Popup form partial view
#model MyProject.Models.Manufacturer
<div class="modal fade" id="modal_addManufacturer">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
#using (Ajax.BeginForm("AddManufacturer", "Cars", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "Success",
OnFailure = "Fail"
}, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="form-group">
#Html.LabelFor(l => l.ManufacturerName, new { #Class = "form-label" })
#Html.TextBoxFor(i => i.ManufacturerName, new { #Class = "form-control" })
<input type="submit" value="Add" />
<input type="reset" value="Reset" />
</div>
}
</div>
</div>
</div>
</div>
These errors seem to stem from the fact that the Edit method in the controller passes an Id parameter. These leads me to the most obvious question, is this approach correct? Should I be using ajax forms in modals to create data on the fly like this especially when the models they use are causing problems when the Id parameter is used on views such as edit.
Can anyone offer some guidance on what I can do about this?

Ajax form not submitting to controller action

Ajax form is not submitting to controller action. Here is the code
#using (Ajax.BeginForm("searchCustomers", "Transaction", new { phoneNumber = Model.CustomerMobile }, new AjaxOptions
{
UpdateTargetId = "custList",
InsertionMode = InsertionMode.Replace
}))
{
<div class="col-md-6">
<div class="form-group">
<label>Customer Mobile No:</label>
#Html.TextBoxFor(x => x.CustomerMobile, new { #class = "form-control", id = "custMobile" })
</div>
#*<div class="form-group">
<label>Customer Name</label>
#Html.TextBoxFor(x => x.CustomerName, new { #class = "form-control", id = "custName" })
</div>*#
<input type="submit" class="btn btn-default" value="Get Customer Details" >
</div>
}
Here is the controller action
public ActionResult searchCustomers(string phoneNumber)
{
if (phoneNumber==null)
{
return PartialView(new List<Models.Customer>());
}
var c = Database.Session.Query<Models.Customer>()
.Where(x => x.MobileNumber.Like(phoneNumber) )
.ToList();
return PartialView(c);
}
but the ajax form is not submitting. I've added the JavaScript files as bundles. I've another #Html.Action("searchCustomers", new { phoneNumber = Model.CustomerMobile }) this one calls the controller action.
Everything is fine in your code. There are two javascript files that are needed for Ajax.Beginform to work.
jquery-{Vaersion}.js
jquery.unobtrusive-ajax.js
Check whether you have included those files to your view or not. Or if your view has any LayOut if those javascript files are included in your LayOut or not.

HttpPost not getting triggered

I have a website where I need to redirect the users according to their role. On button click, if the user is admin, redirect to another page; else reload the same page. On button click, the index page is loaded no matter who logs in. On debugging I found out, the [HttpPost] attribute is not triggered at all.
View:
#model namespace.ViewModels.LoginVM
#{
ViewBag.Title = "Login";
}
<h1>User Login</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<br />
<div style="background-color: skyblue; width: 50%">
<div style="padding-left: 1em">
<div class="display-label" style="font-size: large">
Enter User Info<br />
<br />
</div>
<div>
<div class="editor-label">#Html.LabelFor(model => model.empID)</div>
<div class="editor-field">#Html.TextBoxFor(model => model.empID)
#Html.ValidationMessageFor(model => model.empID)
</div>
<br />
</div>
<br />
<div>
<input id="submit" type="submit" value="Submit" />
</div>
</div>
</div>
<br />
}
Controller:
public class LoginController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginVM model)
{
MySQL msql = new MySQL();
var empID= model.empID
var role = msql.Select("Select `role` from empDB where `eID` = '" + empID + "'");
if(role == "admin")
{
return RedirectToAction("Index","Home");
}
else
{
return View();
}
}
}
Your HttpPost action method name is Login. But your razor view, you used Index!
Update your Html.BeginForm method call to have the correct action method name and controllername values. Then when you click on submit, it will post the form data to /Login/Login
#using (Html.BeginForm("Login", "Login", FormMethod.Post))
{
}

MVC 4 Updating a partial view from another partial view using Ajax.BeginForm()

I have a comment section set up on one of my pages. The parent view has a partial view which shows the comments for that ID and gives the option to display another partial view to post a comment. When someone post a comment I want the first partial view within the parent to refresh displaying the new comment.
Currently when you click Post Comment, the AddComment method is called and added to the database. I get an error saying that I am passing the wrong type of model to the view. It seems to be trying to pass the return value to my AddComment partial view instead of injecting it into Partent View Div.
Parent View
#model QIEducationWebApp.Models.Course
#{
ViewBag.Title = "Course Details";
}
<h1 class="page-header">#ViewBag.Title</h1>
Javascript is here
.
.
.
<table class="table">
DETAILS HERE
</table>
<ul id="view-options">
<li>#Html.ActionLink("Back to Courses", "Index", "Course")</li>
</ul>
<input type="button" id="View" class="ShowComment" value="Show Comments"/>
<div id="CommentSection"/>
Partial View to view comments
Javascript is here
.
.
.
<div class="CommentSection">
#foreach (var item in Model)
{
<div class="Comment">
<div class="CommentText">
#Html.DisplayFor(modelItem => item.CommentText)
</div>
<div class="CommentSep">
<span class="Commenter">#Html.DisplayFor(modelItem => item.UserName)</span> - <span class="CommentDate">#Html.DisplayFor(modelItem => item.CommentDate)</span>
</div>
</div>
}
<input type="button" id="Post" class="AddComment" value="Add a Comment"/>
<br />
<br />
</div>
<div id="AddComment" />
<br />
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("ViewComments",
new { courseID = #ViewBag.courseID, page }),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(
new PagedListRenderOptions { MaximumPageNumbersToDisplay = 5, DisplayLinkToFirstPage = PagedListDisplayMode.IfNeeded,
DisplayLinkToLastPage = PagedListDisplayMode.IfNeeded },
new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "CommentSection" }))
Method behind the is partial view
public PartialViewResult ViewComments(int courseID, int? page = 1)
{
ViewBag.courseID = courseID;
var coursecomments = db.CourseComments.Where(cc => cc.CourseID == courseID);
int pageSize = 10;
int pageNumber = (page ?? 1);
return PartialView(coursecomments.OrderByDescending(cc => cc.CommentDate).ToPagedList(pageNumber, pageSize));
}
Partial to Post Comment
Javascript is here
.
.
.
#using (Ajax.BeginForm("AddComment", "CourseComment", new { courseID = #ViewBag.courseID, userName = #User.Identity.Name },
new AjaxOptions { UpdateTargetId = "CommentSection" }))
{
#Html.ValidationSummary(true)
<div class="NewComment">
<div class="editor-field">
#Html.TextAreaFor(model => model.CommentText, new { maxLength = 500 })
#Html.ValidationMessageFor(model => model.CommentText)
</div>
<input type="submit" class="PostComment" value="Post Comment" />
<div id="Counter" class="CommentCounter"/>
</div>
}
Controller method linked to the Post Comment Ajax.BeginForm()
public PartialViewResult AddComment(CourseComment coursecomment, int courseID, String userName)
{
coursecomment.CommentDate = System.DateTime.Now;
coursecomment.CourseID = courseID;
coursecomment.UserName = userName;
if (ModelState.IsValid)
{
db.CourseComments.AddObject(coursecomment);
db.SaveChanges();
}
ViewBag.courseID = courseID;
return ViewComments(courseID);
}
Adding pictures
Details
After selecting View Comments button
After selecting Add Comment
After Posting the the comment I want the list of Comments to refresh displaying the newly added Comment. Like So
For now I have it changed. I wanted to the comments section to be hidden until the show comments was clicked. Then after posting a comment on the comments section was refreshed, but I couldn't get that to work. So just reloading the whole page will refresh the comments section, but make it hidden at that time. I made it so that the comments section shows by default without the option to hide it. So unless anyone can figure out a way to get it to work how I wanted, this works for now.

Resources