I am creating a MVC project. I try to add a Edit page of a model. Here is my model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace SportsStore.Domain.Entities
{
public class Product
{
[HiddenInput(DisplayValue = false)]
public int ProductID { get; set; }
public string ProductName { get; set; }
[DataType(DataType.MultilineText)]
public string ProductDescription { get; set; }
public decimal ProductPrice { get; set; }
public string ProductCategory { get; set; }
}
}
As you can see, ProductId and ProductCategory property has proper metadata information. As per these metadata information, I shall not see ProductID in edit page and see ProductCategory in multi line.
Here is my edit page. (edit.cshtml)
#model SportsStore.Domain.Entities.Product
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h1>Edit #Model.ProductName</h1>
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="Save" />
#Html.ActionLink("Cancel and return to List", "Index")
}
However, I can not see the page in accordance. Here is the view of my page:
As you can see, ProductID has appeared on the page, and description is not multine. What I am missing?
Thanks in advance.
Thanks for person whom interest with the topic.
The problem is that there are multiple Entity Framework classes in the project mistakenly. Each entity framework has its own Product class. I unite them.
Related
I am using Ajax and rendering a Partial View. The data is being passed fine into the controller. There is nothing null. However for some reason in my Partial View the OwnerUser and the AssignToUser are null but the Hours and the Body are coming through with the correct information. I have this same implementation in another part of my project and it's working fine, even with the user coming in. I can't figure out why in this Partial View the ApplicationUser data is null.
[HttpPost]
public ActionResult ChatAjax([Bind(Include = "Body")] Chat chat, string ChatData)
{
chat.Created = DateTimeOffset.Now;
var user = User.Identity.GetUserId();
chat.OwnerUserId = user;
chat.AssignToUserId = ChatData;
db.Chats.Add(chat);
db.SaveChanges();
if (Request.IsAjaxRequest())
{
return PartialView("_Chats", chat);
}
return RedirectToAction("LandingPage", "Admin");
}
This is my Partial View:
#model BugTracker.Models.Chat
#{
var day = DateTimeOffset.Now.Offset.Hours;
}
<div class="direct-chat-msg">
<div class="direct-chat-info clearfix">
<span class="direct-chat-name pull-left">
#Model.OwnerUser.FirstName</span>
<span class="direct-chat-timestamp pull-right">
#Model.Created.AddHours(day)
</span>
<br />
<span class="direct-chat-timestamp pull-right">Sent to
#Model.AssignToUser.DisplayName
</span>
</div>
<!-- /.direct-chat-info -->
<div class="direct-chat-text" style="background:lightblue">
#Model.Body
</div>
<!-- /.direct-chat-text -->
</div>
Here is my Chat Model
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace BugTracker.Models
{
public class Chat
{
public int Id { get; set; }
public string Body { get; set; }
public DateTimeOffset Created { get; set; }
[Display(Name = "Owner")]
public string OwnerUserId { get; set; }
[Display(Name = "Assign")]
public string AssignToUserId { get; set; }
public virtual ApplicationUser OwnerUser { get; set; }
public virtual ApplicationUser AssignToUser { get; set; }
}
}
I have created two models, Student and School and a composite model, StudentSchool. I am using two different partiel views to create one the Student and the other the School. However, in my controller, I am getting null values for both the Student and School. Below is my code:
Student:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class Student
{
public int studentID { get; set; }
public String firstname { get; set; }
public String lastname { get; set; }
public int year { get; set; }
}
}
School:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class School
{
public int schoolID { get; set; }
public String name { get; set; }
public String add { get; set; }
}
}
Composite model, StudentSchool:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class StudentSchool
{
public Student student { get; set; }
public School school { get; set; }
}
}
PartielViewStudent:
#model LayoutProject.Models.Student
<h4>Student</h4>
#Html.LabelFor(d=>d.studentID) : #Html.TextBoxFor(d=>d.studentID)
<br />
#Html.LabelFor(d=>d.firstname) : #Html.TextBoxFor(d=>d.firstname)
<br />
#Html.LabelFor(d=>d.lastname) : #Html.TextBoxFor(d=>d.lastname)
<br />
#Html.LabelFor(d=>d.year) : #Html.TextBoxFor(d=>d.year)
<br />
PartialViewSchool:
#model LayoutProject.Models.School
<h4>School</h4>
#Html.LabelFor(d=>d.schoolID) : #Html.TextBoxFor(d=>d.schoolID)
<br />
#Html.LabelFor(d=>d.name) : #Html.TextBoxFor(d=>d.name)
<br />
#Html.LabelFor(d=>d.add) : #Html.TextBoxFor(d=>d.add)
<br />
The View:
#{
ViewBag.Title = "StudentSchool";
}
<h2>StudentSchool</h2>
<form action="/Home/CreateStudentSchools" method="post">
#using (Html.BeginForm())
{
#Html.Partial("_PartialViewStudent")
#Html.Partial("_PartialViewSchool")
}
<input id="createSD" type="submit" value="Submit"/>
</form>
The controller:
[HttpPost]
public ActionResult CreateStudentSchools(StudentSchool ss)
{
return View("CreateStudentSchool");
}
Any idea what I might be missing here? Been with this since 4 days.
Move you 'partial' views into the /Views/Shared/EditorTemplates folder and rename them to Student.cshtml and School.cshtml respectively (to match the names of the classes). Then in the main view use
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.Student)
#Html.EditorFor(m => m.School)
}
The inputs your generating will now contain the correct name attribute for binding to your view model, for example name="Student.studentID" instead of the current name="studentID"
Note: As an alternative, you can pass the HtmlFieldPrefix to a Partial as indicated in this answer.
Its not a good idea if you provide the two partial views with different models and combining in one model.You have to pass the reference of the composite model to your partial views.
#using (Html.BeginForm())
{
#Html.Partial("_PartialViewStudent",Model.student)
#Html.Partial("_PartialViewSchool",Model.school)
}
This will work fine as with this approach as everything in the form is strictly typed.
In partial views also you have to specify models as
#model LayoutProject.Models.StudentSchool.student
#model LayoutProject.Models.StudentSchool.school
I am not sure about your [httpget] create method but it should be like
[HttpGet]
public ActionResult CreateStudentSchools(StudentSchool ss)
{
var studentsc=new StudentSchool()
{
student=new Student(),
school=new School()
}
return View("CreateStudentSchool",studentsc);
}
I have a project (below) where I have Categories and Products. Each category will have multiple products and as you can see from the models, the Category ID is referenced as a Foreign Key. What I am trying to do is to have each Category display as a div with the corresponding products shown in a unordered list beneath. With the code I have, I keep ending up with a div and one product with categories repeating for each product.
I have searched and searched but can't seem to find the solution. Where I am I going wrong?
ViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Web.Models
{
public class Category
{
public int CategoryID { get; set; }
[Required, Display(Name = "Category Name")]
public string CategoryName { get; set; }
public bool IsDisplayedInMainMenu { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public int CategoryID { get; set; }
[ForeignKey("CategoryID")]
[Display(Name = "Category Name")]
public Category CategoryName { get; set; }
[Required, Display(Name = "Product Name")]
public string ProductName { get; set; }
[Required, Display(Name = "Product Description")]
[DataType(DataType.MultilineText)]
public string ProductDescription { get; set; }
}
}
Products Controller
namespace WebApplication1.Controllers
{
public class ProductsController : Controller
{
private ServiceContext db = new ServiceContext();
// GET: Products
public ActionResult Index()
{
var products = db.Products.Include(p => p.CategoryName);
return View(products.ToList());
}
}
}
View
model IEnumerable
#{
ViewBag.Title = "Products";
}
<h2>#ViewBag.Title</h2>
<div class="row">
#foreach (var item in Model)
{
<div class="col-md-3">
<h4><strong>#item.CategoryName.CategoryName</strong></h4>
<ul class="list-unstyled">
#if (item.ProductName.Any())
{
<li>
#item.ProductName
</li>
}
</ul>
</div>
}
</div>
Products
Lumber
2 X 4
Lumber
1 X 4
Lumber
Plywood
Power Tools
Drill
Power Tools
Circular Saw
Garden
Lemon Tree
Garden
Orange Tree
Fasteners
Drywall screws
Fasteners
Deck Screws
Change the data you're sending to the view. Instead of this.DB.Products...try the following:
return this.View(this.DB.Category.Select(x => new { CategoryName = x.CategoryName, Products = x.Products);
...or something similar depending on your database structure. The idea is to have a model that resembles what you actually want to display in the view. This is commonly referred to as a view model.
public class CategoryViewModel
{
public string CategoryName {get; set;}
public IEnumerable<Product> Products {get; set;}
}
If you had such a class, then your controller method might look like this:
return this.View(this.DB.Category.Select(x => new CategoryViewModel { CategoryName = x.CategoryName, Products = x.Products));
Then in your view:
<div class="col-md-3">
<h4><strong>#Model.CategoryName</strong></h4>
#foreach (var item in Model.Products)
{
<ul class="list-unstyled">
#item.ProductName (or something)
</ul>
}
</div>
I'm not on a dev machine so I can't really tell if I've made typos. I'm happy to answer any questions you might have though.
If you are returning products under a selected category, you can use below code
#if(Model.Count()>0)
{
<h4><strong>#Model.ToList()[0].CategoryName.CategoryName</strong></h4>
}
Hope it will works
i have a page that contains 3 partial views.
...
.
.
#Html.Action("one" , "Home")
#Html.Action("two" , "Home")
#Html.Action("three" , "Home")
.
.
.
i have 5 table in data base.and some of them have relation.some fields of these table should be filled in partial ONE,some should be filled in partial TWO,and ...
i make a class of combination this 5 table.
public class ViewModelX
{
public Nullable<long> id_sport { get; set; }
public Nullable<long> id_city { get; set; }
public Nullable<long> id_spend { get; set; }
public Nullable<long> id_profile { get; set; }
public Nullable<int> cost { get; set; }
public Nullable<long> idFactor { get; set; }
public Nullable<long> Idpage { get; set; }
public string username { get; set; }
public string Namestar { get; set; }
public string Lnamestar { get; set; }
public string Tell { get; set; }
public string cell { get; set; }
public string Address { get; set; }
public string Code { get; set; }
public string username_s { get; set; }
public Nullable<long> id_s { get; set; }
public Nullable<long> id_mark{ get; set; }
}
now i should pass this model to every partial?
and i should pass it to my basic page that contains this 3 partial views too?
You should not Pass the Model(associated with your Business Layer) to you View.
Your opinion might comes simply from a desire to write/maintain less code. So, It is obvious why creating new view models all of the
time will lead to more code.
Reasons to Use a View Model when it makes sense (and this has happened to me), this allows you to validate your view model
differently than your model for attribute-based validation scenarios.
View model objects can be used to help shape and format data. Need a date or money value formatted a particular way? You can do that in
the view, in the controller, or in the view model. If all you are
doing is formatting and such, you can make a case that the view model
is the best place to do it.
By using a view model you have a good mechanism to flatten out and simplify what the view deals with. This will also filter down what can
be seen in intellisense, so if you have different people developing
the models than those working on the views, creating a simple view
model can make it much easier for those just dealing with the UI.
Conslusion : View Model should contain only those properties that are required for it's corresponding View.
Reference
View Models
public class PartialViewModel1
{
[Display(Name = "Name")]
public String Name { get; set; }
}
public class PartialViewModel2
{
[Display(Name = "id")]
public int id { get; set; }
}
public class PartialViewModel3
{
[Display(Name = "DOB")]
public DateTime DOB { get; set; }
}
Controller Action Methods
[HttpGet]
public PartialViewResult PartialView1()
{
return PartialView(new PartialViewModel1());
}
[HttpGet]
public PartialViewResult PartialView2()
{
return PartialView(new PartialViewModel2());
}
[HttpGet]
public PartialViewResult PartialView3()
{
return PartialView(new PartialViewModel3());
}
Partial Views - 1
#model Practise.Controllers.PartialViewModel1
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
Partial Views - 2
#model Practise.Controllers.PartialViewModel2
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
Partial Views - 3
#model Practise.Controllers.PartialViewModel3
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.EditorForModel();
<input type="submit" name="Submit" value="Submit" />
}
View
#Html.Action("PartialView1", "Account", new { area = "AreaName" })
#Html.Action("PartialView2", "Account", new { area = "AreaName" })
#Html.Action("PartialView3", "Account", new { area = "AreaName" })
I had your problem before .
If your partial view should get some data use #Html.RenderAction() like below:
Your Partial view (_theLastPost.cshtml) :
#model IEnumerable<test1.Models.Post>
#foreach (var item in Model)
{
<h2>
#item.Title
</h2>
<p>
#item.Content
</p>
}
In your Index.cshtml embed partial view :
#{ Html.RenderAction("_theLastPost"); }
And you should have a controller with same name of partial view like below :
public PartialViewResult _theLastPost()
{
var a = (from c in db.Posts
orderby c.ID_Post descending
select c);
return PartialView(a.ToList());
}
I need to add the following field at my form
<input type="file" class="input-file" />
I create model and describe this field (the last field)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CorePartners_Site2.Models
{
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Company { get; set; }
public string AdditionalInformation { get; set; }
public HttpPostedFileBase ProjectInformation { get; set; }
}
}
and create
#Html.TextBox(null, null, new { type="file", #class="input-file" })
but it doesnt work, I get some exception.
What's wrong?
Model
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Company { get; set; }
public string AdditionalInformation { get; set; }
public HttpPostedFileBase ProjectInformation { get; set; }
}
View
#model FeedbackForm
#Html.TextBox("Name")
#Html.TextBox("Email")
...
#Html.TextBox("ProjectInformation", null, new { type="file", #class="input-file" })
// submit button
My recommended view (strongly - typed)
#model FeedbackForm
#Html.TextBoxFor(model=>model.Name)
#Html.TextBoxFor(model=>model.Email)
...
#Html.TextBoxFor(model=>model.ProjectInformation, null, new { type="file", #class="input-file" })
// submit button
Controller
[HttpPost]
public ActionResult FeedbackForm(FeedbackForm model)
{
// this is your uploaded file
var file = model.ProjectInformation;
...
return View();
}
MVC is using name convention, so if your textbox and model names match, then MVC will bind your inputs to your model.
I think you are getting a null because you have not specified the enctype in your form tag.
#using (Html.BeginForm("ActionMethodName", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
}
A working example always help.
Visit http://www.mindstick.com/Articles/cf1e1dd9-fdba-4617-94f0-407223574447/?Upload%20File%20in%20Asp.Net%20Mvc%204
You can use the below syntax
#Html.TextBoxFor(model=>model.Email, new { #type="file", #class="input-file" })
I solved this problem using enctype="multipart/form-data"
#using (Html.BeginForm("SalvarEvidencia", "Evidencia", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
}
There's nothing wrong with just using the input tag directly in your view. You aren't required to use a helper.
<input type="file" class="input-file" />
Just make sure it's within your BeginForm declaration block.
You need to specify the name of the field. If you don't want a name, nor a value, it's better to just include the field as is in your form.
It doesn't make sense to use a helper, if there's nothing dynamic about it.
#using (Html.BeginForm("Action_Name", "Controller_Name",FormMethod.Post))
{
#Html.TextBoxFor(m => m.Email, new {#class = "text_field"})
#Html.ValidationMessageFor(m => m.Email)
}