Page with Multiple Submit Buttons and one Get/Post Action Method - asp.net-mvc

I am new to MVC, so please forgive me if I am being so noob :).
In my new project, I want to make a 'Create Song' page which, of course, creates a new song. In model design, one song can have many artists. So, on the create song page, a user should be able to search for artists and add artists from the search results by pressing the 'Add' links of artists in the search result.
Currently, I have two submit buttons in form which are "Submit" and "SearchArtist" and they call http POST "Create" action method. A ViewModel object(CreateSongScrnData) is used to post the screen data. And it's all working ok. But when I try to add an artist from Artist search result, using #Url.Action passing ViewModel data to "Create" http get method, the viewmodel object parameter is always null when it come into the actiona method. Please help me with some advice and enlighten me if I am missing some concepts. Thank you so much in advance.
Code is as follows.
public ActionResult Create(CreateSongScrnData modelData, Int32? artistIDToAdd)
{
if (modelData != null && artistIDToAdd != null)
{
var artist = db.Artists.Find(artistIDToAdd);
modelData.Song.Artists.Add(artist);
}
ViewBag.GenreID = new SelectList(db.Genres, "GenreID", "Name");
ViewBag.AlbumID = new SelectList(db.Albums, "AlbumID", "Name");
return View(modelData);
}
[HttpPost]
public ActionResult Create(CreateSongScrnData modelData)
{
switch (modelData.SubmitCommand)
{
case "AddNewSong":
if (ModelState.IsValid)
{
db.Songs.Add(modelData.Song);
db.SaveChanges();
return RedirectToAction("Index");
}
break;
default:
modelData.SearchResult = db.Artists.Where(a => a.Name.Contains(modelData.ArtistSearchString)).ToList();
break;
}
ViewBag.GenreID = new SelectList(db.Genres, "GenreID", "Name", modelData.Song.GenreID);
ViewBag.AlbumID = new SelectList(db.Albums, "AlbumID", "Name", modelData.Song.AlbumID);
return View(modelData);
}
Code snippet of search in the view is as follows:
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Song.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Song.Name)
#Html.ValidationMessageFor(model => model.Song.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Song.MyanmarName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Song.MyanmarName)
#Html.ValidationMessageFor(model => model.Song.MyanmarName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Song.Genre)
</div>
<div>
#Html.DropDownList("GenreID", "Choose Genre")
#Html.ValidationMessageFor(model => model.Song.GenreID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Song.AlbumID, "Album")
</div>
<div class="editor-field">
#Html.DropDownList("AlbumID", "Choose Album")
#Html.ValidationMessageFor(model => model.Song.AlbumID)
</div>
<div class="editor-label">
<p>Sing by this artists:</p>
#if (Model.AddedArtists != null)
{
<table><tr><th>Name</th></tr>
#foreach (var item in Model.AddedArtists)
{
<tr><td>#item.Name</td></tr>
}
</table>
}
</div>
<div style=" border-top:1px solid #ccc; width: 400px; height:auto; margin-top:30px; margin-bottom:30px;"></div>
<div>
<p>Search and add artists</p>
#Html.TextBoxFor(model => model.ArtistSearchString)
<input type="submit" name="SubmitCommand" value="SearchArtist" class="cancel" />
#if (Model.SearchResult != null)
{
<div>
<table><tr><th>Name</th><th></th></tr>
#foreach (var item in Model.SearchResult)
{
<tr><td>#item.Name</td>
<td>Add</td>
</tr>
}
</table>
</div>
}
</div>
<div style=" border-top:1px solid #ccc; width: 400px; height:auto; margin-top:30px; margin-bottom:30px;"></div>
<p>
<input type="submit" name="SubmitCommand" value="AddNewSong" />
</p>
}

I think you are mixing too things in a single form.
Solution 1)
Create a first step where user insert data and create song.
Create a second step where user add artists to the song.
Solution 2)
Let to the submit button the function to store data.
For the search of artist use a ajax compnent like this:
http://harvesthq.github.com/chosen/

