Recaptcha doesn't work with ajax and partial views - asp.net-mvc-4

I'm using Recaptcha in my MVC4 web app. It was working correctly when it was embedded in the form but when I moved the #Html.Raw(Html.GenerateCaptchaHelper()) to partial view and trying to call this partial view via ajax request, it doesn't work!
Extension code :
public static string GenerateCaptchaHelper(this HtmlHelper helper)
{
var captchaControl = new Recaptcha.RecaptchaControl
{
ID = "recaptcha",
Theme = "clean",
PublicKey = ************,
PrivateKey = **********************,
Language = "En"
};
var htmlWriter = new HtmlTextWriter(new StringWriter());
captchaControl.RenderControl(htmlWriter);
return htmlWriter.InnerWriter.ToString();
}
my partial view is has the code like :
<p>#Html.Raw(Html.GenerateCaptchaHelper())</p>
and inside my controller
public PartialViewResult Captcha()
{
return PartialView();
}
and inside my main view:
#using (Html.BeginForm("Login", "Account", new { returnUrl = ViewData["ReturnUrl"] }, FormMethod.Post,null))
{
#Html.AntiForgeryToken()
<form role="form">
<div class="form-group">
<label>#Html.LabelFor(m => m.Email)</label><br />
#Html.TextBoxFor(m => m.Email, null, new { #class = "form-control", autocomplete = "off" })
</div>
<div class="form-group">
<label>#Html.LabelFor(m => m.Password)</label><br />
#Html.PasswordFor(m => m.Password, new { #class = "form-control", autocomplete = "off" })
</div>
<div id="captchaView" class="form-group">
</div>
<button type="submit">Login</button>
</div>
</div>
</form>
}
and the javascript is :
$.ajax({
url: '/Account/Captcha',
type: 'GET',
success: function(data) {
$('#captchaView').html(data);
}
});
Could you please help me to figure out why?

Related

Auto Adjust height of multiline editor for in MVC using bootstrap

I have below editorfor which is multiline, I need to auto adjust height when user starts adding multiple email address in separate lines using bootstrap. Any code example is highly appreciated.
Model:
[DataType(DataType.MultilineText)]
public string AdditionalEmailAddressesText { get; set; }
View:
<div class="form-group">
#Html.LabelFor(m => m.AdditionalEmailAddressesText, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
#Html.EditorFor(m => m.AdditionalEmailAddressesText, new { htmlAttributes = new { #class = "form-control", placeholder = #Strings.Porting_AdditionalEmailAddressesSubtext } })
#Html.ValidationMessageFor(m => m.AdditionalEmailAddressesText)
</div>
</div>
For textarea tag, there's no auto-height attribute to make it adjust the height automatically. And for the [DataType(DataType.MultilineText)] annotation, it doesn't provide feature for setting rows and colums as well. So you have to write script code to add oninput event listener to change the style.
#model NewEvent
<h1>#ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
<div class="form-group">
#Html.LabelFor(m => m.Body, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
#Html.EditorFor(m => m.Body, new { htmlAttributes = new { #class = "form-control", placeholder = "placeholder" } })
#Html.TextAreaFor(model => model.Body, new {cols = 2, rows = 5})
#Html.ValidationMessageFor(m => m.Body)
</div>
</div>
#section scripts {
<script>
$("#Body").each(function () {
this.setAttribute("style", "height:" + (this.scrollHeight) + "px;overflow-y:hidden;");
}).on("input", function () {
this.style.height = "auto";
this.style.height = (this.scrollHeight) + "px";
});
</script>
}

How fix not working ActionResult Update in NET Core?

