Invoke a MVC Action from a Button? - asp.net-mvc

*First I want to know is it compulsory to have a view made for each and every Action method in a controller?
*How to Invoke a Action method in MVC4 when a button is clicked in another view? Do i need to have a view made for the Action method that I'm gonna invoke by pressing the button which is in another view.
Here is my code
CustomerController
public class CustomerController : Controller
{
//
// GET: /Customer/
List<Customer> CustomerCollection = new List<Customer>();
public CustomerController()
{
Customer cus = new Customer();
cus.CustomerId = 1;
cus.Name = "dath";
cus.Gender = "Male";
cus.City = "Csmbo";
CustomerCollection.Add(cus);
cus = new Customer();
cus.CustomerId = 2;
cus.Name = "Jacob";
cus.Gender = "FeMale";
cus.City = "Cosbo";
CustomerCollection.Add(cus);
cus = new Customer();
cus.CustomerId = 3;
cus.Name = "Gags";
cus.Gender = "Male";
cus.City = "NewYork";
CustomerCollection.Add(cus);
}
public ActionResult GetCustomerList()
{
return View(CustomerCollection);
}
public ActionResult GetCustomer(int id)
{
var selectedCustomer = CustomerCollection.Where(p => p.CustomerId == id).FirstOrDefault();
return View(selectedCustomer);
}
This is the Action method im gonna invoke by Pressing the button in the view called DeleteCustomer. For this Action method I haven't created any View
[HttpPost]
public ActionResult DeleteCus(int id)
{
var selectedCustomer = CustomerCollection.Where(o => o.CustomerId == id).FirstOrDefault();
CustomerCollection.Remove(selectedCustomer);
RedirectToAction("GetCustomerList", "Customer");
return View();
}
This is the DeleteCustomer Action method
public ActionResult DeleteCustomer(int id)
{
var selectedCustomer = CustomerCollection.Where(a => a.CustomerId == id).FirstOrDefault();
return View(selectedCustomer);
}
Finally this is the DeleteCustomer view that im passing the Customer seleted in DeleteCustomer Action method. And The Button is in this view. from this button i need to invoke the DeleteCus Action method(so it will remove the seleted Customer from the customerCollection List
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<myapp12.Models.Customer>" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title>DeleteCustomer</title>
</head>
<body>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>Customer</legend>
<div class="display-label">
<%: Html.DisplayNameFor(model => model.Name) %>
</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Name) %>
</div>
<div class="display-label">
<%: Html.DisplayNameFor(model => model.Gender) %>
</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Gender) %>
</div>
<div class="display-label">
<%: Html.DisplayNameFor(model => model.City) %>
</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.City) %>
</div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Delete" onclick="location.href='#Url.Action("DeleteCus", "Customer", new { id = Model.CustomerID })'"/>
<%: Html.ActionLink("Back to List", "GetCustomerList")%>
</p>
<% } %>
</body>
</html>
The thing that i have used in onClick event is not working. I need it to work so that selected Customer can be deleted.

You should store your data in a database, otherwise you cannot save changes.
If your data is created in collections in controller constructor it should all die when the page is given and created each time the page is loaded. Database data and things like memcached persist between page calls, usual variable do not.
Here is the code without View. But remove will not work as soon as CustomerCollection is a usual variable.
[HttpPost]
public ActionResult DeleteCus(int id)
{
var selectedCustomer = CustomerCollection.Where(o => o.CustomerId == id).FirstOrDefault();
CustomerCollection.Remove(selectedCustomer);
return RedirectToAction("GetCustomerList", "Customer");
}

Related

Asp.Net MVC 5 1 View 2 models with viewmodel The model item passed into the dictionary is of type error

