How to call a method from the View? MVC - asp.net-mvc

I have a View with a <input type="submit" value="Create" /> when a User click create the Action Method should be activated and the Result written in the db.
At the moment when a User click Create Button in the View nothing happen. Could you tell me what I'm doing wrong? thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestGuestBook.Models;
using TestGuestBook.Models.Repositories;
using TestGuestBook.ViewModels;
namespace TestGuestBook.Controllers
{
[HandleError]
public class HomeController : Controller
{
ICommentRepository _repository;
public HomeController()
{
_repository = new CommentRepository();
}
// Dependency Injection enabled constructors
public HomeController(ICommentRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
// Get all Comments
List<Comment> commentItems = _repository.FindAll().ToList();
// Create the ViewModel and associate the list of comments
CommentListCreateViewModel viewModel = new CommentListCreateViewModel();
viewModel.CommentItems = commentItems;
return View(viewModel);
}
public ActionResult Create()
{
CommentListCreateViewModel createViewModel = new CommentListCreateViewModel();
return View(createViewModel);
}
[HttpPost]
public ActionResult Create(CommentListCreateViewModel createViewModel)
{
if (ModelState.IsValid)
{
Comment comment = new Comment
{
Nominative = createViewModel.Nominative,
Email = createViewModel.Email,
Content = createViewModel.Content
};
_repository.Add(comment);
_repository.Save();
}
return View();
}
}
}
View
#model TestGuestBook.ViewModels.CommentListCreateViewModel
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>ListAddCommentsViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Nominative)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Nominative)
#Html.ValidationMessageFor(model => model.Nominative)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<table>
<tr>
<th>
Nominative
</th>
<th>
Email
</th>
<th>
Content
</th>
<th>
</th>
</tr>
#foreach (var item in Model.CommentItems)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nominative)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
</td>
</tr>
}
</table>

You need to direct the form to your Create controller method:
#using (Html.BeginForm("Create", "Home"))

You can leave it as Html.BeginForm() and after the save, call return RedirectToAction("Index"); The added item should now show in the list. It was probably saving all along, it just wasn't being re-directed to the Index view afterwards.

Related

issue with foreign key in asp.net mvc?

