Dropzone, how do I submit form with data and multiple images? - c#

I am using MVC in ASP.NET and want a Drag n Drop in my view. I would like to call a function in my controller when the images are dropped to verify them and show an OK to the user. When the user has finished typing in information and dropped the appropriate images he/she clicks "Fortsæt" (continue) and calls submit on the form.
This method should be called when an Image is dropped.
[HttpPost]
[Authorize(Roles = "host")]
public ActionResult UploadImages()
{
bool suc;
foreach (string s in Request.Files)
{
HttpPostedFileBase image = Request.Files[s];
string fileName = Request.Headers["X-File-Name"];
string fileExtension = "";
if (!string.IsNullOrEmpty(fileName))
fileExtension = Path.GetExtension(fileName);
suc = Verify(fileExtension);
}
return Json(suc);
}
This should be called when the user clicks "Continue"
[HttpPost]
[Authorize(Roles = "host")]
public ActionResult Create(FleaMarket model, HttpPostedFileBase[] images)
{
ConditionallySetUser(model, User);
foreach (var fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName.ToString()];
if (file != null && file.ContentLength > 0)
{
var image = HttpPostedFileBaseToByteArray(file);
model.Images.Add(new FleaImage
{
Image = image, FleaMarketId = model.EventId
});
}
}
db.FleaMarkets.Add(model);
db.SaveChanges();
ViewBag.HostID = new SelectList(db.Hosts, "HostId", "Name", model.HostId);
TempData["market"] = model;
return
RedirectToAction("AddStallImage", "FleaMarket");
}
Here are some snips of my View
#model FleaPortal.Models.Database.FleaMarket
<link href="~/Content/basic.css" rel="stylesheet" />
<link href="~/Content/dropzone.css" rel="stylesheet" />
<script src="~/Scripts/dropzone.min.js"></script>
#using (Html.BeginForm("Create", "FleaMarket", method: FormMethod.Post, htmlAttributes: new { #encType = "multipart/form-data",#class="dropzone", #id="dropzoneForm"}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.HostId)
<div class="row">
<div class="form-group col-sm-6">
#Html.LabelFor(model => model.HostId, "Arrangør")
<label class="text-box single-line form-control" id="Name">
#Html.DisplayFor(model => model.Host.UserProfile.UserName)
</label>
</div>
<div class="form-group col-sm-6">
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group col-sm-12">
#Html.LabelFor(model => model.Description)
#Html.EditorFor(model => model.Description, new { #class = "TextAreaInput" })
#Html.ValidationMessageFor(model => model.Description)
</div>
...
...
<div class="form-group col-sm-12">
<label>Stemningsbilleder</label>
<div id="dropzonePreview">
drop your images here
<div class="dz-default dz-message" data-dz-message="">
</div>
</div>
</div>
...
...
<div class="btn-group two-bt-group col-sm-12">
<button name="ButtonType" value="Continue" id="submitAll" type="submit" class="btn btn-success two-bt">#Resources.Views_Global_Continue</button>
<button name="ButtonType" value="Cancel" type="button" class="btn btn-danger two-bt" onclick="location.href='#Url.Action("Manage", "Account")'">#Resources.Views_Global_Cancel</button>
</div>
#section Scripts {
#Scripts.Render("~/bundles/datepicker")
#Scripts.Render("~/bundles/booking")
#Scripts.Render("~/bundles/dropzonescripts")
<script type="text/javascript">
$(document).ready(function() {
$(".form_date").datetimepicker({ format: 'yyyy-mm-dd', startView: 2, minView: 2 });
$(".form_time").datetimepicker({ format: 'hh:ii', startView: 1, maxView: 1 });
});
</script>
<script>
Dropzone.options.dropzoneForm = {
clickable: false,
//url: '/FleaMarket/UploadImages',
autoProcessQueue: false,
uploadMultiple: true,
paramName: "images",// Must match the name of the HttpPostedFileBase argument that the Upload action expects
maxFiles: 100,
autoQueue: false,
previewsContainer: "#dropzonePreview",
parallelUploads:100,
init: function () {
debugger;
this.on("success", function (file, responseText) {
file.previewTemplate.appendChild(document.createTextNode(responseText));
});
}
};
</script>
I have spent way too much time trying to figure this out, and I believe there might be a simple solution - I just don't know. ? Can someone help me figuring this out?
Many thanks in advance.