I'm learning about .NET Core and I'm using code from this tutorial. But my update sql is not working.
Here is the index view code:
public ActionResult Index(int? id)
{
ViewBag.Operation = id;
ViewBag.Name = db.Chars.ToList();
Chars Chars = db.Chars.Find(id);
return View(Chars);
}
As for now it work I see results from sql and here is the updated part:
public ActionResult Update(Chars Chars)
{
if (ModelState.IsValid)
{
db.Entry(Chars).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index", new { id = 0 });
}
Here is index.cshtml part:
#using (Html.BeginForm()
{
#foreach (var item in (IEnumerable<MVC__test_2.Chars>)ViewBag.Name)
{
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(modelItem => item.CharName, new { htmlAttributes = new { #class = "form-control" } })
#Html.HiddenFor(modelItem => item.CharID, new { id = item.CharID })
</div>
</div>
#Html.ActionLink("Index", "Index", new { id = item.CharID })
<input type="submit" value="Update" name="Update"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:block" : "display:none") />
}
}
According to the tutorial you provided , I made a demo to test and it updated the data well. The following is the working example , you could refer to and make the modification as per your need .
Model
public class Description
{
public int Id { get; set; }
public string Display { get; set; }
}
Controller
public IActionResult Index(int? id)
{
ViewBag.Operation = id;
ViewBag.Name = _context.Description.ToList();
Description description= _context.Description.Find(id);
return View(description);
}
public ActionResult Update(Description description)
{
if (ModelState.IsValid)
{
_context.Entry(description).State = EntityState.Modified;
_context.SaveChanges();
}
return RedirectToAction("Index", new { id = 0 });
}
Index.cshtml , you should hide the id of the modified data in the modification section.
#model WebApplication1.Models.Description
#using (Html.BeginForm("Update", "Home", FormMethod.Post))
{
#foreach (var item in (IEnumerable<WebApplication1.Models.Description >)ViewBag.Name)
{
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(modelItem => item.Display, new { htmlAttributes = new { #class = "form-control" } })
#Html.HiddenFor(modelItem => item.Id, new { id = item.Id })
</div>
</div>
#Html.ActionLink("Edit", "Index", new { id = item.Id })
}
// Create or Update data
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<fieldset>
<legend> <b>Entry Screen</b></legend>
<div class="form-group">
#Html.LabelFor(model => model.Display, new { #class = "control-label col-md-2" })
#Html.HiddenFor(model => model.Id)
<div class="col-md-10">
#Html.EditorFor(model => model.Display)
#Html.ValidationMessageFor(model => model.Display)
</div>
</div>
<div class="form-group">
<p>
<input type="submit" value="Create" name="Create"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:none" : "display:block") />
<input type="submit" value="Update" name="Update"
style=#((ViewBag.Operation != null && Convert.ToInt32(ViewBag.Operation) > 0) ? "display:block" : "display:none") />
</p>
</div>
</fieldset>
</div>
}

File upload in MVC 5 when used in bootstrap modal returns null

I'm trying to allow file uploading on modal popup using bootstrap modal popup.
But it always returns null for type = "file"
I've tried following solutions but no luck:
File upload in MVC when used in bootstrap modal returns null
it always return null. If I run this directly as separate page then it works fine but only having problem with popup.
I tried to change the content type on ajax but then its giving me this error "required anti-forgery form field __requestverificationtoken is not present"
I've tested what does page post using development tools:
enter image description here
here are my codes:
controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Create([Bind(Include = "ID,FileName,Link,SourceType,Comments,SourceDate,DateCreated,DateModified,ProjectID")] ProjectSource projectSource, HttpPostedFileBase uploadFile)
{
if (ModelState.IsValid)
{
//upload method 1
var fileSavePath = "";
if (HttpContext.Request.Files.AllKeys.Any())
{
// Get the uploaded image from the Files collection
var httpPostedFile = HttpContext.Request.Files[0];
if (httpPostedFile != null)
{
// Validate the uploaded image(optional)
// Get the complete file path
fileSavePath = (HttpContext.Server.MapPath("~/xyz/") + httpPostedFile.FileName);
// Save the uploaded file to "UploadedFiles" folder
httpPostedFile.SaveAs(fileSavePath);
}
}
//upload method 2
if (uploadFile != null && uploadFile.ContentLength > 0)
{
try
{
string path = Path.Combine(Server.MapPath("~/xyz/"),
Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(path);
ViewBag.Message = "File uploaded successfully";
}
catch (Exception ex)
{
ViewBag.Message = "ERROR:" + ex.Message.ToString();
}
}
else
{
ViewBag.Message = "You have not specified a file.";
}
db.ProjectSources.Add(projectSource);
await db.SaveChangesAsync();
return " File : " + ViewBag.Message + " == " + fileSavePath;
}
return " File : " + ViewBag.Message +" === "+sb.ToString();
}
view:
#model CharterPortal.Models.ProjectSource
#{
Layout = "";
#Scripts.Render("~/Scripts/jquery-2.2.3.min.js")
#Scripts.Render("~/Scripts/moment.min.js")
#Scripts.Render("~/Scripts/bootstrap.min.js")
#Scripts.Render("~/Scripts/bootstrap-datetimepicker.min.js")
#Scripts.Render("~/Scripts/bootstrap.fd.js")
}
×
Add new Source
#using (Html.BeginForm("Create", "ProjectSource", FormMethod.Post, new { enctype = "multipart/form-data" , #id="ajaxForm"}))
{
#Html.AntiForgeryToken()
<div class="modal-body">
<div class="form-horizontal">
#*#Html.ValidationSummary(true, "", new { #class = "text-danger" })*#
<div class="form-group">
#Html.Label("Source file", htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.FileName, new { htmlAttributes = new { #class = "form-control" } })
#*<input type="file" name="uploadFile" />*#
#Html.TextBox("uploadFile",null, new { #class = "form-control", type = "file" })
#*Add file*#
#Html.ValidationMessageFor(model => model.FileName, "", new { #class = "text-danger" })
</div>
</div>
#*<div class="form-group">
<div class="col-md-10" id="files" style="padding-left:40px;">
</div>
</div>*#
<div class="form-group">
#Html.LabelFor(model => model.Link, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.Link, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Link, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SourceType, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
#Html.EditorFor(model => model.SourceType, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SourceType, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Comments, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6" style="color:black;">
#Html.TextAreaFor(model => model.Comments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Comments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SourceDate, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6" style="color:black;">
#Html.EditorFor(model => model.SourceDate, new { htmlAttributes = new { #class = "form-control datepicker datefield" } })
#Html.ValidationMessageFor(model => model.SourceDate, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-med btn-orange" data-dismiss="modal">Cancel</button>
<input class="btn btn-med btn-orange" type="submit" name="submit" value="Add" />
</div>
}
ajax:
$('form', dialog).submit(function (event) {
event.preventDefault();
$.ajax({
url: this.action,
type: this.method,
async: true,
data: $(this).serialize(),
contentType:this.enctype,
success: function (result) {
if (result) {
alert(result)
//Refresh
} else {
alert(result)
}
}
});
return false;
});
I hope to get good working solution for this:
thanks in advance for your time.
Thanks
Ive been using this block of code to solve this problem and ModelState.IsValid in partials for about a year. cheers.
$(function () {
window.addEventListener("submit", function (e) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = xhr.responseText;
}
}
}
};
xhr.send(new FormData(form));
}
}
}, true);
$('#modal').on('shown.bs.modal', function () {
$.validator.unobtrusive.parse($(this));
});
$('#modal').on('hidden.bs.modal', function () {
$('#spinner').remove();
});
$.ajaxSetup({ cache: false });
});