I am facing a referance issue
empid is not insert in the table when employee generate the experiance then not display the experiance data on the index page?
HomeController.cs
public class HomeController : Controller
{
private readonly dbozeeEntities dbemp;
public HomeController()
{
dbemp = new dbozeeEntities();
}
// GET: Home
public ActionResult Index()
{
var list = dbemp.employees.ToList();
return View(list);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(employee emp)
{
var create = dbemp.employees.Add(emp);
dbemp.SaveChanges();
return RedirectToAction("Experiance", new { empId = emp.empid }); //here going to experiance page
}
public ActionResult Experiance(employee emps)
{
//ViewData["empid"] = emps.empid;
return View(new experiance() { empid = emps.empid });
}
[HttpPost]
public ActionResult Experiance(experiance exp,employee emps)
{
//ViewData["empid"] = emps.empid;
var create = dbemp.experiances.Add(exp);
dbemp.SaveChanges();
return RedirectToAction("Index");
}
Index.cshtml
#model IEnumerable<DemoOzeeTechno.Models.employee>
#using DemoOzeeTechno.Models
#{
ViewBag.Title = "Index";
IEnumerable<experiance> exp = ViewData["empid"] as IEnumerable<experiance>;
}
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.empname)
</th>
<th>
#Html.DisplayNameFor(model => model.emailaddress)
</th>
<th>
#Html.DisplayNameFor(model => model.contactno)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.empname)
</td>
<td>
#Html.DisplayFor(modelItem => item.emailaddress)
</td>
<td>
#Html.DisplayFor(modelItem => item.contactno)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.empid }) |
#*#Html.ActionLink("Details", "Details", new { id=item.empid }) |*#
#Html.ActionLink("Delete", "Delete", new { id=item.empid })
</td>
</tr>
}
</table>
<table>
<tr>
<th>CompanyName</th>
<th>YearOfExperiance</th>
</tr>
#if (ViewData["empid"] != null)
{
foreach (experiance ex in exp)
{
<tr>
<td>#ex.companyname</td>
<td>#ex.yearofexp</td>
</tr>
}
}
</table>
Experiance.cshtml
#model DemoOzeeTechno.Models.experiance
#{
ViewBag.Title = "Experiance";
}
<h2>Experiance</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>experiance</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.companyname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.companyname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.companyname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.yearofexp, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.yearofexp, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.yearofexp, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#* #Html.LabelFor(model => model.empid, "empid", htmlAttributes: new { #class = "control-label col-md-2" })*#
<div class="col-md-10">
#Html.HiddenFor(model => model.empid)
#*#Html.DropDownList("empid", null, htmlAttributes: new { #class = "form-control" })*#
#Html.ValidationMessageFor(model => model.empid, "", new { #class = "text-danger" })
</div>
</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>
#Html.ActionLink("Back to List", "Index")
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Database Design:
experiance data inserted in table but issue is Does not Displaying the experiance data in index page
Watch Window:
empis is not insert in the table and experiance data not display on the page that is the issue??
First, you should know that ViewData get loss data while redirection from one action to another, So you have two options to pass empid from one Action to another one is to use Session and other is pass data in query string. So I would prefer a query string. So here is how you can do this.
First, you need to pass created empid to Experience action by the query string.
[HttpPost]
public ActionResult Create(employee emp)
{
var create = dbemp.employees.Add(emp);
dbemp.SaveChanges();
return RedirectToAction("Experiance",new{empId=emp.id}); //here going to experiance page
}
Now pass data to your view so that it post this id with newly created experience.
public ActionResult Experiance(int empId)
{
return View(new experiance(){empid=empId});
}
In the view you need a hidden field which will store this id into create experience form and submit along with experience fields.
#Html.HiddenFor(model=>model.empid)
Now in you Experience post-action you don't need to set empid explicitly it will get it from posted form values.
[HttpPost]
public ActionResult Experiance(experiance exp)
{
var create = dbemp.experiances.Add(exp);
dbemp.SaveChanges();
return RedirectToAction("Index");
}
Updated
To show the experience table on index page get all the experience list from the database and store it to ViewData.
// GET: Home
public ActionResult Index()
{
var list = dbemp.employees.ToList();
ViewData["empid"]=dbemp.experience.ToList();
return View(list);
}

MVC ViewModel collections are null on postback