I ended up calling a method in my controller every time an image was uploaded. I assigned an ID to the imaged and passed it to my view like this:
Dropzone.autoDiscover = false;
$("div#dropzonePreview").dropzone(
{
url: '/FleaMarket/UploadImage',
paramName: "images",
autoProcessQueue: true,
addRemoveLinks: true,
//clickable: "#dropzonePreview",
uploadMultiple: true,
acceptedFiles: "image/*",
maxFiles: 100,
parallelUploads: 10,
dictInvalidFileType: "Dette er ikke et billede",
dictFileTooBig: "Billedet er for stort",
success: function(file, response) {
$('#ImageIds').val($('#ImageIds').val() + "," + response.Ids);
done();
}
});
#Html.HiddenFor(model => model.ImageIds);
<div class="form-group col-sm-12">
<label>Stemningsbilleder</label>
<div id="dropzonePreview" class="dropzone">
</div>
</div>

Related

Can't load image to partial view in edit view

In my application, previously I had issue with loading data to the partial view. With help I resolved that it. But still there is some issue here. Now when create the request I use this partial view to add data and image for user.
#model Asp_PASMVC.Models.GeneralItms
#using Asp_PASMVC.Infrastructure
#{
var z = Model.Attachment_Description;
var a = Model.Attachment_Amount;
var x = Model.Attachment;
}
<li style="padding-bottom:15px">
#using (Html.BeginCollectionItem("GeneralItmsList"))
{
#Html.HiddenFor(model => model.TempID)
<div class="form-horizontal" id="quickForm" novalidate="novalidate">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-md-5 col-sm-6">
<div class="form-group">
Select Item Description
<div class="col-md-10">
#Html.EditorFor(model => model.Attachment_Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Attachment_Description, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="form-group">
Attachment Amount
<div class="col-md-10">
<div class="input-group-prepend">
<span class="input-group-text">Rs.</span>
#Html.EditorFor(model => model.Attachment_Amount, new { htmlAttributes = new { #class = "form-control" } })
</div>
#Html.ValidationMessageFor(model => model.Attachment_Amount, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="form-group">
Attachment
<div class="col-md-10">
<input type="file" name="ImageData#(Model.TempID.ToString())" id="ImageData#(Model.TempID.ToString())" multiple="multiple" data-id="Img#(Model.TempID.ToString())" onchange="checkImage(this)" />
#Html.ValidationMessageFor(model => model.Attachment, "", new { #class = "text-danger" })
</div>
</div>
<img id="Img#(Model.TempID.ToString())" src="" alt="" width="100" height="100" class="ml-1" />
</div>
<button type="button" class="btn btn-danger" onclick="$(this).parent().remove();">Remove</button>
</div>
</div>
}
</li>
<script type="text/javascript">
$('.js-dropdown').select2({
width: '100%', // need to override the changed default
});
function checkImage(obj) {
var fileExtension = ['jpeg', 'jpg', 'png', 'gif', 'bmp'];
var ResponceImgId = $(obj).data('id');
if ($.inArray($(obj).val().split('.').pop().toLowerCase(), fileExtension) == -1) {
alert('error', 'Upload Error', 'Only .jpeg, .jpg, .png, .gif, .bmp formats are allowed.');
}
else {
var files = obj.files;
var reader = new FileReader();
name = obj.value;
reader.onload = function (e) {
$('#' + ResponceImgId).prop('src', e.target.result);
};
reader.readAsDataURL(files[0]);
}
}
</script>
When creating the request in the controller I have code like this
if (appRequest.GeneralItmsList != null)
{
foreach (GeneralItms item in appRequest.GeneralItmsList)
{
HttpPostedFileBase file = Request.Files["ImageData" + item.TempID];
item.Attachment = ConvertToBytes(file);
}
appRequest.General = new List<General>()
{
new General
{
GeneralItms = appRequest.GeneralItmsList,
}
};
}
and this method will convert the image to byte and pass to the controller to submit the data.
public ActionResult RetrieveImageG(int id)
{
var q = from temp in db.GeneralItms where temp.Id == id select temp.Attachment;
byte[] cover = q.First();
if (cover != null)
{
return File(cover, "image/jpg");
}
else
{
return null;
}
}
So Crete is working fine, and when in the edit view, I again called the same partial view to load the data inside the edit main view.
It's has 3 fields. Item Description , Amount and the attachment.
So It's loading the Item Description and amount properly, and it won't load the image again. Within the partial view I have put
#{
var z = Model.Attachment_Description;
var a = Model.Attachment_Amount;
var x = Model.Attachment;
}
to check is data passing to the view. attachment is shown in the Model.Attachment. But it won't show in the view. Can I get a help on this?
if you already happen to have the image loaded in your model: doing this way you can display the image
<img src="data:image;base64,#System.Convert.ToBase64String(Model.Attachment)" />