I am new to Asp.Net MVC and I am coding a simple blog with using ASP.NET MVC 5 Framework. I can create edit and delete posts. You can see my code on GitHub in details. And I want to add comment property to Details page of every posts or articles. I spent so much time for this and tried several ways. I am trying to make it with using ViewModel Here is my code.
CommentVM:
public DateTime Date { get; set; }
public string CommentContent { get; set; }
public Article articles { get; set; }
public List<Comment> commentList { get; set; }// to show comments which is written before.
Details View:(I modified Details page of Articles. it was #model Blog.Models.Comment I turned to CommentVM and added model.articles.Title. So there is no error in Visual Studio.)
#model Blog.Models.CommentVM
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Article</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.articles.Title)
</dt>
<dd>
#Html.DisplayFor(model => model.articles.Title)
</dd>
.
.
.
</dl>
</div>
<div class="jumbotron">
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="col-md-10">
#Html.EditorFor(model => model.CommentContent, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
Of course this code is not enough. First of all I should write a controller for this. Default controller for this Details page is this:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Article article = db.Articles.Find(id);
if (article == null)
{
return HttpNotFound();
}
return View(article);
}
How will I change this Controller Method and View to create and show comments under articles? If you recommend good ViewModel tutorial, I will appretiate this. I want 3 things in Details page 1) Details of an article 2) Create comment 3) show under this comment as in forums or any blog. Please help
You should create a partial view for showing the comments, the model of that view being List<Comment> for displaying the list of comments.
For adding a new comment also can be done using a partial view which will have Comment as the model
Or you can follow the method mentioned in this post
CSHTML
<% using (Html.BeginForm(new { Action = "AddComment", postId = Model._id}))
{ %>
<h2>Title: <%= Model.Title%> </h2>
<%= Model.Body%>
<h3>Comments</h3>
<% if(Model.Comments.Count > 0)
{ %>
<% foreach (var comment in Model.Comments)
{ %>
Name: <%= comment.Name %>
Comment: <%= comment.Text %>
<% } %>
<%
}%>
<h4>Enter Comments</h4>
Name: <%= Html.TextBox("Name")%>
Comment: <%= Html.TextArea("Text")%>
<input type="submit" value="Submit" />
<% } %>

Pass object to partial view

I have this controller which fetches an object that I would like to render in a partial view:
public ActionResult EditPhoto(string id)
{
var photo = RavenSession.Load<ContentPage>(id);
return View("_editPhoto");
}
Its the photo I would like to pass to my partial view.
I have this in my view:
#{
Html.RenderPartial("_editPhoto" );
}
How will I go about to pass my photo into the partial view in order for it to render in its parent?
EDIT:
This is how I pass the object to the controller:
#foreach (var item in Model.Photographys)
{
<li class="span3" style="text-align: center">
<div class="thumbnail thumbnail-1">
#Html.ActionLink(item.Name,
"EditPhoto", // <-- ActionMethod
new { id = item.Id }, // <-- Route arguments.
null // <-- htmlArguments .. which are none. You need this value
// otherwise you call the WRONG method ...
// (refer to comments, below).
)
<h3 style="margin-bottom: 10px;">#item.Name</h3>
<div class="">
<div class="">
<img src="#item.ImgUrl" alt="" style="visibility: visible; opacity: 1;">
</div>
</div>
<section>
<p>#item.Description</p>
Read More
<p>#item.IsAccordion</p>
</section>
</div>
</li>
}
There seems a problem with this line however:
#{
Html.RenderPartial("_editPhoto" , Model);
}
Model gets underlined explaining that the Model passed into it (Photo) is not the right one..It seems that _editPhoto inherits the same Model as its parent maybe?
I managed to do this in the view:
#{
var i = new Photography();
Html.RenderPartial("_editPhoto", i);
}
The problem now is that the partialView gets rendered in a new window and not in its parent as I want it to.
UPDATE
Im gonna give this one last go, wont create a new question:
This is my controller passing a photo to a partial view:
public ActionResult EditPhoto(string id)
{
var photo = RavenSession.Load<ContentPage>(id) as Photography;
return PartialView("_editPhoto", photo);
}
My "mainview" contains this code to render the partial view with the photo getting sent to it:
<div class="form-control">
#{
var model = new Photography();
Html.Partial("_editPhoto",model);
}
</div>
This opens up a new window where my new photo shows up. I would like it to get rendered inside of its parents view the same way as it gets rendered automaticaly when i first visit the page...
Your controller action method should be:
public ActionResult EditPhoto(string id)
{
var photo = RavenSession.Load<ContentPage>(id);
return View("EditPhoto",photo);
}
and your "EditPhoto" view should be:
#{ Html.RenderPartial("_editPhoto",Model); }
Update
Your controller action method should be:
public ActionResult Photos()
{
return View();
}
public ActionResult EditPhoto(string id)
{
var photo = RavenSession.Load<ContentPage>(id);
return View(photo);
}
your "EditPhoto" should be view (not a partialview), on link click, "EditPhoto" action method is called and it returns the "EditPhoto" view
This questions seems related to one of your previous question.
Controller should be as follows;
public ActionResult EditPhoto(string id)
{
var photo = RavenSession.Load<ContentPage>(id);
return PartialView("_editPhoto", photo);
}
In your partial view _editPhoto, you can have the following code. I assume photo variable is a Photography object.
#model aPhoto_web.Models.AdminPages.Photography
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Photography</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
}
Thanks!