ASP.Net MVC: When form post then one view model property getting null

i have simple form where one dropdown and one submit button. i have two index function one for get and one for form post. when i select a product from dropdown and click on submit button then my index action getting invoke but there i notice my products property getting null. see my code please and tell me where i made the mistake.
view code
#model AuthTest.Models.SampleViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DateValTest</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Products, htmlAttributes: new { #class = "control-label col-md-2", style = "padding-top:0px;" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedProductId, new SelectList(Model.Products, "ID", "Name"), "-- Select Product--")
#Html.ValidationMessageFor(model => model.SelectedProductId, "", 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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
model code
public class Product
{
public int ID { set; get; }
public string Name { set; get; }
}
public class SampleViewModel
{
[Display(Name = "Products")]
public List<Product> Products { set; get; }
[Required(ErrorMessage = "Select any one")]
public int SelectedProductId { set; get; }
}
controller code
public class TestValController : Controller
{
// GET: TestVal
public ActionResult Index()
{
var SampleVM = new SampleViewModel();
SampleVM.Products = new List<Product>
{
new Product{ ID=1, Name="IPhone" },
new Product{ ID=2, Name="MacBook Pro" },
new Product{ ID=3, Name="iPod" }
};
return View(SampleVM);
}
[HttpPost]
public ActionResult Index(SampleViewModel vm)
{
var SampleVM = new SampleViewModel();
SampleVM.Products = new List<Product>
{
new Product{ ID=1, Name="IPhone" },
new Product{ ID=2, Name="MacBook Pro" },
new Product{ ID=3, Name="iPod" }
};
if (ModelState.IsValid)
return View(vm);
else
return View(SampleVM);
}
}
when i debug second action then i saw vm products property getting null
please tell me where i made the mistake?
thanks
You are not making any mistake, You are not getting the list of products back because you are not including them in the HTML input form.
If you want to include the list of products you can add the following inside the input form
#for (int i = 0; i < Model.Products.Count(); i++)
{
<div>
#Html.HiddenFor(model => Model.Products[i].Name)
#Html.HiddenFor(model => Model.Products[i].ID)
</div>
}
#Mou,
Please modify your razor view and try this.
In Razor View nowhere you have specified the Http verb(Get,Post).
#using (Html.BeginForm("Index", "TestVal", FormMethod.Post)

ajax beginform mvc callback

I have a single page with multiple partials set up. I want to be able to validate and update each partial seperatly. The validation works BUT when I type in a correct value and press save the page goes to the partial view instead of staying on the single page. What am I doing wrong here?
This is my main page :
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Action("Detail", new { id = i })
</div>
}
The partial is created like this:
#{
var idTest = "Test_" + Model.Id;
var ajaxOptions = new AjaxOptions
{
UpdateTargetId = #idTest,
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace
};}
#using (Ajax.BeginForm("Detail", ajaxOptions))
{ #Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Test</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Gemeente, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Gemeente, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Gemeente, "", new { #class = "text-danger" })
</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>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
This is the simple model:
public class Test
{
public int Id { get; set; }
[Required(ErrorMessage = "Gelieve een gemeente op te geven")]
public string Gemeente { get; set; }
}
These are the actions:
[HttpGet]
public ActionResult Detail(int id)
{
Models.Test model = new Models.Test();
model.Id = id;
return View(model);
}
[HttpPost]
public ActionResult Detail(Models.Test model)
{
if(ModelState.IsValid)
{
return PartialView(model);
}
return PartialView(model);
}
Add these lines to your view and also use #Html.Partial as shown below
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
so that your main view is
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Partial("Detail", new Test { Id = i })}
</div>
}
Scripts would be for unobtrusive ajax so that your ajax button works and Html.Partial so that first time when you load your page in foreach only partial view is rendered (not the full view)