reCAPTCHA not visible in a MVC partialview page

I'm having troubles adding google reCAPTCHA to my page.
in the Layout I have added the Google Recaptcha js
_layout
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
<script src='https://www.google.com/recaptcha/api.js'></script>
<script type="text/javascript">
<script type="text/javascript">
$(document).ready(function () {
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
});
</script>
then in my index I select which form I want to show:
#Html.DropDownListFor(model => model.contactSelectListItems, new List<SelectListItem>
{
new SelectListItem() {Text = "option1", Value="option1"},
new SelectListItem() {Text = "option2", Value="option2"},
new SelectListItem() {Text = "option3", Value="option3"},
}, "--Choose--", new { id = "subject", #class= "dropdown-item" })
</div>
<div id="renderForms">
</div>
in both partial page there is a form where I do something similiar yet different viewmodels:
#using (Html.BeginForm("SendCustomerTeam", "ContactUs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CustomerTeamViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
#Html.LabelFor(model => model.Inquiry, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-12">
#Html.EditorFor(model => model.Inquiry, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Inquiry, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
<div class="col-sm-12">
<div id="NotRobot">
<label>Are you Human?</label>
<div id='recaptcha' class="col-sm-12 g-recaptcha"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]"
>
</div>
<div id="recaptchaMessage" data-verifyrecaptchatokenurl="#Url.Action("VerifyReCaptchaToken", "Home")" style="display:none;padding:10px;color:red;font-weight:bold;" class="error">You need to verify reCAPTCHA.</div>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-6">
<div class="row">
<div class="col-sm-9">
<input id="Send" type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div> etc...
In my controller I handle it like this thou I would like to handle the reCAPTCHA as an ajax call I have yet to figure out how to do that.
public ActionResult Index()
{
ViewData["ReCaptchaKey"] = System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"];
//do something here
}
public static bool ReCaptchaPassed(string gRecaptchaResponse, string secret)
{
HttpClient httpClient = new HttpClient();
var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={gRecaptchaResponse}").Result;
if (res.StatusCode != HttpStatusCode.OK)
{
//logger.LogError("Error while sending request to ReCaptcha");
return false;
}
string JSONres = res.Content.ReadAsStringAsync().Result;
dynamic JSONdata = JObject.Parse(JSONres);
if (JSONdata.success != "true")
{
return false;
}
return true;
}
[HttpPost]
public ActionResult SendCustomerTeam(CustomerTeamViewModel model)
{
ContactViewModel contactModel = new ContactViewModel();
contactModel.CustomerTeamModel = model;
ViewData["ReCaptchaKey"] = System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"];
if (ModelState.IsValid)
{
if (!ReCaptchaPassed(
Request.Form["g-recaptcha-response"], // that's how you get it from the Request object
System.Configuration.ConfigurationManager.AppSettings["RecaptchaPrivateKey"]
))
{
ModelState.AddModelError(string.Empty, "You failed the CAPTCHA, stupid robot. Go play some 1x1 on SFs instead.");
return View(contactModel);
}
}
My problem is the reCAPTCHA never appears on my page.
Edit:
I've tried the following simplification to see if I could find the issue.
SimplePageViewModel
public class simplePageViewModel
{
public string Name { get; set; }
}
SimplePagePartialView
#model Contact_Portal.Models.simplePageViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>simplePageViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="row">
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
<div class="col-sm-12">
<div id="NotRobot">
<label>Are you Human?</label>
<div id='recaptcha' class="col-sm-12 g-recaptcha" style="padding:10px;"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]">
</div>
<div id="recaptchaMessage" data-verifyrecaptchatokenurl="#Url.Action("VerifyReCaptchaToken", "Home")" style="display:none;padding:10px;color:red;font-weight:bold;" class="error">You need to verify reCAPTCHA.</div>
</div>
</div>
</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>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
in the controller I get the partial view shown through this line
return PartialView("View", contactModel.simplePageModel);
Still the same problem persist.
Could it be because I'm displaying my partial page containing the reCAPTCHA as part of an Jquery Ajax call ? like this:
$(document).ready(function () {
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
I've now tried a entire new project where I've simplified it all the way down to one html file:
Index.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
<link href="~/Content/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="~/Scripts/modernizr-2.6.2.js"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
#Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { #class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div id='recaptcha' class="col-sm-12 g-recaptcha" style="padding:10px;"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]"></div>
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>
Still it is not visible it never appears. why is it not working ?
could it be that ASP.NET MVC is not supported by Recaptcha from google?
Your script src is wrong:
<script src='https://www.google.com/recaptcha/api.js async defer'></script>
to
<script src='https://www.google.com/recaptcha/api.js'></script>
Also could you check deveoper console, if there any error?
Well I found a solution I'm not happy with it but it works.
in my Layout file I've made a section like this:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script type="text/javascript">
function enableBtn() {
document.getElementById("subject").disabled = false;
}
$(document).ready(function () {
document.getElementById("subject").disabled = true;
});
</script>
Then in my view I created this
<div class="g-recaptcha" data-sitekey="*********PublicKEY*************" data-callback="enableBtn"></div>
And it seems to be working.
I wish I could make it work in the partial view because now I have to have it no matter what else will happen and not just on a submit.
I don't know if I can verify this one server side anymore as it is also outside my form. ?
Anyone with a better option would be welcomed.
EDIT:
I found a better solution for me. I changed my ajax call like this:
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
if (!debug) {
document.getElementById("Send").disabled = true;
grecaptcha.render('Captcha', {
'sitekey': '**********PublicKey*********',
'callback': function() {
document.getElementById("Send").disabled = false;
},
'expired-callback': function() {
//document.getElementById("subject").selectedIndex = 0;
document.getElementById("Send").disabled = true;
//document.getElementById("renderForms").innerHTML = "";
}
});
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
Now it is working as I intended. At least in the user interface part.

c# mvc retrieve data from a view

I want to retrieve data from a view, it should work like this:
User fill a form available on the webpage
User clicks SEARCH button
Some function(s) collect the data and display them in another view
I tried all the basic tutorials and tips on others stackoverflow question but it still doesn't work. I don't know what I'm doing wrong...
Here's my code from the view:
section id="roomSearch">
<div class="banner">
<div class="banner-info">
<div class="container">
<div class="details-1">
#using (Html.BeginForm("UploadRoomSearchData", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="col-md-10 dropdown-buttons">
<div class="col-md-3 dropdown-button">
#Html.AntiForgeryToken()
<div class="input-group">
#Html.TextBoxFor(m => m.YourName, new { #class = "form-control has-dark-background", #placeholder = "Imię" })
#Html.ValidationMessageFor(m => m.YourName, "", new { #class = "text-danger" })
<!--<input class="form-control has-dark-background"
name="slider-name" id="slider-name" placeholder="Imię" type="text" required="">-->
</div>
</div>
<!---strat-date-piker---->
<link rel="stylesheet" href="~/Content/jquery-ui.css" />
<script src="~/Scripts/jquery-ui.js"></script>
<script>
$(function () {
$("#datepicker,#datepicker1").datepicker();
});
</script>
<!---/End-date-piker---->
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date" id="datepicker" type="text" value="Przyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Przyjazd';}">
<!-- #Html.TextBoxFor(m => m.CheckIn, new { #class = "date" })
#Html.ValidationMessageFor(m => m.CheckIn, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date1" id="datepicker1" type="text" value="Wyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Wyjazd';}">
<!--#Html.TextBoxFor(m => m.CheckOut, new { #class = "date1" })
#Html.ValidationMessageFor(m => m.CheckOut, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="section_1">
<select id="country" onchange="change_country(this.value)" class="frm-field required">
<option value="null">Dwuosobowy</option>
<option value="null">Jednoosobowy</option>
<option value="AX">Apartament</option>
<option value="AX">Gościnny</option>
</select>
</div>
</div>
<div class="clearfix"> </div>
</div>
<div class="col-md-2 submit_button">
<form >
<input type="submit" value="SZUKAJ">
<!-- <p> #Html.ActionLink("SZUKAJ", "Book1", "Home")</p>-->
</form>
</div>}
And here's my code in the controller. For now I try to retrieve only a name, to see if it's working.
[HttpPost]
public ActionResult UploadRoomSearchData(FormCollection form)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
//return RedirectToAction("Book1");
return Content(sbRoom.ToString());
}
I also tried something like this:
foreach(var v in form)
{
Write.Response("name:" + v);
}
I tried your code and it seems to work.
First I have the controller method to display the form
public ActionResult CreatePerson()
{
Person model = new Person();
return View(model);
}
Then the form:
#model RetrieveDataFromaView.Models.Person
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.YourName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.YourName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.YourName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="submit" class="btn btn-default" />
</div>
</div>
</div>
}
Which does a post to the controller method
[HttpPost]
public ActionResult CreatePerson(FormCollection formCollection)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
return Content(sbRoom.ToString());
}
This returns a view with only the content of the StringBuilder.
Maybe you are looking for RedirectToAction?
Hello you have this line inside the form:
#Html.AntiForgeryToken()
You can remove it or add the corresponding attribute to use it:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreatePerson(FormCollection formCollection)
{
///Your code here
}
Basically this is a token generated for the server to avoid requests from forms not generated by the server.
You have many ways of retrieving data from a form Post in ASP.NET MVC.
Using a Model
Usually, forms are created by specifying a Model type in the Razor view. You can use that type to retrieve the data. ASP.NET MVC will parse the body and populate the object in parameter for you.
Ex:
Controller:
public class HomeController: Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person p)
{
//Just for the sake of this example.
return Json(p);
}
}
Razor view
#model WebApplication2.Models.Person
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.LabelFor(m => m.FirstName): <br/>
#Html.TextBoxFor(m => m.FirstName)
</div>
<div>
#Html.LabelFor(m => m.LastName): <br/>
#Html.TextBoxFor(m => m.LastName)
</div>
<input type="submit" value="Submit" />
}
</div>
</body>
</html>
Using a FormsCollection
The FormsCollection object allows you to access the raw values of a form. It acts as a Dictionary for the Forms value. This is useful, especially when you have a dynamic model to parse, or if you just plain don't know about the Model type.
It's also pretty straightforward to use.
[HttpPost]
public ActionResult Index(FormCollection form)
{
var dict = form.AllKeys.ToDictionary(key => key, key => form[key]);
return Json(dict);
}
PS: I saw you are using Request[key]. It may just be me, but this call just looks like Dark magic, where you get data from who knows where (it uses the Query String, the cookies, the Request body, etc. It seems like it could be really problematic in some cases in the future. I much prefer knowing exactly where the data comes from. But that may just be me.
Conclusion
In conclusion, use the Model approach if you know exactly what should be in the Form. Use the FormCollection approach if you really need to. That's pretty much it.
Good luck.

The value of the property '$' is null or undefined, not a Function object

I'm developing purchase module with ASP.NET MVC 5. In Create view purchase, I'm using PartialView to load the detail purchase.
The Detail Purchase contains:
A textbox with browse button to input item
A textbox to input quantity
A button to add the item to the list (purchase detail)
When I clicked browse button the modal will show up with list of paged items (using PagedList). The modal form contains:
In modal header there are a textbox and a button for searching item name
In modal body to display list of items (load partially)
The error occurs if I searched item name
"The value of the property '$' is null or undefined, not a Function
object"
The jQuery script is already added by default at ~/Shared/_Layout.cshtml, and in the create view, I have added #Scripts.Render("~/bundles/jqueryval")
Code: View Create Purchase (Create.cshtml)
#model SalesSupportSystem.ViewModels.PurchaseOrderViewModel
#using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>PurchaseOrder</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.PurchaseOrderDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PurchaseOrderDate)
#Html.ValidationMessageFor(model => model.PurchaseOrderDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.InvoiceNo, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.InvoiceNo)
#Html.ValidationMessageFor(model => model.InvoiceNo)
</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>
}
#{ Html.RenderPartial("~/Views/PurchaseOrderDetail/_AddEdit.cshtml", Model.PurchaseOrderAddEditDetails); }
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/bootstrap-datepicker.js"></script>
<script>
$(document).ready(function () {
$(".date").datepicker({
autoclose: true,
clearBtn: true,
format: "dd/mm/yyyy",
todayBtn: "linked",
todayHighlight: true
});
$("#btnLookupItem").click(function (e) {
e.preventDefault();
$.ajax({
type: "GET",
url: "#Url.Content("~/INVENTSUM1/Lookup")",
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
$("#itemModal").modal("show");
});
});
$("#btnSubmitINVENTSUM1").click(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "#Url.Content("~/INVENTSUM1/Lookup")",
data: { filterValue: $("#FilterValue").val() },
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
});
});
});
function setINVENTSUM1(ITEMID, ITEMNAME) {
document.getElementById("ItemID").value = ITEMID;
document.getElementById("ItemName").value = ITEMNAME;
$("#itemModal").modal("hide");
}
</script>
}
PartialView (_AddEdit.cshtml)
#model SalesSupportSystem.ViewModels.PurchaseOrderDetailAddEditViewModel
<!-- Item Modal -->
<div class="modal fade bs-example-modal-lg" id="itemModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" id="btnCancelCUSTTABLE" title="Clear the selected input on form" class="close" data-dismiss="modal" data-toggle="tooltip" data-placement="left"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Select Item</h4>
#using (Html.BeginForm("Lookup", "INVENTSUM1"))
{
<div class="form-inline">
Find by name: <input type="text" id="FilterValue" name="FilterValue" class="form-control" placeholder="Enter keyword" value="" />
<input type="submit" id="btnSubmitCUSTTABLE" value="Search" class="btn btn-primary" />
</div>
}
</div>
<div class="modal-body" id="itemContainer">
...
</div>
</div>
</div>
</div>
#using (Html.BeginForm("AddEdit", "PurchaseOrderDetail", FormMethod.Get, new { #class = "form-inline" }))
{
<h4>Detail</h4>
<hr />
<fieldset>
<div class="form-inline">
<div class="form-group">
#Html.HiddenFor(model => model.ItemID)
<div class="input-group">
#Html.EditorFor(model => model.ItemName)
<div class="input-group-btn">
<button class="btn btn-primary" id="btnLookupItem">...</button>
</div>
</div>
</div>
<div class="form-group">
#Html.EditorFor(model => model.QuantityOrder)
</div>
<button class="btn btn-primary" id="btnAddItem">Add</button>
</div>
</fieldset>
}
Controller (INVENTSUM1Controller.cs)
public ActionResult Lookup(int? page)
{
var pagedItem = db.INVENTSUM1
.OrderBy(i => i.ITEMNAME)
.ToPagedList(page, 10);
return PartialView("_Lookup", pagedItem);
}
[HttpPost]
public ActionResult Lookup(string filterValue)
{
var pagedItem = db.INVENTSUM1
.Where(i => i.ITEMNAME.Contains(filterValue))
.OrderBy(i => i.ITEMNAME)
.ToPagedList(1, 10);
return PartialView("_Lookup", pagedItem);
}
PartialView (_Lookup.cshtml)
#model IEnumerable<SalesSupportSystem.Models.INVENTSUM1>
#using PagedList.Mvc;
#{
var pagedList = (PagedList.IPagedList)Model;
}
<div>
<table class="table table-striped table-hover table-condensed">
<tr>
<th></th>
<th>
#Html.DisplayNameFor(model => model.ITEMID)
</th>
<th>
#Html.DisplayNameFor(model => model.ITEMNAME)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td></td>
<td>#Html.DisplayFor(modelItem => item.ITEMID)</td>
<td>#Html.DisplayFor(modelItem => item.ITEMNAME)</td>
</tr>
}
</table>
</div>
Page #(pagedList.PageCount < pagedList.PageNumber ? 0 : pagedList.PageNumber) of #pagedList.PageCount
<div id="pager">
#Html.PagedListPager(pagedList, page => Url.Action("Lookup", new { page }))
</div>
<script>
$(document).ready(function () {
$("#pager").on("click", "a", function () {
if (this.href == "") {
return;
}
$.ajax({
type: "GET",
url: this.href,
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
});
return false;
});
});
</script>
Another question: as you can see in the lookup.cshtml code, I placed script at there. I've read from SO articles, it should not be placed in partialview, but I have no choice, if I placed in Create.cshtml, the paging will not work. Is there any workaround for this?