Post parameter is null

I Have controller with following methods:
public ActionResult Create()
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult Create(Tests test)
{
test.CreateDate = DateTime.Now;
test.Author = User.Identity.Name;
TestEntities db = new TestEntities();
db.AddToTests(test);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new { OrderNumber = 1, idTest = test.id });
}
[Authorize]
public ActionResult CreateQuestion(int OrderNumber,int idTest)
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult CreateQuestion(Questions question)
{
TestEntities db = new TestEntities();
db.AddToQuestions(question);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new {id = question.id, t = question.Type});
}
The problem is Create methods works right. It get parameter and adds it to DB. But similar method CreateQuestion displays message about question is null.
What do I wrong?
CreateQuestion view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<test.su.Models.Questions>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Создать вопрос
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Создать вопрос</h2>
<% using (Html.BeginForm("CreateQuestion","Test")) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Вопрос</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Type,"Тип вопроса") %>
</div>
<% // List of question types
List<SelectListItem> QuestionTypes = new List<SelectListItem>();
SelectListItem t = new SelectListItem();
t.Text = "Вопрос с вариантами ответа (флажки или радиокнопки)";
t.Value = "0";
QuestionTypes.Add(t);
t = new SelectListItem();
t.Text = "Вопрос со свободным ответом (текстовое поле)";
t.Value = "1";
QuestionTypes.Add(t);
%>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Type, QuestionTypes) %>
<%: Html.ValidationMessageFor(model => model.Type) %>
</div>
<%-- <div class="editor-label">
<%: Html.LabelFor(model => model.OrderNumber,"Порядковый номер вопроса") %>
<%: Html.EditorFor(model => model.OrderNumber) %>
<%: Html.ValidationMessageFor(model => model.OrderNumber) %>
</div>--%>
<div class="editor-label">
<%: Html.LabelFor(model => model.Question,"Текст вопроса") %>
</div>
<div class="editor-field">
<%: Html.TextAreaFor(model => model.Question,2,47,"") %>
<%: Html.ValidationMessageFor(model => model.Question) %>
</div>
<%: Html.HiddenFor(model => model.idTest) %>
<%: Html.ValidationMessageFor(model => model.idTest) %>
<%: Html.HiddenFor(model => model.OrderNumber ) %>
<%: Html.ValidationMessageFor( model => model.OrderNumber) %>
<p>
<input type="submit" value="Далее" />
</p>
</fieldset>
<% } %>
</asp:Content>
This is difficult to figure out without knowing the model. Someone else may provide a better answer, but here is the only thing I can think of for now:
If your Questions model looks like this:
public class Questions
{
int Id {get;set;}
string Name {get;set;}
string Description {get;set;}
}
What you can do, for now, is alter your controller to accept the individual parameters and create the object yourself. This might help you figure out which critical property in your Model is missing.
public ActionResult CreateQuestion(string Name, string Description)
{
//make the entity yourself
Questions newQuestion = new Questions()
{
Name = Name,
Description = Description
}
//your other code here
}
Now normally MVC is smart enough to bind your individual values in your form (view) to your model, but some critical value is missing and causing you issue. Once you've figured out what that is, you can actually restore your controller back to accepting only a Questions object.
Sorry I couldn't help you more.
Good Luck.

Create view is posting null objects