I have a view model which contains a class reference and 2 IEnumerable collections.
public class BuildingTypeViewModel
{
public Static_Item BuildingType { get; set; }
public IEnumerable<Reading_Type> ReadingTypes { get; set; }
public IEnumerable<Building_Type_Reading> BuildingReadings { get; set; }
}
I populate this ViewModel in the Edit action on the controller
public ActionResult Edit(int id)
{
Static_Item staticItem = db.Static_Item.Find(id);
BuildingTypeViewModel model = new BuildingTypeViewModel
{
BuildingType = staticItem,
ReadingTypes=db.Reading_Type.ToList(),
BuildingReadings = db.Building_Type_Reading.Where(bt => bt.UN_Building_Type == staticItem.UN_Building_Type).ToList()
};
return View(model);
}
Building type on the view model is a class with an ID and Description and the data would be something like this:
UN_Building_Type=1, Description = "Hospital"
The IEnumerable of Reading_Type's would be like this:
UN_Reading_Type = 1, Description = "Electric"
UN_Reading_Type = 2, Description = "Gas"
The IEnumerable of Building_Type_Readings would be like this:
UN_Building_Type_Readings=1, UN_Building_Type=1, UN_Reading_Type = 1, Typical=300, Good=150
UN_Building_Type_Readings=2, UN_Building_Type=1, UN_Reading_Type = 2, Typical=800, Good=400
I load this data into my view:
#model SSE.Enterprise.EE_Web_Portal.Models.BuildingTypeViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Static_Item</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.BuildingType.UN_Building_Type)
<div class="form-group">
#Html.LabelFor(model => model.BuildingType.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BuildingType.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BuildingType.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2">Building Readings</label>
<div class="col-md-10">
<table class="table">
<tr>
<th/>
<th>
#Html.LabelFor(model=>model.BuildingReadings.FirstOrDefault().Typical)
</th>
<th>
#Html.LabelFor(model => model.BuildingReadings.FirstOrDefault().Good)
</th>
</tr>
#foreach (var item in Model.ReadingTypes)
{
<tr>
<td>
#Html.Label(item.Description)
</td>
<td>
#Html.EditorFor(model => model.BuildingReadings.FirstOrDefault(b => b.UN_Reading_Type == item.UN_Reading_Type).Typical, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(model => model.BuildingReadings.FirstOrDefault(b => b.UN_Reading_Type == item.UN_Reading_Type).Good, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</table>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Here is my edit postback method.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "BuildingType")] BuildingTypeViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
When the page is posted back the 2 IEnumerable collections are null so I'm not able to save the data that has been entered.
Any idea?
Ta
First of all, by specifying the attribute Bind(Include = "BuildingType") you're telling MVC to only bind this single property. Remove the attribute, and MVC will try to bind your 2 IEnumerable collections.
Next, check your #Html.EditorFor calls. I'm not sure MVC can understand FirstOrDefault inside. Try avoiding LINQ selectors inside your view.
And after that, as #will mentioned, try changing IEnumerable to List.

asp.net mvc onr-to-many details partial view in master main view

I am sorry if im asking same thing for the nth time but i can not find the answer to my question...
I have problem adding partial views...
I have One-to-Many relation in the database tables.
My Model is:
using System;
using System.Collections.Generic;
public partial class Job
{
public Job()
{
this.Flights = new HashSet<Flight>();
}
public int JobID { get; set; }
public string JobNumber { get; set; }
public int ClientID { get; set; }
public virtual Client Client { get; set; }
public virtual ICollection<Flight> Flights { get; set; }
}
My Controller (Create):
// GET: /Jobs/Create
public ActionResult Create()
{
ViewBag.ClientID = new SelectList(db.Clients, "ClientID", "ClientName");
return View();
}
And View (for create Job):
#model AOG.Models.Job
<div class="form-horizontal">
<h4>Job</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.JobNumber, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.JobNumber)
#Html.ValidationMessageFor(model => model.JobNumber)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ClientID, "ClientID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ClientID", String.Empty)
#Html.ValidationMessageFor(model => model.ClientID)
</div>
</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>
Now if i add partial view (Generated Partial List View) On Create Job Page:
#html.Partial("_PartialFlights");
I get an error: Object reference not set to an instance of an object on
Line 23: #foreach (var item in Model) {
in my partial view. This is the code:
#model IEnumerable<AOG.Models.Flight>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FlightName)
</th>
<th>
#Html.DisplayNameFor(model => model.FlightETD)
</th>
<th>
#Html.DisplayNameFor(model => model.FlightETA)
</th>
<th>
#Html.DisplayNameFor(model => model.Job.JobNumber)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FlightName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FlightETD)
</td>
<td>
#Html.DisplayFor(modelItem => item.FlightETA)
</td>
<td>
#Html.DisplayFor(modelItem => item.Job.JobNumber)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.FlightID }) |
#Html.ActionLink("Details", "Details", new { id=item.FlightID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.FlightID })
</td>
</tr>}</table>
How ever If i put this in the details view:
#foreach (var item in Model.Flights)
{
<div>
<table>
<tr><th>Flight</th><th>ETD</th><th>ETA</th></tr>
<tr>
<td>#Html.DisplayFor(modelItem => item.FlightName)</td>
<td>#Html.DisplayFor(modelItem => item.FlightETD)</td>
<td>#Html.DisplayFor(modelItem => item.FlightETA)</td>
</tr></table>
</div>
}
It shows everything I need, but i want to learn how to do it with the partial views.
Thank you all so much!
You need to pass an IENumerable<Flight> instance to your partial view, so in stead of:
#html.Partial("_PartialFlights");
...do this:
#html.Partial("_PartialFlights", Model.Flights);

How to add a list to a View Model MVC