Related

How to validate a duplicate post request from a form in MVC

I am having an form which insert a record whenever a post request is made,but the problem is that if someone clicks submit button more than 1 times than duplicate post request are made and at the end same records are getting inserted. I dont want to check that the record is already present or not because the record would be different always. I tried using ValidateAntiForgeryToken filter in controller but it is failing to validate the requests, Below is my View Code.
#using (Html.BeginForm("Create", "Home",FormMethod.Post,new { onkeydown = "return event.keyCode!=13" }))
{
#Html.AntiForgeryToken()
<div class="right-col">
#Html.TextBoxFor(model => model.Name, new { placeholder = "Name", #class = "small-box" })
</div>
<div class="left-col">Email Id :</div>
<div class="right-col">
#Html.TextBoxFor(model => model.EmailId, new { placeholder = "Email Id", #class = "small-box",id="resumeemailid" })
#Html.ValidationMessageFor(model => model.EmailId)
</div>
<div class="left-col">Address :</div>
<div class="right-col">
#Html.TextAreaFor(model => model.Address, new { placeholder = "Address", #class = "small-box" })
</div>
<div class="buttons resume-threebutton">
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Upload", "Upload")" name="Command" />
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Button.UploadandAdd", "Upload And Add New")" name="Command" />
<input type="button" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Cancel", "cancel")" name="register-button" onclick="location.href='#Url.Action("SelectTemplate", "CustomerTemplate")'" />
</div>
}
and below is my controller Post method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProductModel model)
{
//To do add the product here...
}

How to get a form value in another form value submission

I had username and password in first form and retrieve password in another form , in which i want userame entered in first form in submission of second form.
#model Network.Models.LoginDetail
<script type="text/javascript">
</script>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<p>
Please enter your user name and password. #Html.ActionLink("Register", "Register") if you don't have an account.
</p>
#using (Html.BeginForm("Index","Student",FormMethod.Post)) {
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Username)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Username)
#Html.ValidationMessageFor(model => model.Username)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Log in" style="width: 200px"/>
</p>
#ViewBag.Message
</fieldset>
</div>
}
#using (Html.BeginForm("RetrievePassword","Student",FormMethod.Post)) {
<p>
Forgot password? <input type="submit" onclick="updateUsername();"value="Click Here" style="width: 150px"/> Entering your username to retrieve your password.
</p>
#Html.HiddenFor(model => model.Username)
}
How can we acheive this, i tried in javascript capturing of username in hiddenfield but not working.
Or can form within form be used to acheive this.
Please provide a solution.
Thanks,
Michaeld
At the post method of "Index" action in "Stundent" controller you will be able to get the value either in formcollection or in LoginDetail object form.
Example:
public ActionRestult Index(FormCollection FC)
{
string UserName = FC["Username"];
string Password = FC["Password"];
}
Or Alternatively
public ActionRestult Index(LoginDetail obj)
{
string UserName = obj.Username;
string Password = obj.Password;
}
This will fix your concern.

Change method call order when form is posted in MVC

