I want to upload gallery images to ASP.NET MVC 5 application using filesystem upload. I added
public IEnumerable<string> GalleryImages { get; set; }
to my ProductModel, built solution and performed update-database in the package manager console. But, the property is not added to the Product table and when I try to add and then edit a product, I get this error:
System.ArgumentNullException: 'Value cannot be null.
Parameter name: source'
Also, I added this piece of code to Edit.cshtl:
#if (!Model.GalleryImages.Any())
{
<h4>There are no gallery images for this product.</h4>
}
<form action="/AdminPanel/Product/SaveGalleryImages" method="post" enctype="multipart/form-data" class="dropzone" id="dropzoneForm">
<div class="fallback">
<input type="file" name="file" multiple />
<input type="submit" value="Upload" />
</div>
</form>
<br /><br />
#foreach (var image in Model.GalleryImages)
{
<div style="display: inline-block">
<img src="/Images/Uploads/Products/#Model.Id/Gallery/Thumbs/#image" />
#Html.ActionLink("delete", "DeleteImage", "Product", new { #class = "deleteimage", data_name = image })
</div>
}
<link href="~/Scripts/dropzone/basic.css" rel="stylesheet" />
<link href="~/Scripts/dropzone/dropzone.css" rel="stylesheet" />
#section Scripts{
<script src="~/Scripts/dropzone/dropzone.js"></script>
<script>
$(function () {
//preview image
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$("img#imgpreview").attr("src", e.target.result).width(200).height(200);
}
reader.readAsDataURL(input.files[0]);
}
}
$("#ImageUpload").change(function () {
readURL(this);
});
//dropzone js
Dropzone.options.dropzoneForm = {
acceptedFiles: "image/*",
init: function () {
this.on("complete", function (file) {
if (this.getUploadingFiles().length === 0 && this.getQueuedFiles().length === 0) {
location.reload();
}
});
this.on("sending", function (file, xhr, formData) {
formData.append("id", #Model.Id);
});
}
};
//dropzone js
$("a.deleteimage").click(function (e) {
e.preventDefault();
if (!confirm("confirm deletion"))
return false;
var $this = $(this);
var url = "/admin/shop/DeleteImage";
var imageName = $this.data("name");
$.post(url, { id: #Model.Id, imageName: imageName }, function (data) {
$this.parent().fadeOut("fast");
});
});
});
</script>
}
UPDATE:
What exactly do you expect as a column datatype when you model it as List<string>? SQL Server doesn't have any column data type to handle an arbitrary list of strings....
If you have an 1:n relationship between ProductModel and gallery images, you should really have a separate model class that holds the image information - e.g. MyImages. Then you could add a collection-style property
public virtual ICollection<MyImages> GalleryImages
to your ProductModel class.
SQL Server can't really handle List<string> as a column type .....
The steps needed to get this done are:
Change your C# model class (you've done this already)
Run add-migration migration-name so that an EF migration is added to your project (you seem to have skipped this step)
Run update-database to actually apply that migration to the database.
Only if you've completed ALL 3 steps in exactly this order are changes from your C# model class actually applied to the database - you CANNOT simply skip step #2 ....
Related
Hi friends,I am working on MVC 4 Razor and I am stuck in a situation
where Employee Personal Details form is to be filled in
steps(wizard)..for which i used jquery accordion control..for every
step i put an accordion..The html in each accordion section is
rendered from partial view through ajax call on every click of
respective accordion (i.e. <h3></h3> tag)..
On page load first/top accordion is active by default. My problem is
to restrict the user to click on next accordion until he/she fills the
presently active accordion correctly..
Here is my full code:
View:
#model XXX.ViewModels.PersonalDetailsViewModel
#{
ViewBag.Title = "PersonalDetails";
Layout = "~/Views/Shared/Template.cshtml";
}
#using (Html.BeginForm("Lifestyle", "Apply", FormMethod.Post, new { id = "personalDetailForm" }))
{
<div class="centerdiv margin_top20">
<div class="row">
#Html.ValidationSummary(true, "Please Correct the following errors:")
</div>
<div style="width: 1000px;">
<div id="Personalaccordion" class="acordion_div" style="padding: 10px; float: left;">
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetBasicDetailsView','personalDetailForm','BasicDetailsDiv');">
<p>
Basic Details<span id="BasicDetailsDivExp"></span>
</p>
</h3>
<div id="BasicDetailsDiv">
</div>
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetPersonalAddressView','personalDetailForm','PersonalAddressDiv');">
<p>
Address<span id="PersonalAddressDivExp"></span></p>
</h3>
<div id="PersonalAddressDiv">
</div>
</div>
<ul id="conlitue_ul" style="margin-top: 20px;">
<li style="margin-left: 140px;">
<input type="submit" class="compareBtn float_lt" value="Continue Buying >" id="continue" /></li>
</ul>
</div>
</div>
}
#Scripts.Render("~/bundles/PersonalDetails")
<script type="text/javascript">
PersonalModule.GetRenderingView('Apply/GetBasicDetailsView', '', 'BasicDetailsDiv');
</script>
My Controller:
public ActionResult PersonalDetails(int leadId)
{
var personalDetailsViewModel = LeadHelper.GetPersonalDetails(leadId);
return View(personalDetailsViewModel);
}
public ActionResult GetBasicDetailsView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.BasicDetails == null)
{
ModelInitializerHelper.InitilaizeBasicDetailsVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializeBasicLookup(personalDetailsViewModel);
return PartialView("Personal/BasicDetails", personalDetailsViewModel);
}
public ActionResult GetPersonalAddressView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.PersonalAddressDetails == null)
{
ModelInitializerHelper.IntializePersonalAddressVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializePersonalAddressLookup(personalDetailsViewModel);
return PartialView("Personal/PersonalAddress", personalDetailsViewModel);
}
My JS :
var PersonalModule = {
GetRenderingView: function (url, formId, containerID) {
var applicationurl = ApplicationRoot + '/' + url;
var objects = $('#BasicDetailsDivExp , #PersonalAddressDivExp' );
viewDivID = containerID;
GetAccordionView(applicationurl, formId, objects, containerID, 'accordion_plus', 'accordion_minus');
}
}
GetAccordionView: function (url, formId, objects, containerID, accordion_plus, accordion_minus) {
var formObjectData = null;
if (formId != undefined) {
formObjectData = $("#" + formId).serialize();
}
var renderView = function (data) {
$('#' + containerID).innerHtml = data;
}
ExpandAccordion(objects, containerID, accordion_plus, accordion_minus);
DoServerRequest(url, formObjectData, renderView);
}
ExpandAccordion: function (objects, spanIconID, accordion_plus, accordion_minus) {
var Objects = objects;
Objects.removeClass(accordion_minus);
Objects.addClass(accordion_plus);
$('#' + spanIconID + 'Exp').removeClass(accordion_plus).addClass(accordion_minus);
if (Browser.ie7) {
Objects.css("margin-top", "-22px");
}
}
DoServerRequest: function (url, data, funSuccess) {
$.ajax({
type: "POST",
url: url,
data: data,
async: false,
dataType: "json",
success: funSuccess,
error: function (errorResponse) {
if (errorResponse.readyState == 4 && errorResponse.status == 200) {
renderCurrentView(errorResponse.responseText)
}
else {
alert(errorResponse.responseText);
}
}
});
}
Please somebody help..I have heard lots of good thing about this forum
and this is my first Question...Thanks in advance..
I have removed my jquery validation attempt as it made the code
garbage thing Now I dont know what to write and where to write
If you are trying to validate data that has been added to form via Ajax after page load then you will need to use the rules method and add rules for these new elements. Jquery Validate has no way of knowing about them otherwise.
Example
Once you have loaded your new content via Ajax you need to find each element and add the necessary rules to them.
$('#yourDiv').find(".newElements").rules("add", {
required: true,
messages: {
required: "Bacon is required"
}
});
If you are using unobtrusive validate you may need to add your new elements to that also. See this SO question for more details.
Validating the Form
To check if the fields are valid, you will need to validate the form on click. This can be done using .validate(). You can then check if the form validated using .valid()
Example
$('#yourForm').validate();
if(!$('#yourForm').valid()) {
alert('Bacon is required');
}
var uri="#Url.Content("/Views/Shared/_LogOnPartial")";
$("#logindisplay").load(uri);
it give me error
Files with leading underscores ("_") cannot be served.
why the url don't work.
You can use following code to load Partial Views in ~/Views/Shared/ Folder.
<script type="text/javascript">
$(document).ready(function () {
$("#btnclick").click(function () {
var uri = '#Url.Content("_LogOnPartial")';
$("#logindisplay").load(uri);
});
});
</script>
HTML is,
<input type="button" id="btnclick" value="Load View" />
<div id="logindisplay">
</div>
You should use
"#Html.Partial("/Views/Shared/_LogOnPartial)
to load partial instead of #Url.Content("/Views/Shared/_LogOnPartial")
best practice is to define path for partials, Layouts & views earlier
in App_Start/RouteConfig write method like below
public static void RegisterViewEngines(ICollection engines)
{
/*
* {0} = view name
* {1} = controller name
*/
engines.Clear();
engines.Add(new RazorViewEngine
{
ViewLocationFormats = new[] { "~/Views/{0}.cshtml" },
MasterLocationFormats = new[] { "~/Views/Shared/{0}.cshtml" },
PartialViewLocationFormats = new[] { "~/Views/Partial/{0}.cshtml" }
});
}
then execute it in Globa.asax like
RouteConfig.RegisterViewEngines(ViewEngines.Engines);
then you can easily call partial like this
#Html.Partial("_LogOnPartial");
I have used Valums uploader plugins for file uploads in asp.net mvc 3. Following is the views which have form fields and ajax query upload button inside form. I am not sure that I am doing it right or not. What I have to change on view so that When I Choose the file to upload the form field's value is also send.
Views:
<link href="#Url.Content("~/Content/css/fileuploader.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Content/js/fileuploader.js")" type="text/javascript"></script>
#using (Html.BeginForm("Upload","AjaxUpload")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Upload Image File</legend>
<div class="editor-label">
#Html.Label("Select Language")
</div>
<div>
#Html.DropDownList("Language1", (SelectList) ViewBag.lang)
</div>
<div class="editor-label">
#Html.Label("Select Category")
</div>
<div>
#Html.DropDownList("ParentCategoryID", ViewBag.ParentCategoryID as SelectList)
</div>
<div id="file-uploader">
<noscript>
<p>
Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
</fieldset>
}
**<script type="text/javascript">
var uploader = new qq.FileUploader
({
element: document.getElementById('file-uploader'),
action: '#Url.Action("upload")', // put here a path to your page to handle uploading
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // user this if you want to upload only pictures
sizeLimit: 4000000, // max size, about 4MB
minSizeLimit: 0 // min size
});
</script>**
How Can I passed the value of form to controller of HTTPOST Action So that I can save data to the database. Here, I have Upload action which save the data in database but I don't know to retrieve to those value send by form post.
HttpPost Action
[HttpPost]
public ActionResult Upload(HttpPostedFileBase qqfile)
{
var wav = new PlayWav
{
Name = ***filename***,
CategoryID = ***value from category dropdown select list***,
UserID = repository.GetUserID(HttpContext.User.Identity.Name),
LanguageID = int.Parse(***value from language dropdown select list***),
UploadDateTime = DateTime.Now,
ActiveDateTime = DateTime.Now,
FilePath = "n/a"
};
if (qqfile != null)
{
// this works for IE
var filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(qqfile.FileName));
qqfile.SaveAs(filename);
return Json(new { success = true }, "text/html");
}
else
{
// this works for Firefox, Chrome
var filename = Request["qqfile"];
if (!string.IsNullOrEmpty(filename))
{
filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(filename));
using (var output = System.IO.File.Create(filename))
{
Request.InputStream.CopyTo(output);
}
**db.PlayWavs.Attach(wav);
db.SaveChanges();**
return Json(new { success = true });
}
}
return Json(new { success = false });
}
Didn't you read the documentation? There's a whole section entitled Sending additional params. Even an example is given:
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/server-side.upload',
// additional data to send, name-value pairs
params: {
param1: 'value1',
param2: 'value2'
}
});
Do we have better ways to handle it?
#foreach (var item in Model)
{
<div id="divDetail#{#item.CategoryId}"/>
#Ajax.ActionLink(
item.CategoryName,
"GetDetails",
new { id = item.CategoryId },
new AjaxOptions() { UpdateTargetId = string.Format("divDetail{0}", item.CategoryId) })
}
</div>
}
I would use the HTML.ActionLink helper method to generate the link and then use my custom jQuery ajax call to get the data. The advantage of doing this is i have full control so that i can do some manipulation of the response data before showing in the detail div.
I added a CSS class to the link so that i can be more specific (in selection of element) when binding my functionality.
#foreach (var item in Model)
{
<div id='divDetail#(item.ID)'></div>
#Html.ActionLink(item.CategoryName, "GetDetails", new { #id = item.CategoryId}, new {#id= "link-"+item.CategoryId, #class="lnkItem" })
}
and the script is
<script type="text/javascript">
$(function () {
$(".lnkItem").click(function (e) {
e.preventDefault();
var itemId = $(this).attr("id").split("-")[1]
$.get($(this).attr("href"), { id: itemId }, function (data) {
//i am free to do anything here before showing the data !
$("#divDetail" + itemId).html(data);
})
});
});
</script>
Requirment: I have a drop down and a table on my cshtml page. The drop down displays a list of vendors and the details corresponding to selected vendor are displayed in table. I am submitting the form using jquery when the value of the drop down changes.
Problem: How to cath selected value of drop down in controller?
Code:
#Html.DropDownList("VendorList", new SelectList(Model.vendorList, "vendorId", "vendorName"))
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
}
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
$('#VendorList').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
the code in my controller is:
[AcceptVerbs("POST")]
public ActionResult SearchResult(FormCollection collection)
{
try
{
string vendorName = collection["searchItem"].ToString();
vendorName = vendorName.Trim();
List<Vendor> vendorList = Queries.compiledVendorQuery(dbContext, vendorName).ToList<Vendor>();
if(vendorList.Count() == 0)
return View("EmptySearch");
Vendor selectedVendor = vendorList[0];
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorList = vendorList;
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
catch (Exception e)
{
return View("EmptySearch");
}
}
[AcceptVerbs("POST")]
public ActionResult VendorDetails(FormCollection collection)
{
**here comes the control after postback
require value of the selected item**
Vendor selectedVendor = ??
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
Since you're not really using the FormCollection, you could just use an int (or whatever the ID is on your model) in your action method:
[HttpPost]
public ActionResult VendorDetails(int vendorId = 0)
{
Vendor selectedVendor = // Load from your data source using vendorId
... // Do the rest of your work
}
In your HTML, move your #Html.DropDownListFor() into your form, rename it to the argument name, then submit the form as normal. Since the display doesn't seem to have any affect on what gets sent to the server, I would pull this out and just leave the #Html.DropDownListFor() in the form:
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
#Html.DropDownList("vendorId", new SelectList(Model.vendorList, "vendorId", "vendorName"))
}
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
<script type='text/javascript'>
$(document).ready(function () {
$('#vendorId').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
Edit
Take a look at this article about MVC's model binding for an idea of how vendorId gets injected from the submitted form. Basically, the binder will match property names with the name attribute (by default) to your model. In this case, our model is just an int.