I'm using MVC 3 with View Model, in my case I have a View Model that should display a list of items and also a form for inserting some input.
I have problem in my View because I'm not able to associate the Form for inserting the data with the view model, could you tell me what I'm doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using TestGuestBook.Models;
namespace TestGuestBook.ViewModel
{
public class ListAddCommentsViewModel
{
public int CommentId { get; set; }
[Required]
public string Nominative { get; set; }
[Email]
public string Email { get; set; }
[Required]
public string Content { get; set; }
public List<Comment> CommentItems { get; set; }
}
}
View
#model IEnumerable<TestGuestBook.ViewModel.ListAddCommentsViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ListAddCommentsViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CommentId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CommentId)
#Html.ValidationMessageFor(model => model.CommentId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Nominative)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Nominative)
#Html.ValidationMessageFor(model => model.Nominative)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
CommentId
</th>
<th>
Nominative
</th>
<th>
Email
</th>
<th>
Content
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CommentId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Nominative)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
You dont need to pass a Collection to your View. Only one object of the ViewModel is enough. Your ViewModel already have property to holde the collection (List of Comments)
So in your GET Action, return only one instance of this viewModel to the View
public ActionResult GetComments(int postId)
{
var viewModel=new ListAddCommentsViewModel();
viewModel.CommentItems =db.GetComments(postId);
return View(viewModel);
}
and now in your View, Let it bind to a single instance of ListAddCommentsViewModel
#model TestGuestBook.ViewModel.ListAddCommentsViewModel
And Inside your view, to Show your List of comments, use the Collection type property (Model.CommentItems) in your ViewModel
#foreach (var item in Model.CommentItems) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CommentId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Nominative)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { #id=item.PrimaryKey }) |
#Html.ActionLink("Details", "Details", new { #id=item.PrimaryKey }) |
#Html.ActionLink("Delete", "Delete", new { #id=item.PrimaryKey })
</td>
</tr>
}
This is the best solution, I had checked almost all information and this is the one working!! Thanks
public ActionResult UploadFile(UploadFileViewModel model)
{
if (ModelState.IsValid)
{
var file = model.File;
var parsedContentDisposition =
ContentDispositionHeaderValue.Parse(file.ContentDisposition);
var filename = Path.Combine(_environment.WebRootPath,
"Uploads", parsedContentDisposition.FileName.Trim('"'));
file.SaveAsAsync(filename);
}
return View();
}

ASP.NET MVC Strongly-Type ViewModel - Combine Create/List Views

I am learning ASP.NET MVC and Entity Framework Code First, LINQ by creating a simple Bug/Feature tracking system. I would like to mimic the Twitter interface by having the user submit a form above and having the submitted content appear below. I am not sure how to structure the strongly-typed view and the said model. I would like to merge my Create and Index views into a single view, the problem is the Create takes a single type Entry (Pylon.Models.Entry), while the Index takes IEnumerable of Entry (IEnumerable<Pylon.Models.Entry>). Below is my viewmodel class and Display view. I simply copied the code generated by scaffolding from the "Create" and "Index" views obviously mixing the different models causes run-time errors so the view is broken. My question is how do I restructure the view.
// Entry ViewModel
public class EntryViewModel
{
public Entry Entry { get; set; }
public IEnumerable<Entry> Entries { get; set; }
}
#* Display View *#
#model ?
#{
ViewBag.Title = "Display";
}
<hr />
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Entry</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OpenDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OpenDate)
#Html.ValidationMessageFor(model => model.OpenDate)
</div>
<div class="editor-label">
Paradigm
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ParadigmId, ((IEnumerable<Pylon.Models.Paradigm>)ViewBag.PossibleParadigms).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.ParadigmId.ToString(),
Selected = (Model != null) && (option.ParadigmId == Model.ParadigmId)
}), "Choose...")
#Html.ValidationMessageFor(model => model.ParadigmId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<hr />
<table>
<tr>
<th></th>
<th>
Description
</th>
<th>
OpenDate
</th>
<th>
Type
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#item.Description
</td>
<td>
#String.Format("{0:d}", item.OpenDate)
</td>
<td>
#(item.Paradigm == null ? "None" : item.Paradigm.Name)
</td>
</tr>
}
</table>
Any pointers or better yet tutorials/working code would be great.
Do the following changes.
set #model EntryViewModel at top of the view.
For create form, change model => model.Description to model => model.Entry.Description, so model is replaced with model.Entry
For listing template, do the following change. #foreach (var item in Model.Entries )
I am not if thats correct. The post at ASP.NET MVC 3 Viewmodel Pattern says that you shouldnt use model objects in your viewmodel.
maybe you'd double check?

Resources