a bit of a strange one here. I've got a blog that's another 'dip my toe into MVC' project that will highlight the benefits of our new Intranet. I have a typical blog post page with the article, comments and a form to submit your comments against a given article.
I have a stringly typed main View ("Post") which has the article content, then two Html.RenderAction methods; one to get the comments and one to add comments via a form.
My issue is that when a comment is posted, my GetComments method is called before AddComment, so when the page is refreshed the new comment isn't visible although it has been added to the database. A quick F5 confirms this. I understand that GetComments is being called first due to it being declared first in the view but I'm not sure how to tell the view to do an add before a get.
Here's my code:
Controller:
public ActionResult AddComment()
{
return PartialView("AddComment");
}
[HttpPost]
public ActionResult AddComment(Comment comment)
{
comment.DateSubmitted = DateTime.Now;
db.Comments.Add(comment);
db.SaveChanges();
return PartialView(comment);
}
public ActionResult GetComments(int articleid)
{
var comments = db.Comments.Where(c => c.ArticleID == articleid).ToList();
return PartialView(comments);
}
Post view
#model IntranetBlog.Models.Article
#{
ViewBag.Title = "Post";
}
<div class="row">
<div class="span12">
<h3>#Html.DisplayFor(modelItem => Model.Title)</h3>
<small>by Ruth Barlow on #Html.DisplayFor(modelItem => Model.DateCreated)</small>
#if (Model.Image != null)
{
<p>
<img src="#Url.Action("GetImage", "Home", new { articleID = Model.ArticleID })" alt="" width="150" height="150" />
</p>
}
<div>
#Html.DisplayFor(modelItem => Model.Body)
</div>
<small>Posted under #Html.DisplayFor(modelItem => Model.Category.Name)</small>
</div>
<div class="span12">
#{
Html.RenderAction("GetComments", "Home", new { articleID = Model.ArticleID });
}
</div>
<div class="span12">
#{
Html.RenderAction("AddComment", "Home", new { articleID = Model.ArticleID });
}
</div>
</div>
GetComments partial:
#model IEnumerable<IntranetBlog.Models.Comment>
#if (Model.Any())
{
<h3>What you're saying</h3>
foreach (var item in Model)
{
<div>
Comment: #Html.DisplayFor(modelItem => item.Body)
</div>
<div>
Submitted by: #Html.DisplayFor(modelItem => item.SubmittedBy)
on #Html.DisplayFor(modelItem => item.DateSubmitted)
</div>
<hr />
}
}
else
{
<p>There are no comments for this post. Why not add one?</p>
}
AddComment partial
#model IntranetBlog.Models.Comment
#using (Html.BeginForm())
{
<h3>Why not leave us a comment?</h3>
#Html.ValidationSummary()
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Body, 20, 20, null)
#Html.ValidationMessageFor(model => model.Body)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SubmittedBy)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SubmittedBy)
#Html.ValidationMessageFor(model => model.SubmittedBy)
</div>
<p>
<input type="submit" value="Add comment" id="AddComment" class="btn btn- primary" />
</p>
</fieldset>
}
Hope this makes sense.
Thanks in advance.
The trick is to use Html.Action instead of Html.RenderAction this will allow you to store the result in a variable and then add it to the display where it is needed.
This will allow you to generate the PartialView in the logical order you need, while displaying them in an other order.
See this post for a quick example on how to do it : https://stackoverflow.com/a/13301057/971693
I would suggest to you a slightly different approach. Instead of using Html.BeginForm, think about using Ajax.BeginForm to submit the comment. Being ajax, it will have better performance as it allows your method to just return the comments so you can replace the old ones, or even just the newly added one so it can be added to the bottom of the list. Having said that, this solution does rely on the use of javascript and preferably jquery-unobtrusive-ajax to work and render decent looking client code. You don't have to know javascript to use this method thanks to the AjaxOptions class which has some powerful yet easy to use options built into it.

Data from view to different controller

