I have below form which is of method=get.
#using (Html.BeginForm("Search", "Home", FormMethod.Get, htmlAttributes: new { #class = "main-search", id = "frmsearch", role = "form" })) {
<div class="row">
<div class="col-md-3 col-sm-3">
<div class="form-group">
<label for="type">Property Type</label>
#Html.ListBoxFor(m => m.searchModel.CategoriesId, Model.searchModel.Categories, htmlAttributes: new { id = "type", multiple = "multiple", #class = "animate", data_transition_parent = ".dropdown-menu", title = "All" })
</div>
<!-- /.form-group -->
</div>
<div class="col-md-3 col-sm-3">
<div class="form-group">
<label for="location">Location</label>
#Html.DropDownListFor(m => m.searchModel.LocationID, Model.searchModel.Locations, htmlAttributes: new { id = "location", multiple = "multiple", #class = "animate", data_transition_parent = ".dropdown-menu", title = "All" })
</div>
<!-- /.form-group -->
</div>
<div class="col-md-3 col-sm-3">
<div class="form-group">
<label>Status</label>
#Html.DropDownListFor(m => m.searchModel.StatusID, Model.searchModel.Status, htmlAttributes: new { id = "status", multiple = "multiple", #class = "animate", data_transition_parent = ".dropdown-menu", title = "All" })
</div>
<!-- /.form-group -->
</div>
<div class="col-md-2 col-sm-3">
<div class="form-group">
<label>Price</label>
<div class="ui-slider" id="price-slider-category" data-value-min="#Model.searchModel.MinPrice" data-value-max="#Model.searchModel.MaxPrice" data-value-type="price" data-currency="₹" data-currency-placement="before">
<div class="values clearfix">
#Html.TextBoxFor(m => m.searchModel.MinPrice, htmlAttributes: new { id = "value-min", #class = "value-min", name = "value-min[]", #readonly = "readonly", style = "padding:0px" })
#Html.TextBoxFor(m => m.searchModel.MaxPrice, htmlAttributes: new { id = "value-max", #class = "value-max", name = "value-max[]", #readonly = "readonly", style = "padding:0px" })
</div>
<div class="element"></div>
</div>
</div>
<!-- /.form-group -->
</div>
<div class="col-md-1 col-sm-3">
<div class="form-group">
<label></label>
<button type="submit" style="color:white" id="searchSubmit" class="btn btn-block blue waves-effect">
<i class="fa fa-search"> </i>
</button>
</div>
<!-- /.form-group -->
</div>
<!--/.col-md-6-->
</div>
<!--/.row-->
}
and I have this JS to post form values through AJAX
$(document).on('click', '#searchSubmit', function (e) {
var _form = $(this).closest('form');
var _url = _form.attr('action');
var formData = _form.serialize();
var request = $.get(_url, formData);
request.complete(function (response) {
})
})
Here is my model
public class SearchFilters
{
public SearchFilters()
{
MinPrice = 10000;
MaxPrice=8000000;
}
public IEnumerable<SelectListItem> Categories { get; set; }
public int[] CategoriesId { get; set; }
public IEnumerable<SelectListItem> Locations { get; set; }
public int[] LocationID { get; set; }
public IEnumerable<SelectListItem> Status { get; set; }
public int[] StatusID { get; set; }
public int MinPrice { get; set; }
public int MaxPrice { get; set; }
}
and this is my controller method to process the search request.
[HttpGet]
public ActionResult Search([Bind(Prefix = "searchModel")]SearchFilters smodel)
{
ProjectsViewModel model = new ProjectsViewModel();
//search db and fill model
return PartialView("_PropertyDetails", model);
}
The UI rendering happens for min and max value using noUiSlider plugin and thus inputs are readonly but gets updated through update option of noUiSlider. But whenever model is received in Server it comes as default value assigned to model variables even after update. The values doesn't get updated when inspected in DOM but its reflected in UI. Yes it is because of readonly property of textbox but Is there any other way to post the readonly property values in these type of situations? Below are few screenshots of how UI looks and DOM and model values when it is received.
UI
DOM
Model
UPDATE
I can see the posted values in URL as ...searchModel.MinPrice=₹2%2C189%2C090.00&searchModel.MaxPrice=₹5%2C772%2C480.00 But not in model. Not sure how to get on this..
₹ and , formatting makes the MinPrice and MaxPrice as strings. And as a result those are not getting bind to int properties. Just remove the formatting and send them in GET, then they will be getting bind to int properties.
Related
I have a Profile page with a Postcode look up feature from https://postcodes.io. So far I have a Partial View with Ajax Form using the following code.
#using (Ajax.BeginForm("_CityLookUp", "Home", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "div1",
InsertionMode = InsertionMode.Replace
}))
{
<div id="div1">
<div class="form-group">
#Html.LabelFor(m => m.PostCode, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.PostCode, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.HiddenFor(m => m.County, new { #class = "form-control", id = "County" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.HiddenFor(m => m.City, new { #class = "form-control", id = "City" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Look Up" />
</div>
</div>
</div>
}
This works. I then rendered the Partial Page on the main profile page with the main profile form.
I just want to assign the value from the two other hidden fields to fields in the main page.
Partial Controller
[HttpGet]
public PartialViewResult _CityLookUp()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _CityLookUp(string postcode)
{
var client = new PostcodesIOClient();
var result = client.Lookup(postcode);
var jst = new AddressLookupViewModel();
jst.City = result.AdminDistrict;
jst.County = result.AdminCounty;
jst.PostCode = postcode;
ViewBag.City = jst.City;
ViewBag.County = jst.County;
var results = new BooksViewModel();
results.City = jst.City;
results.County = jst.County;
return PartialView(jst);
}
I have tried a new view model and assigning the results to the view model but it didn't work. Tried using JavaScript to get the value of the hidden field, no luck. If you'd rather do with a separate method, please explain how you would implement it.
Parent View
#model TestingView.Models.ParentViewModel
<div class="container">
#Html.Partial("_CityLookUp")
<div class="form-group">
<div class="col-md-10">
#Html.TextBoxFor(v => v.City, new { #class = "form-control", id = "City" })
</div>
</div>
</div>
PartialViewModel
namespace TestingView.Models
{
public class AddressLookupViewModel
{
public string PostCode { get; set; }
public string County { get; set; }
public string City { get; set; }
}
}
Parent View Model
namespace TestingView.Models
{
public class ParentViewModel
{
public string City { get; set; }
public string County { get; set; }
}
}
Side question: For some reason, when I hover over
#Html.HiddenFor(m => m.City, new { #class = "form-control", id = "City" })
on the parent view, it references the AddressLookUpViewModel and not the BooksViewModel in the parent view.. I have added both View Models.
I will answer this two ways; first using the approach you were initially asking about and then how I would prefer to implement this.
Solution 1
With this approach we will copy the value of the City element from the partial view to the parent view.
First thing we need to fix up is when you view the profile right now, there will be two elements with an Id of "City"; one from the parent page and one from the partial. That's invalid markup and it will cause problems for any potential solution.
Rename the Id attribute in the parent view:
#Html.TextBoxFor(v => v.City, new { #class = "form-control", id = "Profile_City" })
Update the partial view to call a js function when it successfully retreives a set of postcode values:
#using (Ajax.BeginForm("_CityLookUp", "Home", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "div1",
InsertionMode = InsertionMode.Replace,
OnSuccess = "UpdateProfile" // Add this
}))
Add a js function, UpdateProfile, to the end of the parent view:
#section scripts {
<script>
function UpdateProfile()
{
var City = $("#City").val();
alert(City);
$("#Profile_City").val(City);
}
</script>
}
That should be all that's required. The alert is just there for debugging.
The #section scripts code will be injected in to your _Layout.cshtml where it calls #RenderSection("scripts", required: false), part of the default MVC project.
One problem that might crop up going forward is when you build the parent view into a form you might be tempted to nest the form elements for layout reasons but nested form elements aren't permitted.
Solution 2
This approach uses jQuery's ajax() method to fetch the data and directly populate the relevant fields on a form.
Set up the model.
namespace TestingView.Models
{
public class ProfileViewModel
{
public string PostCode { get; set; }
public string County { get; set; }
public string City { get; set; }
}
}
This is a copy of AddressLookupViewModel as it contains all the necessary fields. I have simply renamed it to suggest its use is for the main profile form itself.
Create the view.
The view now has a single Html.BeingForm(), with the Look Up button bound to an ajax function rather than submitting an ajax form.
Its not 100% clear to me whether you want the user to be able to edit the County and City fields after a look up. In the code below they can.
#model TestingView.Models.ProfileViewModel
#using (Html.BeginForm())
{
<div class="form-group">
#Html.LabelFor(m => m.PostCode, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.PostCode, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="button" class="btn btn-primary" onclick="Lookup()">Look Up</button>
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.County, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.County, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.City, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.City, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
}
#section scripts {
<script>
function Lookup() {
$.ajax("/Home/CityLookup", {
type: "POST",
dataType: 'json',
data: {
postcode: $("#PostCode").val()
}
})
.success(function (response) {
console.log("Success");
console.log(response);
var cityObj = response;
$("#City").val(cityObj.City);
console.log("City " + cityObj.City);
$("#County").val(cityObj.County);
})
.error(function () {
alert("There was a problem looking up the postcode");
})
};
</script>
}
Create a controller to service the ajax request. This is heavily based on your POST _CityLookUp controller. Note the Action type is JsonResult and the return converts the jst object in to a JSON string. Using JSON makes the lookup extensible; we can return multiple properties as an object and unpack them to a javascript object for use client-side.
[HttpPost]
public JsonResult CityLookup(string postcode)
{
var client = new PostcodesIOClient();
var result = client.Lookup(postcode);
var jst = new AddressLookupViewModel();
jst.City = result.AdminDistrict;
jst.County = result.AdminCounty;
jst.PostCode = postcode;
return Json(jst);
}
How can i set a validation message on all of these fields? Im not sure how to set it when I bind everything directly to my entitymodel Cancellation? I tried setting a validationmessage directly in my entityclass nut no luck.
This is my razorpage
#page
#model Index
#{
ViewBag.Title = "Index";
}
<div class="body-content">
<form id="avboka-form" method="post">
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Elev"></label>
<input type="text" id="elev" asp-for="Cancellation.Elev" class="form-control">
<span asp-validation-for="Cancellation.Elev"></span>
</div>
</div>
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Dag"></label>
<input asp-for="Cancellation.Dag" type="datetime" id="datepicker" class="datepicker1 form-control">
<span asp-validation-for="Cancellation.Dag"></span>
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedKommun, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.KommunId, new SelectList(Model.Kommun, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "kommun" })
#Html.ValidationMessageFor(x => x.SelectedKommun, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedFordon, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.FordonId, new SelectList(Model.Fordon, "Value", "Text"), htmlAttributes: new { #class = "form-control", #id = "fordon" })
#Html.ValidationMessageFor(x => x.SelectedFordon, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-med-5">
<label asp-for="Cancellation.Skola.Namn"></label>
<select id="skola" name="Cancellation.SkolaId" class="form-control">
#foreach (var schools in Model.School)
{
<option value="#schools.Id">#schools.Namn</option>
}
</select>
<span asp-validation-for="Cancellation.SkolaId"></span>
</div>
<input type="submit" name="save" value="Avboka skolskjuts" class="vt-btn" />
</form>
</div>
Here is part of my pagemodel where i bind my input-fields. The selects is collected from other tables and therefore is never empty.
[BindProperty]
public Avbokning Cancellation { get; set; }
public Index(SqlAvbokningData<Avbokning> avbokningRepo, SqlKommunData<Kommun> kommunRepo, SqlFordonData<Fordon> fordonRepo, SqlSkolaData<Skola> skolaRepo)
{
_avbokningRepo = avbokningRepo;
_kommunRepo = kommunRepo;
_fordonRepo = fordonRepo;
_skolaRepo = skolaRepo;
}
public async Task<IActionResult> OnGet()
{
Kommun = await _kommunRepo.GetKommuner();
Fordon = _fordonRepo.GetFordon();
Municipalities = await _kommunRepo.GetAll();
Vehicle = await _fordonRepo.GetAll();
School = await _skolaRepo.GetAll();
return Page();
}
[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
//if (!Cancellation.Validate())
// return Redirect("/");
await _avbokningRepo.Add(Cancellation);
return Redirect("/Tack");
}
return RedirectToAction("OnGet");
}
Validation in MVC can be done with a viewmodel. You specify your model this way:
public class LogOnViewModel
{
[Required(ErrorMessage = "RequiredField")]
[Display(Name = "Username")]
public string Username { get; set; }
[Required(ErrorMessage = "RequiredField")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
Once you get to the web page itself, the ValidationMessageFor will then validate the fields based on the data annotations you have placed on your viewmodel, as you pass that on to the web page.
In the controller you can pass it on to the page by means like this:
var viewModel = new LogOnViewModel();
// do stuff
return View(viewModel);
It's not a perfect example, but this should give some idea of how you can use it.
I'm using ASP.NET c# mvc with entity framework to build a web site. So I want to create user profile for the registered user which is editable. Within that i have coded for a image upload part and it was not successfully worked out for me.
This is my View file (Manage.cshtml)
#model TheFoody.Models.ManageViewModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script>
function editFunc() {
document.getElementById("Photo").disabled = false;
document.getElementById("FirstName").disabled = false;
document.getElementById("LastName").disabled = false;
document.getElementById("Email").disabled = false;
document.getElementById("UserType").disabled = false;
document.getElementById("Address").disabled = false;
document.getElementById("City").disabled = false;
document.getElementById("District").disabled = false;
document.getElementById("Phone").disabled = false;
//document.getElementById("Photo").disabled = false;
document.getElementById("PostCode").disabled = false;
document.getElementById("Status").disabled = false;
}
function reload() {
window.location.href = "http://localhost:1672/Manage";
}
</script>
<div class="breadcrumb-wrapper">
<div class="container">
<ol class="breadcrumb-list booking-step">
<li>Home</li>
<li><span>User Profile</span></li>
</ol>
</div>
</div>
<div class="admin-container-wrapper">
<div class="container">
<div class="GridLex-gap-15-wrappper">
<div class="GridLex-grid-noGutter-equalHeight">
<div class="GridLex-col-3_sm-4_xs-12">
<div class="admin-sidebar">
<div class="admin-user-item">
<div class="image">
<img src="http://localhost:33409/images/man/01.jpg" alt="image" class="img-circle" />
</div>
<h4>John Doe</h4>
<p class="user-role">Foodies</p>
</div>
<div class="admin-user-action text-center">
Edit
Deactivate
</div>
<ul class="admin-user-menu clearfix">
<li>
<i class="fa fa-tachometer"></i> Dashboard
</li>
<li class="active">
<i class="fa fa-user"></i> Profile
</li>
<li>
<i class="fa fa-key"></i> Change Password
</li>
<li>
<i class="fa fa-bookmark"></i> Favourite Restaurant
</li>
<li>
<i class="fa fa-sign-out"></i> Logout
</li>
</ul>
</div>
</div>
<div class="GridLex-col-9_sm-8_xs-12">
<div class="admin-content-wrapper">
<div class="admin-section-title">
<h2>Profile</h2>
<p>Enquire explain another he in brandon enjoyed be service.</p>
</div>
<!--<form class="post-form-wrapper" action="http://localhost:33409/UpdateProfile/Edit" id="updateForm" method="POST">-->
#using (Html.BeginForm("Manage", "Manage", new { #id = "updateForm", #class = "post-form-wrapper" }, FormMethod.Post))
{
#Html.AntiForgeryToken();
<div class="row gap-20">
<div class="col-sm-6 col-md-4">
#ViewBag.Error
<div class="form-group bootstrap-fileinput-style-01">
<label>Photo</label>
<input type="file" name="Photo" id="Photo" disabled>
#*#Html.HiddenFor(model => model.Photo, new { #class = "form-control", disabled = "disabled" })*#
#*<input type="hidden" value="default" id="photo" name="photo" />*#
<span class="font12 font-italic">** photo must not bigger than 250kb</span>
</div>
</div>
<div class="clear"></div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>First Name</label>
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>Last Name</label>
#Html.TextBoxFor(model => model.LastName, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>Email</label>
#*<input type="email" class="form-control" value=Session["UserEmail"].tostring() id="email" name="email" disabled>*#
#Html.TextBoxFor(model => model.Email, new { #class = "form-control", disabled = "disabled"})
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="clear"></div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>Address</label>
#*<input type="text" class="form-control" value="254" id="address" name="address" disabled>*#
#Html.TextBoxFor(model => model.Address, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.Address, "", new { #class = "text-danger" })
</div>
</div>
<div class="clear"></div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>District</label>
#*<input type="text" class="form-control" value="254" id="district" name="district" disabled>*#
#Html.TextBoxFor(model => model.District, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.District, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>City/town</label>
#*<input type="text" class="form-control" value="Somewhere " id="city" name="city" disabled>*#
#Html.TextBoxFor(model => model.City, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.City, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>PostCode</label>
#*<input type="text" class="form-control" value="Somewhere " id="postcode" name="postcode" disabled>*#
#Html.TextBoxFor(model => model.PostCode, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.PostCode, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>UserType</label>
</div>
<div class="col-sm-6 col-md-4">
#{
List<SelectListItem> listItemsUserType = new List<SelectListItem>();
listItemsUserType.Add(new SelectListItem
{
Text = "Admin",
Value = "Admin"
});
listItemsUserType.Add(new SelectListItem
{
Text = "Customer",
Value = "Customer",
Selected = true
});
listItemsUserType.Add(new SelectListItem
{
Text = "Business",
Value = "Business"
});
}
#Html.DropDownListFor(model => model.UserType, listItemsUserType, "-- Select Status --", new { #class = "form-control",disabled = "disabled" })
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>Status</label>
</div>
<div class="col-sm-6 col-md-4">
#{
List<SelectListItem> listItemsStatus = new List<SelectListItem>();
listItemsStatus.Add(new SelectListItem
{
Text = "Availble",
Value = "Available",
Selected = true
});
listItemsStatus.Add(new SelectListItem
{
Text = "Not Available",
Value = "Not Available"
});
}
#Html.DropDownListFor(model => model.Status, listItemsStatus, "-- Select Status --", new { #class = "form-control",disabled = "disabled" })
</div>
</div>
<div class="clear"></div>
<div class="col-sm-6 col-md-4">
<div class="form-group">
<label>Phone Number</label>
#*<input type="text" class="form-control" value="+66-85-221-5489" id="phone" name="phone" disabled>*#
#Html.TextBoxFor(model => model.Phone, new { #class = "form-control", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
<div class="clear"></div>
<div class="col-sm-12 mt-10">
#*<input type="submit" onclick="document.getElementById('updateform').submit()" class="btn btn-primary" value="Save" />*#
<input type="submit" class="btn btn-primary" value="Save" />
Cancel
</div>
</div>
}
<!--</form>-->
</div>
</div>
</div>
</div>
</div>
</div>
And it will give a UI like below.
And my Model file is like below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace TheFoody.Models
{
public class ManageViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Photo { get; set; }
public string Address { get; set; }
public string City { get; set; }
public int PostCode { get; set; }
public string District { get; set; }
public string UserType { get; set; }
public string Status { get; set; }
}
}
And my Controller looks like this (ManageController.cs)
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TheFoody.DataAccess;
using TheFoody.Models;
namespace TheFoody.Controllers
{
public class ManageController : Controller
{
//ManageContext db = new ManageContext();
//
//GET: /Manage/
public ActionResult Manage()
{
//LoadData();
var manageviewmodel = new ManageViewModel() { Email = Session["UserEmail"].ToString() };
return View(manageviewmodel);
}
private bool isValidContentType(string contentType)
{
return contentType.Equals("Images/png") || contentType.Equals("Images/gif") || contentType.Equals("Images/jpg") || contentType.Equals("Images/jpeg");
}
private bool isValidContentLength(int contentLength)
{
return (contentLength / 1024) / 1024 < 1; //1MB
}
[HttpPost]
public ActionResult Manage(ManageViewModel manageviewmodel, HttpPostedFileBase Photo)
{
TheFoodyContext db = new TheFoodyContext();
User user_to_update = db.Users.SingleOrDefault(s => s.email == manageviewmodel.Email);
if (ModelState.IsValid)
{
try
{
if (!isValidContentType(Photo.ContentType))
{
ViewBag.Error = "Only JPG , JPEG , GIF & PNG are allowed!";
return View("Manage");
}
else if (!isValidContentLength(Photo.ContentLength))
{
ViewBag.Error = "Your File is too Large!";
return View("Manage");
}
else
{
if (user_to_update != null && (Photo != null && Photo.ContentLength > 0))
{
var fileName = Path.GetFileName(Photo.FileName);
var path = Path.Combine(Server.MapPath("~/Content/Images"), fileName);
Photo.SaveAs(path);
user_to_update.email = manageviewmodel.Email;
user_to_update.fname = manageviewmodel.FirstName;
user_to_update.lname = manageviewmodel.LastName;
user_to_update.phone = manageviewmodel.Phone;
//user_to_update.photo = manageviewmodel.Photo;
user_to_update.address = manageviewmodel.Address;
user_to_update.city = manageviewmodel.City;
user_to_update.postcode = manageviewmodel.PostCode;
user_to_update.district = manageviewmodel.District;
user_to_update.user_type = manageviewmodel.UserType;
user_to_update.status = manageviewmodel.Status;
db.SaveChanges();
return RedirectToAction("Manage");
}
}
}
catch (Exception ex)
{
return View("Error");
}
return View(manageviewmodel);
}
return View(manageviewmodel);
}
}
}
And the design of My database is;
And my DbContext file looks as below;
namespace TheFoody.DataAccess
{
using System;
using System.Collections.Generic;
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
this.Restaurants = new HashSet<Restaurant>();
}
public string email { get; set; }
public string password { get; set; }
public string fname { get; set; }
public string lname { get; set; }
public string phone { get; set; }
public string photo { get; set; }
public string address { get; set; }
public string city { get; set; }
public Nullable<decimal> postcode { get; set; }
public string district { get; set; }
public string user_type { get; set; }
public string status { get; set; }
public System.DateTime created_date { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Restaurant> Restaurants { get; set; }
}
}
But when i'm executing all these things My ~/Content/Images file does not have the image file that i have uploaded. And it will give me the error to the view as follows.
Actually I wanted to save the path to the relevant image file in the database and image in the ~/Content/Images folder which in following hierarchy.
I'm very new to this environment specially Entity Framework. So i don't know how to correct my code to get what i'm expected.
First you have to do is copy and past that image to your image folder
System.IO.File.Copy("source", "destination");
Then save that path to your data base.
I am fairly new to MVC5 and C# and I am trying to achieve something that I don't fully understand.
I have a Team Model such as this:
public class Team
{
[Key]
public Guid ID { get; set; }
public string TeamName { get; set; }
public string Coach { get; set; }
public string Conference { get; set; }
}
I also have a Player Model such as this:
public class Player
{
[Key]
public Guid Id { get; set; }
[ForeignKey("Teams")]
public Guid TeamId { get; set; }
public string Name { get; set; }
public virtual Team Teams { get; set; }
}
View Model is
public class TeamViewModel
{
public string TeamName { get; set; }
public string Coach { get; set; }
public string Conference { get; set; }
public List<Player> Players { get; set; }
}
With this structure, you are suppose to be able to add and infinite number of players to each team. As such I have a Teams table with few properties and a Player table that contains the player name as well as the player TeamId so that we know to what team they belong.
My problem comes when I am creating a team. I have Create Controller such as this:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(TeamViewModel model)
{
if (ModelState.IsValid)
{
var team = new Team { TeamName = model.TeamName, Coach = model.Coach, Conference = model.Conference, Player = model.Player };
db.Teams.Add(team);
var result = await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View();
}
And my View is as follows:
#model SoccerTeams.Models.ViewModels.TeamViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Team</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.TeamName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TeamName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TeamName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Coach, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Coach, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Coach, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Conference, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Conference, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Conference, "", new { #class = "text-danger" })
</div>
</div>
#if (#Model != null)
{
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
}
else
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">Player</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</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>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
From my understanding, the View is suppose to be able to convert the input element to a list and pass it on to my ViewModel. However, my ViewModel is always coming up as null.
What am I missing and how would I make this work?
P.S. I understand that I can user Html.EditorFor, but I was not able to get it working, so I just printed it out as Html as I need to solve my other problem first.
Edit
I have altered my View to have the following code
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">Player</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"model.Players[0].Name\" type-\"text\"")
</div>
</div>
As a result, the model now properly populates the Players Array, however all other values have now become null. If I remove the input element, the values are populated but players array is null again as there are no form fields for it. Do you know what could be the culprit?
In the TeamViewModel I have also renamed Player to Players.
In order for MVC to bind your form data to the Action method's parameters
their names should match.
Supposing your ViewModel has property for List<Player> Players your code should be:
In your case:
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
Should be:
for (int i = 0; i < Model.Player.Length; i++)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"model.Player[" + i + "].Name\" type-\"text\"")
</div>
</div>
}
Because this is the name of the parameter that you have provided:
Create(TeamViewModel model)
Also be careful because the indexes should not be broken, which means that they should be 0, 1, 2.. etc. without skipping a number.
The way that we read in the properties is by looking for
parameterName[index].PropertyName. The index must be zero-based and
unbroken.
NOTE You can read more about binding collections in Scott Hanselman's post - here
And last I suggest if you have a property that is list of something - in your case list of Player to use the plural form for the property name - Players.
EDIT
Try removing the "model." in front in the name. Make it like this "Players[0].Name". Since you only have one parameter in your Create Action method it should be fine.
I suggest you to use the helper #Html.EditorFor, so to do this you will create a partial view that will be used as template to inputs of the nested property. see the example:
Shared/EditorTemplates/Player.cshtml
#model Player
<div class="form-group">
#Html.HiddenFor(e => e.Id)
#Html.HiddenFor(e => e.TeamId)
<label class="control-label col-md-2" for="player">Player</label>
<div class="col-md-10">
#Html.TextBoxFor(e => e.Name, new { #class = "form-control text-box single-line", id = "player", name = "Player"})
</div>
</div>
Players form on Team view:
#Html.EditorFor(e => e.Player)
Instead of:
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
See this article for more information about editor templates: Editor and display templates
I'm trying to pass a RadioButtonFor to the model.
Controller
[HttpPost]
public ActionResult Contact(ApplicationCommentType model)
{
//send email here
//reload form
ApplicationCommentType appdata = new ApplicationCommentType();
appdata.CommentTypeData = db.CommentTypes.ToList();
return View(appdata);
}
ApplicationCommentType
public class ApplicationCommentType
{
public IEnumerable<CommentType> CommentTypeData { get; set; }
public String CommentTypeDataSelection { get; set; }
public String Name { get; set; }
public String Email { get; set; }
public String Comment { get; set; }
}
CommentType
public partial class CommentType
{
public int CommentTypeID { get; set; }
public string CommentTypeDesc { get; set; }
}
View
#using(#Html.BeginForm("Contact", "Home", FormMethod.Post, new{ #class ="form-horizontal"})){
<fieldset>
<legend>Contact Us</legend>
<div class="form-group">
#Html.LabelFor(x => x.Email, new {#class="col-lg-2 control-label"})
<div class="col-lg-10">
#Html.TextBoxFor(x => x.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.Name, new { #class = "col-lg-2 control-label" })
<div class="col-lg-10">
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<label for="textArea" class="col-lg-2 control-label">Questions, Comments, or Concerns</label>
<div class="col-lg-10">
#Html.TextAreaFor(x => x.Comment, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label">Comment Type</label>
<div class="col-lg-10">
#foreach (var item in Model.CommentTypeData)
{
<div class="radio">
<label>
#Html.RadioButtonFor(x => x.CommentTypeData, item.CommentTypeDesc)
#Html.LabelFor(m => m.CommentTypeData, item.CommentTypeDesc, item.CommentTypeID)
</label>
</div>
}
#Html.HiddenFor(x => x.CommentTypeDataSelection)
</div>
</div>
</fieldset>
}
Now this kind of works, all the textbox items work. Placing a break point on the [HttpPost] return yields the following values.
Comment: "awesome"
CommentTypeData: Count = 0
CommentTypeDataSelection: null
Email: "example#example.com"
Name: "John Smith"
Shouldn't CommentTypeData have a count? If I check the request the selected value is there.
Request.Params["CommentTypeData"]: "General Improvement Suggestion"
So why is the Model not updated? Is it a requirement to manually update the Model from the Request object?
You can use #Html.RadioButtonFor but you should make sure that item.CommentTypeDesc compatible with Radio type.
Refer to MVC4: Two radio buttons for a single boolean model property
Hope it helps.