Should be an easy question to answer.
I am trying to create an object in a view. The class that contains the object consists of a User class and a password.
When I click on the submit button, the Controller picks up null values for Password and User.
See below the Container class, the Controller and the View;
public class UserExtended
{
public UserITOC User { get; set; }
public string Password { get; set; }
}
[Authorize]
public ActionResult Create()
{
return View(new UserExtended());
}
//
// POST: /Dinners/Create
[Authorize(Roles = "Administrator")]
[HttpPost]
public ActionResult Create(UserExtended user)
{
if (ModelState.IsValid)
{
// Create user in the User datatable
SqlUsersRepository sqlRepository = new SqlUsersRepository();
ITOCEntities db = new ITOCEntities();
db.UserITOCs.AddObject(user.User);
// Create user as an authenticated user within the Reader role.
int i = user.User.EmailAddress.IndexOf('#') - 1;
string userName = user.User.EmailAddress.Substring(0, i);
string email = user.User.EmailAddress;
Membership.CreateUser(userName, user.Password, email);
Roles.AddUserToRole(userName, "Reader"); // Automatically assigned as a Reader
}
return View(new UserExtended());
}
" %>
Create
<h2>Create</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.Forename) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.Forename)%>
<%: Html.ValidationMessageFor(model => model.User.Forename)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.Surname) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.Surname)%>
<%: Html.ValidationMessageFor(model => model.User.Surname)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.EmailAddress) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.EmailAddress)%>
<%: Html.ValidationMessageFor(model => model.User.EmailAddress)%>
</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="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
Extremely simple solution:
Change your action-signature from
public ActionResult Create(UserExtended user)
to
public ActionResult Create(UserExtended UserExtended)
That way the ModelBinder will know how to reassemble the object from Request.
Hope this helps!
I had a very similar problem, but found in my case that I had to match the database table name rather than the type name
Name of the type: NonTradingDay
Database table name: dbo.NonTradingDays (had been pluralized)
Create Method:
[HttpPost]
public ActionResult Create(NonTradingDay NonTradingDays)
{
if (ModelState.IsValid)
{
db.NonTradingDay.Add(NonTradingDays);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(NonTradingDays);
}
I had tried 'NonTradingDay', but still got null; I then looked at the database table name, tried 'NonTradingDays' and the mapping was made (the argument was no longer null).
I think this was because I had the database context as:
public DbSet<NonTradingDay> NonTradingDay { get; set; }
Rather than:
public DbSet<NonTradingDay> NonTradingDays { get; set; }
you are returning a new instance of UserExtended class
return View(new UserExtended());
instead return the object you get as the parameter
return user

MVC Validation Not Working In Web Forms Project

I have the following code in my aspx view page:
<% using (Html.BeginForm())
{
%>
<div>
CustomerCode:
<%= Html.TextBoxFor(x=> x.CustomerCode) %>
<%= Html.ValidationMessageFor(x => x.CustomerCode)%>
and this code in my model:
public class MyModel
{
[Required(ErrorMessage="customer code req")]
[StringLength(2,ErrorMessage="must be 2 u idiot")]
public string CustomerCode {get; set;}
Though if I enter more than 2 charachters in the textbox and submit the page, in the controller when I do:
if (ModelState.IsValid)
It always says its valid? What am I missing? I have put this MVC project inside a Web Forms project but the MVC project works fine, its just the validation which is not working, any ideas? Thanks.
Make sure that the controller action accepts the model as parameter:
public ActionResult SomeAction(MyModel model)
{
if (ModelState.IsValid)
{
}
return View();
}
Now if you invoke:
http://example.com/myapp/home/someaction?customercode=123
The model should not be valid.
Hmm, it works for me on a test page with the following
public ActionResult Test()
{
MyModel model = new MyModel();
return View(model);
}
[HttpPost]
public ActionResult Test(MyModel model)
{
if (ModelState.IsValid) { }
return View(model);
}
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.CustomerCode) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.CustomerCode) %>
<%: Html.ValidationMessageFor(model => model.CustomerCode) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
public class MyModel
{
[Required(ErrorMessage = "customer code req")]
[StringLength(2, ErrorMessage = "must be 2 u idiot")]
public string CustomerCode { get; set; }
}

Resources