2 Points
3 Posts
Data from view to different controller
1 minute ago|LINK
Hello friends
I'm from Colombia, sorry for the writing
I have a problem I do not know how to connect two controllers from one view, I'm using EF Data Base First, this automatic genre classes to my model, one of these classes is called "UNIVERSITY" which is a table of the database where are all the universities, and another class is "CAMPUS_UNIVERSITY" where are all the campus of a university, a university can have multiple campus
I have 2 controllers and their associated views
The first controller is "University" (I think i not necessary show) and your view "Index" (list all Universidadades). That is this:
#model IEnumerable<RolesMVC3.Models.UNIVERSITY>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Nombre
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.ActionLink("Add Campus", "Create", "CampusUniversity" new { id=item.IdUniversity }) |
#Html.ActionLink("Edit", "Edit", new { id=item.IdUniversity }) |
#Html.ActionLink("Delete", "Delete", new { id=item.IdUniversity })
</td>
</tr>
}
</table>
The link "Add Campus" routed to controller "CampusUniversity" to the action "Create". That is this:
public ActionResult Create()
{
ViewBag.IdCityCampus = new SelectList(db.CITY_CAMPUS, "IdCityCampus", "Name");
ViewBag.IdUniversity = new SelectList(db.UNIVERSITY, "IdUniversity", "Name");
return View();
}
//
//
[HttpPost]
public ActionResult Create(CAMPUS_UNIVERSITY campus_university)
{
if (ModelState.IsValid)
{
db.CAMPUS_UNIVERSITY.AddObject(campus_university);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.IdCityCampus = new SelectList(db.CIUDAD_SEDE, "IdCityCampus", "Nombre", campus_university.IdCityCampus);
ViewBag.IdUniversity = new SelectList(db.UNIVERSIDAD, "IdUniversity", "Nombre", campus_university.IdUniversity);
return View(campus_university);
}
And the associated view (View "Create" Controller " CampusUniversity ") is:
#model RolesMVC3.Models.CAMPUS_UNIVERSITY
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<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>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>SEDE_UNIVERSIDAD</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdUniversity, "UNIVERSIDAD")
</div>
<div class="editor-field">
#Html.DropDownList("IdUniversity", String.Empty)
#Html.ValidationMessageFor(model => model.IdUniversity)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IdCityCampus, "CITY_CAMPUS")
</div>
<div class="editor-field">
#Html.DropDownList("IdCityCampus", String.Empty)
#Html.ValidationMessageFor(model => model.IdCityCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AddressCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AddressCampuse)
#Html.ValidationMessageFor(model => model.AddressCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneCampus)
#Html.ValidationMessageFor(model => model.PhoneCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MailCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MailCampus)
#Html.ValidationMessageFor(model => model.MailCampus)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I want to do that by clicking "Add Campus" appears the name of the university comes fromthe table or class "UNIVERSITY" in the view Create (controller "SedeUniversidad") and that can save the campus of the university and not as I have now, because I have to choose the university of a DropDownList, how I can do?
Thank you, blessings!
I can't understand some of your English. It sounds like you want to send data from your Create view to your University controller. You can make the POST url of your form go wherever you want by putting the following values in your HTML.BeginForm statement in your Create view.
#using (Html.BeginForm("ActionName", "ControllerName"))

JQuery UI Tab with form in ASP.NET MVC 3

I try to make user registation form. I have two user types and want to make two JQuery UI tabs with forms. But tab is empty and in java script console error "GET http://localhost/ParcDocs/Admin/Users/AddWorker 500 (Internal Server Error)".
Code of user registration page:
<script type="text/javascript">
$(document).ready(function() {
$("#tabContainer").tabs();
});
</script>
<div id="tabContainer">
<ul>
<li>#Html.ActionLink("Пользователь", "AddUser", "Users", null, null)</li>
<li>#Html.ActionLink("Сотрудник", "AddWorker", "Users", null, null)</li>
</ul>
</div>
PartialView code:
#model ParcDocs.Models.WorkerUser
#using (Html.BeginForm("AddWorker", "Users"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Пользователь</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.RoleId, ((IEnumerable<ParcDocs.Models.Role>)ViewBag.PossibleRoles).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.Id.ToString(),
Selected = (Model != null) && (option.Id == Model.RoleId)
}), "Выберете роль пользователя")
</div>
<p>
<input type="submit" value="Добавить" />
</p>
</fieldset>
}
Controller code:
public ActionResult AddWorker()
{
var model = new WorkerUser();
return PartialView(model);
}
Same behavior this second tab.
You should be returning a PartialViewResult, rather than an ActionResult. Put a breakpoint on public ActionResult AddWorker() and see what exception you get. Paste it here so that we have more information.

Resources