why the variable URL is undefined?

I have a problem with a variable that take the value undefined.
In the file Create.cshtml i have:
#using (Html.BeginForm("Create", "Enrollment", FormMethod.Post, new
{
id = "YearCourseFormId",
data_courseListAction = #Url.Action("CourseList")
})) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Enrollment</legend>
<div class="editor-label">
#Html.LabelFor(model => model.StudentId, "Student")
</div>
<div class="editor-field">
#Html.DropDownList("StudentId", ViewBag.Student as SelectList, String.Empty, new { #class = "chosen-select", data_placeholder = "Please Select a Student...",style="width:350px;" })
#Html.ValidationMessageFor(model => model.StudentId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Course.YearId, "Year")
</div>
<div class="editor-field">
#Html.DropDownList("YearId", ViewBag.Year as SelectList, String.Empty, new { #class = "chosen-select", data_placeholder = "Please Select a Year...",style="width:250px;" })
#Html.ValidationMessageFor(model => model.Course.YearId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CourseId, "Course")
</div>
<div class="editor-field">
#Html.DropDownList("CourseId", String.Empty)
#Html.ValidationMessageFor(model => model.CourseId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
In the Jquery File i have:
$(function () {
$('#YearId').change(function () {
var URL = $('#YearCourseFormId').data('courseListAction');
alert(URL);
$.getJSON(URL + '/' + $('#YearId').val(), function (data) {
var selectList = $("#CourseId");
selectList.empty();
var option = $('<option>');
selectList.append(option);
$.each(data, function (index, optionData) {
option = $('<option>').text(optionData.Text).val(optionData.Value);
selectList.append(option);
});
});
});
});
In this part alert(URL);the result is undefined.
In the EnrollmentController.cs i have:
public ActionResult CourseList(string ID)
{
int Year = int.Parse(ID);
var courses = from s in db.Courses
where s.YearId == Year
select s;
if (HttpContext.Request.IsAjaxRequest())
return Json(new SelectList(
courses.ToArray(),
"Id",
"CourseName")
, JsonRequestBehavior.AllowGet);
return RedirectToAction("Index");
}
But this method is not called due to error.
What is the problem?
Your form is rendered like this:
<form action="/Enrollment/Create" data-courselistaction="..." id="YearCourseFormId" method="post">
</form>
You can access using any of these:
$('#YearCourseFormId').data('courselistaction');
$('#YearCourseFormId').attr('data-courselistaction');
$('#YearCourseFormId').attr('data-courseListAction');
Given T.J. Crowder's comments about quirks with data(), it would probably be safer to go with one of the attr() solutions.
Edit - The plot thickens..
Chrome inspecter:
Source:
I'm not sure what the implications of that are, but my javascript snippet did work to get the value.

Categories

Resources