Use recaptcha v3 without form and button - recaptcha

I would like to use recaptcha on our forms but our forms are specific as they are made by our CMS Sitefinity. They have no <form> eitheir <button>. Its structure looks like this:
<div class="sfFormsEditor sfTopLbls ">
[...]
<div class="g-recaptcha" data-sitekey="Site key"></div>
<div class="sfFormSubmit sfSubmitBtnMedium">
<input type="submit" value="Envoyer la demande" data-sitekey="Site key" data-callback="onSubmit" data-action="submit">
</div>
</div>
I tried to use this script:
<script src='https://www.google.com/recaptcha/api.js'></script>
<script>
$(".sfFormSubmit input").attr('data-sitekey','Site key');
$(".sfFormSubmit input").attr('data-callback','onSubmit');
$(".sfFormSubmit input").attr('data-action','submit');
$(document).ready(function(){
$(".sfFormSubmit input").on('click',function(){
e.preventDefault();
grecaptcha.execute('Site key', {action: 'submit'});
});
});
</script>
The captcha is visible but when filling the form without clicking on the captcha, the form is submitted.
Is there a way to use recaptcha on such a form?
Thank you
Best
Sophie

You need to build a custom field control. For webforms, you can start here:
https://www.progress.com/documentation/sitefinity-cms/tutorial-build-a-custom-field-control-webforms-
It may look something like this:
ReCaptcha.ascx
<%# Control Language="C#" %>
<%# Register Assembly="Telerik.Sitefinity" TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" %>
<% if ( !Request.RawUrl.ToLower().Contains("/sitefinity/content/forms/entries/") ) { %>
<script src='https://www.google.com/recaptcha/api.js'></script>
<asp:Label runat="server" ID="titleLabel" CssClass="sfTxtLbl" Text="Captcha" AssociatedControlID="TextBox1" Visible="false" />
<div class="sfFieldWrp" style="display: none;">
<asp:TextBox ID="TextBox1" CssClass="sfTxt" runat="server" Text="OK" />
<sf:SitefinityLabel runat="server" ID="descriptionLabel" WrapperTagName="div" CssClass="sfDescription" />
<sf:SitefinityLabel runat="server" ID="exampleLabel" WrapperTagName="div" CssClass="sfExample" />
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="g-recaptcha" data-sitekey="__YourReCaptchaSiteKey___"></div>
</div>
<% } %>
ReCaptcha.cs
// not including the full code, as most of it is auto-generated, but here are
// the most important methods:
public override bool IsValid()
{
// check the captcha with google
var encodedResponse = HttpContext.Current.Request.Form["g-Recaptcha-Response"];
var isCaptchaValid = ReCaptchaModel.Validate(encodedResponse);
return isCaptchaValid;
}
ReCaptchaModel.cs
public class ReCaptchaModel
{
public bool Success { get; set; }
public List<string> ErrorCodes { get; set; }
public static bool Validate(string encodedResponse)
{
if (string.IsNullOrEmpty(encodedResponse)) return false;
var client = new WebClient();
var secret = __YourReCaptchaSecretKey__ ;
if (string.IsNullOrEmpty(secret)) return false;
var googleReply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, encodedResponse));
var serializer = new JavaScriptSerializer();
var reCaptcha = serializer.Deserialize<ReCaptcha>(googleReply);
return reCaptcha.Success;
}
}
ReCaptcha.js
Type.registerNamespace("SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha");
SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha.ReCaptcha = function (element) {
this._textbox = null;
this._dataFieldName = null;
SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha.ReCaptcha.initializeBase(this, [element]);
}
SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha.ReCaptcha.prototype = {
/* --------------------------------- set up and tear down ---------------------------- */
/* --------------------------------- public methods ---------------------------------- */
// Gets the value of the field control.
get_value: function () {
return jQuery(this._textbox).val();
},
// Sets the value of the text field control depending on DisplayMode.
set_value: function (value) {
jQuery(this._textbox).val(value);
},
/* --------------------------------- event handlers ---------------------------------- */
/* --------------------------------- private methods --------------------------------- */
/* --------------------------------- properties -------------------------------------- */
get_textbox: function () {
return this._textbox;
},
set_textbox: function (value) {
this._textbox = value;
},
get_dataFieldName: function () {
return this._dataFieldName;
},
set_dataFieldName: function (value) {
this._dataFieldName = value;
}
}
SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha.ReCaptcha.registerClass('SitefinityWebApp.CustomControls.FormControls.CustomFormWidgets.ReCaptcha.ReCaptcha', Telerik.Sitefinity.Web.UI.Fields.FieldControl);

Related

Handling Razor Dropdowns for auto load values

I have two dropdowns in the view but one relies on the selected value from the other. But how could i load values into the second dropdown after selecting a value from the other? The second dropdown should load values basing on the id selected from the other dropdown.
<div class="form-group">
<label asp-for="BankId" class="control-label col-xs-2"></label>
<div class="col-xs-4">
<select class="form-control" asp-for="BankId" asp-items=#bank>
<option>--- select bank ---</option></select>
</div>
</div>
<div class="form-group">
<label asp-for="BankBranchId" class="control-label col-xs-2"></label>
<div class="col-xs-4">
<select class="form-control" asp-for="BankBranchId" asp-items=#bankbranches>
<option>--- select bank branch ---</option></select>
</div>
</div>
BankBranch should fill values basing on the bank selected from up
Below is example for bank and branches.
you can try out something
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width"/>
<title>Index</title>
</head>
<body>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.DropDownListFor(m => m.bank, Model.bank, "Please select", new { onchange = "document.forms[0].submit();" })
<br/>
<br/>
#Html.DropDownListFor(m => m.branches, Model.branches, "Please select", new { disabled = "disabled" })
<br/>
<br/>
<input type="submit" value="Submit"/>
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$(function () {
if ($("#bank option").length > 1) {
$("#bank").removeAttr("disabled");
}
if ($("#branches option").length > 1) {
$("#branches").removeAttr("disabled");
}
if ($("#bank").val() != "" && $("#branches").val() != "") {
var message = "Bank: " + $("#CountryId option:selected").text();
message += "\nbranck: " + $("#StateId option:selected").text();
alert(message);
}
});
</script>
</body>
</html>
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
// populate bank values
foreach (var bankent in entities.bank)
{
model.bank.Add(new SelectListItem { Text = bankent.bank, Value = bankent.id.ToString() });
}
return View(model);
}
[HttpPost]
public ActionResult Index(int? bank)
{
// populate bank values
foreach (var bankent in entities.bank)
{
model.bank.Add(new SelectListItem { Text = bankent.bank, Value = bankent.id.ToString() });
}
if (bank.HasValue)
{
//populate branches based on bank id
foreach (var state in branches)
{
model.branches.Add(new SelectListItem { Text = state.branches, Value = state.StateId.ToString() });
}
}
return View(model);
}
}
for more detail check out Populate one DropDownList based on another DropDownList selected value in ASP.Net MVC

Many to Many Relation Popup

basically from embedded field and new to MVC/ASP.net, learning.
I have 2 entities with Many to Many relation.
It is working fine i am able to assign relation bet
Heading
ween them using checkbox.
I want to implement the following:
On Create page of Entity 1, Relative Entity 2 list is shown in table with Link and Unlink buttons.
Find below Image:
Link button will open up the popup which will show Entity 2 listing which is not there in the relation with the Entity 1.
User will select the required Entity 2 using checkbox and press 'Submit button.
On pressing Submit button, the selected Entity 2 objects are added to the **Entity 2 ** table in the Create view and popup closes.
On Saving create view will save everything with relation.
I hope I'm not asking too much... Not able to judge.
Thanks in advance.
Already Working:
1) I am able to open the model using bootstrap modal popup approach and pass the Entity 2 list to it.
2.) I am able to display the list in table.
To achieve:
1) Populate Entity 2 list in popup view with objects which are not in the Entity 2 table in the main view.
2) Have Checkbox in Popup table for selection.
3) Get the selected Entity 2 row details to main view without posting to controller.
4) Update Entity 2 table in the main view with the selected rows.
5) Save to table when save button is pressed..
Entity 1:
public partial class JobPost
{
public JobPost()
{
this.JobTags = new HashSet<JobTag>();
}
public int JobPostId { get; set; }
public string Title { get; set; }
public virtual ICollection<JobTag> JobTags { get; set; }
}
Entity 2:
public partial class JobTag
{
public JobTag()
{
this.JobPosts = new HashSet<JobPost>();
}
public int JobTagId { get; set; }
public string Tag { get; set; }
public virtual ICollection<JobPost> JobPosts { get; set; }
}
public class TempJobTag
{
public int JobTagId { get; set; }
public string Tag { get; set; }
public bool isSelected { get; set; }
}
View Model:
public class JobPostViewModel
{
public JobPost JobPost { get; set; }
public IEnumerable<SelectListItem> AllJobTags { get; set; }
private List<int> _selectedJobTags;
public List<int> SelectedJobTags
{
get
{
if (_selectedJobTags == null)
{
_selectedJobTags = JobPost.JobTags.Select(m => m.JobTagId).ToList();
}
return _selectedJobTags;
}
set { _selectedJobTags = value; }
}
}
Entity 1 Controller:
// GET: JobPosts/Create
public ActionResult Create()
{
var jobPostViewModel = new JobPostViewModel
{
JobPost = new JobPost(),
};
if (jobPostViewModel.JobPost == null)
return HttpNotFound();
var allJobTagsList = db.JobTags.ToList();
jobPostViewModel.AllJobTags = allJobTagsList.Select(o => new SelectListItem
{
Text = o.Tag,
Value = o.JobTagId.ToString()
});
return View(jobPostViewModel);
}
// POST: JobPosts/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(JobPostViewModel jobpostView)
{
if (ModelState.IsValid)
{
var newJobTags = db.JobTags.Where(
m => jobpostView.SelectedJobTags.Contains(m.JobTagId)).ToList();
var updatedJobTags = new HashSet<int>(jobpostView.SelectedJobTags);
foreach (JobTag jobTag in db.JobTags)
{
if (!updatedJobTags.Contains(jobTag.JobTagId))
{
jobpostView.JobPost.JobTags.Remove(jobTag);
}
else
{
jobpostView.JobPost.JobTags.Add((jobTag));
}
}
db.JobPosts.Add(jobpostView.JobPost);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(jobpostView);
}
public ActionResult ViewJobPostTagPopUp()
{
var allJobTagsList = db.JobTags.ToList();
foreach (JobTag jobTag in db.JobTags)
{
if (jobTag.JobTagId == 1)
{
allJobTagsList.Remove(jobTag);
}
}
List<TempJobTag> tmpJobTags = new List<TempJobTag>();
foreach (JobTag jobTag in db.JobTags)
{
TempJobTag tmpJT = new TempJobTag();
tmpJT.Tag = jobTag.Tag;
tmpJT.JobTagId = jobTag.JobTagId;
tmpJobTags.Add(tmpJT);
}
return PartialView("JobTagIndex", tmpJobTags);
}
[HttpPost]
//[ValidateAntiForgeryToken]
public JsonResult ViewJobPostTagPopUp(List<TempJobTag> data)
{
if (ModelState.IsValid)
{
}
return Json(new { success = true, message = "Some message" });
}
Main View:
#model MVCApp20.ViewModels.JobPostViewModel
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>JobPost</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.JobPost.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.JobPost.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.JobPost.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.AllJobTags, "JobTag", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(m => m.SelectedJobTags, Model.AllJobTags)
</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("+", "ViewJobPostTagPopUp", "JobPosts",
null, new { #class = "modal-link btn btn-success" })
</div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script src="~/Scripts/jquery-2.1.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
</script>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Partial Popup View:
#model IEnumerable<MVCApp20.Models.TempJobTag>
#{
ViewBag.Title = "Index";
//Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Tags</h2>
#using (Html.BeginForm())
{
<table id="datatable" class="table">
<tr>
<th>
<input type="checkbox" id="checkAll" />
</th>
<th>
#Html.DisplayNameFor(model => model.Tag)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#*#Html.EditorFor(modelItem => item.isSelected)*#
<input type="checkbox" class="checkBox"
value="#item.isSelected" />
</td>
<td>
#Html.DisplayFor(modelItem => item.Tag)
</td>
</tr>
}
</table>
#*<div>
#Html.ActionLink("Done", "ViewJobPostTagPopUp", "JobPosts",
null, new { #class = "modal-link btn btn-primary" })
</div>*#
<div>
<button type="submit" id="btnSubmit" class=" btn btn-primary">Submit</button>
</div>
}
<script>
$(document).ready(function () {
$("#checkAll").click(function () {
$(".checkBox").prop('checked',
$(this).prop('checked'));
});
});
$(function () {
$('#btnSubmit').click(function () {
var sdata = new Array();
sdata = getSelectedIDs();
var postData = {};
postData[values] = sdata;
$.ajax({
url: '#Url.Action("ViewJobPostTagPopUp")',
type: "POST",
type: this.method,
//data: $(this).serialize(),
data: JSON.stringify(product),
success: function (result) {
alert("success");
},
fail: function (result) {
alert("fail");
}
});
//alert("hiding");
//$('#modal-container').modal('hide');
});
});
function getSelectedIDs() {
var selectedIDs = new Array();
var i = 0;
$('input:checkbox.checkBox').each(function () {
if ($(this).prop('checked')) {
selectedIDs.push($(this).val());
i++;
alert("got" + i);
}
});
return selectedIDs;
}
</script>

AjaxBegin form and DataAnnotation don't work

I have a BeginForm with DataAnnotation on the model but they don't work properly.
model.cs
public class modelx
{
.....
[Required(AllowEmptyStrings = false, ErrorMessage = "Time_Step is required"]
public String time_step_serialization { get; set; }
.....
{
view.cs
<script text="text/javascript">
function OnSuccess() {
windows.location.href = '#Url.Action(.....);
}
</script>
<table class....>
#using (Ajax.BeginForm(.........., new AjaxOptions()
{
....
OnSuccess="OnSuccess"
}))
{
#Html.ValidationSummary()
<td>
#Html.TextBoxFor(model => model.time_step_serialization)
#Html.ValidationMessageFor(model => model.time_step_serialization)
</td>
.....
</td>
}
</table>
Controller.cs
I don't want to check nothing server side.
I setted the right configuration on the web.config and I imported the right libraries js:
jquery-1.7.1.min.js
jquery.unobtrusive-ajax.min.js
jquery.validate.js
jquery.validate.unobtrusive.js
What is the problem?
The html generated at runtime for the field is:
<input data-val="true" data-val-required="Time_step is required" id="time_step_serialization" name="time_step_serialization" type="text" value>
<span class="field-validation-valid" data-valmsg-for="time_step_serialization" data_valmsg_replace="true"></span>
Try to use valid before sending data.
function save(){
var valid = $("#FormName").valid();
if (!valid) return false;
// post data
}

Why are my required attributes of my model not work in MVC3

In my class file where my model is I have required attributes such as:
[Required]
[Range(0, 99, ErrorMessage = "Sorry, you must select a range between 0 - 99.")]
public int MaxConcurrentUsers { get; set; }
So you would think that when I click the submit button on the page to post the values, that because I have typed an incorrect value for MaxConcurrentUsers it wouldn't reach the actionResult method in my C# code. But it does. One thing I have noticed is that my modelstate .valid is false, but I want the client to stop it from getting to that method. What am I doing wrong?
My model
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UserManager.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class vw_UserManager_Model
{
public string rowtype { get; set; }
public System.Guid applicationid { get; set; }
public System.Guid userid { get; set; }
// [StringLength(12, MinimumLength = 6,
//ErrorMessage = "Username must be between 6 and 12 characters.")]
public string UserName { get; set; }
[Required]
[Range(0, 99, ErrorMessage = "Sorry, you must select a range between 0 - 99.")]
public int MaxConcurrentUsers { get; set; }
[Required(ErrorMessage = "First name is a required field")]
[Display(Name = "First name")]
public string firstname { get; set; }
[Required(ErrorMessage = "Last name is a required field")]
[Display(Name = "Last name")]
public string lastname { get; set; }
public string salutation { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required(ErrorMessage = "Email is required.")]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string email { get; set; }
public string group_name { get; set; }
public Nullable<long> group_id { get; set; }
public int moduleid { get; set; }
public Nullable<int> session_status { get; set; }
public Nullable<int> islockedout { get; set; }
public Nullable<bool> isactive { get; set; }
public bool IsApproved { get; set; }
public bool alf { get; set; }
public bool brad { get; set; }
public string module_name { get; set; }
public string CompanyName { get; set; }
public string CompanySearch { get; set; }
public string selected_module { get; set; }
public string selected_group { get; set; }
public string selected_moduleAlf { get; set; }
public string selected_moduleBrad { get; set; }
public string selected_groupAlf { get; set; }
public string selected_groupBrad { get; set; }
}
}
My view
#model UserManager.Models.vw_UserManager_Model
<h2 style="padding-left: 25px;">
Create user</h2>
#using (Html.BeginForm())
{
<!-- ALF/BRAD selection -->
#Html.ValidationSummary(true)
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Select module type:</legend>
<div class="module-selection">
#Html.Label("Select ALF")
<input type="checkbox" checked="checked" id="chkAlf" name="selection" value="Alf"
onclick="chkSelection()" />
#Html.Label("Select BRAD")
<input type="checkbox" id="chkBrad" name="selection" value="Brad" onclick="chkSelection()" />
</div>
</fieldset>
<!-- Module selection -->
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Select module:</legend>
<div id="alfModules">
#{Html.RenderAction("_CreateUserModulesAlf", "UserManager");}
</div>
<br />
<div id="bradModules">
#{Html.RenderAction("_CreateUserModulesBrad", "UserManager");}
</div>
</fieldset>
<!-- Check if group exists -->
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Group Checker</legend>
<div id="createuser-groupnamesearch">
#{Html.RenderAction("_txtGroupSearchForm", "UserManager");}
</div>
</fieldset>
<fieldset style="width: 400px; padding-left: 15px;">
<legend>New User Details</legend>
<div class="editor-label">
#Html.LabelFor(Model => Model.salutation)
</div>
<div class="editor-field">
#Html.DropDownListFor(Model => Model.salutation, new List<SelectListItem>
{
new SelectListItem{ Text="Mr", Value = "Mr" },
new SelectListItem{ Text="Mrs", Value = "Mrs" },
new SelectListItem{ Text="Miss", Value = "Miss" },
new SelectListItem{ Text="Ms", Value = "Ms" },
new SelectListItem{ Text="Dr", Value = "Dr" }
})
#Html.ValidationMessageFor(model => Model.salutation)
</div>
<div id="createuser-usernamesearch">
#{Html.RenderAction("_txtUsernameSearch", "UserManager");}
</div>
<div class="editor-label">
#Html.Label("Firstname")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.firstname)
#Html.ValidationMessageFor(model => Model.firstname)
</div>
<div class="editor-label">
#Html.Label("Surname")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.lastname)
#Html.ValidationMessageFor(model => Model.lastname)
</div>
<div class="editor-label">
#Html.Label("Password")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.password)
#Html.ValidationMessageFor(model => Model.password)
</div>
<div class="editor-label">
#Html.Label("Email")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.email)
#Html.ValidationMessageFor(model => Model.email)
</div>
<div class="editor-label">
#Html.Label("Is active")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.isactive)
#Html.ValidationMessageFor(model => Model.isactive)
</div>
<div class="editor-label">
#Html.Label("Maximum concurrent users")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.MaxConcurrentUsers)
#Html.ValidationMessageFor(model => Model.MaxConcurrentUsers, "Enter a number between 0-99.")
</div>
<div id="moduleSelection">
#Html.HiddenFor(Model => Model.selected_moduleAlf, new { id = "hdnModuleAlf" })
#Html.HiddenFor(Model => Model.selected_moduleBrad, new { id = "hdnModuleBrad" })
</div>
<input type="submit" value="Create" onclick="return submitWith();" />
<span id="validationMessage"></span>
<br />
<br />
#Html.ActionLink("Back to List", "Index")
</fieldset>
<div>
#Html.ValidationSummary()
</div>
}
<script type="text/javascript">
// Count checkboxes that are checked.
function submitWith() {
var checkedCount = $("input:checked").length;
var valid = checkedCount > 0;
// Check that one checkbox is checked first
if (!valid) { // IF false
$('#validationMessage').html('You must select at least one option').css("background-color", "red");
}
// Second check ALF
else if ($('.module-selection #chkAlf').is(':checked')) {
if ($("#txtGroupnameExistsAlf").val() == "Alf Group doesn't exist.") {
valid = false;
$('#validationMessage').html('Group must exist in ALF Database first').css("background-color", "red");
}
if ($("#txtGroupnameExistsAlf").val() == "") {
valid = false;
$('#validationMessage').html('A group must be picked when creating a new user.').css("background-color", "red");
}
}
// Third check
else if ($('.module-selection #chkBrad').is(':checked')) {
if ($("#txtGroupnameExistsBrad").val() == "Brad Group doesn't exist.") {
valid = false;
$('#validationMessage').html('Group must exist in BRAD Database first').css("background-color", "red");
}
if ($("#txtGroupnameExistsBrad").val() == "") {
valid = false;
$('#validationMessage').html('A group must be picked when creating a new user.').css("background-color", "red");
}
}
else {
valid = true;
}
return valid;
}
function chkSelection() {
// alert("check selection");
filters = new Object();
if ($('.module-selection #chkAlf').is(':checked')) {
// Show Div
$("#alfModules").show();
$("#groupname-checker-alf").show();
// Show username checker for Alf
$("#username-checker-alf").show();
// Set ALF model property to true
$("#hdnAlf").val("true");
// Set alf value for one to be passed to Ajax request
filters.alf = 1;
var selectedVal = $("#ddlSelectedAlf :selected").val();
$('#hdnModuleAlf').val(selectedVal);
}
else {
$("#alfModules").hide();
$("#groupname-checker-alf").hide();
$("#hdnAlf").val("false");
$("#username-checker-alf").hide();
filters.alf = 0;
$('#hdnModuleAlf').val("false");
$("#txtGroupnameExistsAlf").val("").css("background-color", "white");
}
if ($('.module-selection #chkBrad').is(':checked')) {
// Show Div
$("#bradModules").show();
$("#groupname-checker-brad").show();
// Show username checker for Alf
$("#username-checker-brad").show();
// Set alf value for one to be passed to Ajax request
filters.brad = 1;
var selectedVal = $("#ddlSelectedBrad :selected").val();
$('#hdnModuleBrad').val(selectedVal);
}
else {
$("#bradModules").hide();
$("#groupname-checker-brad").hide();
$("#hdnBrad").val("false");
$("#username-checker-brad").hide();
filters.brad = 0;
$('#hdnModuleBrad').val("false");
$("#txtGroupnameExistsBrad").val("").css("background-color", "white");
}
filters.username = $('#createuser-usernamesearch #user_name').val();
return filters;
}
function searchUsername() {
var filters = chkSelection();
$.ajax({
url: '#Url.Action("UsernameSearch", "UserManager")',
type: "POST",
async: true,
dataType: "json",
data: "username=" + filters.username,
success: function (data) {
var usernameExistsAlf = parseInt(data.usernameAlf);
if (usernameExistsAlf > 0) {
$('#txtUsernameExistsAlf').val("Username already exists").css("background-color", "red");
}
else {
$('#txtUsernameExistsAlf').val("Username doesn't exist").css("background-color", "#33ff00");
}
var usernameExistsBrad = parseInt(data.usernameBrad);
if (usernameExistsBrad > 0) {
$('#txtUsernameExistsBrad').val("Username already exists").css("background-color", "red");
}
else {
$('#txtUsernameExistsBrad').val("Username doesn't exist").css("background-color", "#33ff00");
}
},
error: function (data) {
}
});
}
$("#group_name").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("LookUpGroupName", "UserManager")',
dataType: "json",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
value: request.term
},
success: function (data) {
response($.map(data, function (item) {
// alert(item.group);
return {
label: item.group,
value: item.group
} // end of return
})); // end of response
}, // end of success
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
} // end of error
}); // end of ajax
},
minLength: 2,
select: function (event, ui) { // Assign to hidden values to trigger onchange ajax call.
$.ajax({
url: '#Url.Action("GroupnameCheck", "UserManager")',
dataType: "json",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
value: ui.item.label
},
success: function (data) {
$.each(data, function (index, value) {
if (index == "AlfGroup") {
$("#txtGroupnameExistsAlf").val(value);
if ($("#txtGroupnameExistsAlf").val() == "Alf Group doesn't exist.") {
$("#txtGroupnameExistsAlf").css("background-color", "red");
}
else {
$('#txtGroupnameExistsAlf').css("background-color", "#33ff00");
}
}
if (index == "BradGroup") {
$("#txtGroupnameExistsBrad").val(value);
if ($("#txtGroupnameExistsBrad").val() == "Brad Group doesn't exist.") {
$("#txtGroupnameExistsBrad").css("background-color", "red");
}
else {
$('#txtGroupnameExistsBrad').css("background-color", "#33ff00");
}
}
});
}, // end of success
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
} // end of error
}); // end of ajax
$('#hdnGroupAlf').val(ui.item.label);
$('#hdnGroupBrad').val(ui.item.label);
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
}
});
$(document).ready(function () {
chkSelection();
});
</script>
My layout with all the scripts
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<!-- Javascript -->
<script src="../../Scripts/jquery-1.8.3.min.js" type="text/javascript"></script>
#* <script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>*#
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
#* <script src="#Url.Content("~/Scripts/jquery.autocomplete.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/Custom/autocompleteGroup.js")" type="text/javascript"></script>*#
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<!-- Javascript -->
<!-- Stylesheets -->
<link href="#Url.Content("~/Content/themes/base/jquery.ui.autocomplete.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/themes/base/jquery.ui.autocomplete.custom.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<!-- Stylesheets -->
</head>
<body>
<div class="page">
<div id="header">
<div id="title" >
<h1>ALF and BRAD User Manager</h1>
</div>
<div id="logindisplay">
<span style="color:Black; background-color:white; text-align:right;">
Logged in as:&nbsp<strong>#Context.User.Identity.Name</strong>
</span>
</div>
<nav>
<ul id="menu">
#Html.ActionLink("User Manager Dashboard", "Index", "UserManager")&nbsp&nbsp
#Html.ActionLink("User Analytics", "Index", "UserStatus")&nbsp&nbsp
#Html.ActionLink("Email Distibution", "Index", "EmailDistributionList")&nbsp&nbsp
#Html.ActionLink("Email User Details", "Index", "EmailUserDetails")&nbsp&nbsp
</ul>
</nav>
</div>
<section id="main">
#RenderBody()
</section>
<footer>
</footer>
</div>
</body>
</html>
#* <script type="text/javascript">
$(document).ready(function () {
doAutocomplete('#Url.Action("LookUpGroupName", "UserManager")');
});
</script>*#
So any help? Thanks!
This is how it should work. You will still get to the method, but can check the ModelState to decide what to do, for example...
if (ModelState.IsValid) {
// Save, redirect to action
}
return View(model); // send them back to correct the problem!
You will also be able to display the errors on the view, as they will be present. You can use a ValidationSummary or have individual ValidationFor elements.
Check the below link. It may help you.
Client side validation
Update:
You need to enable clientside validation, unobtrusivejavascript and refer the script files in master page.
[web.config]
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
[layout.cshtml]
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

ASP.NET MVC 3 Model has no information on postback

I have a view with a couple of partial views that I bind to my model. For some reason, when I post, the model is empty, and I am not sure why.
Below is my ViewModel.
public class IndexViewModel
{
public bool AdvancedSearchOption { get; set; }
public bool ForceAdvanced { get; set; }
public bool ForceSimple { get; set; }
public string SimpleSearchCriteria { get; set; }
public string CustomerNumberCriteria { get; set; }
public string AccountNumberCriteria { get; set; }
public string NameCriteria { get; set; }
public string PhoneNumberCriteria { get; set; }
}
Here is my controller. I am filling in all the values of the viewmodel because I wanted to see if the values got to the partial views. They do get there, so it is just on the post that I am having issues.
public class HomeController : Controller
{
private ISecurityRepository SecurityRep;
public HomeController(ISecurityRepository repo)
{
SecurityRep = repo;
}
public ActionResult Index()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View(temp);
}
public ActionResult SimpleSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = true;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index",temp);
}
public ActionResult AdvancedSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = true;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria= "Acct";
temp.CustomerNumberCriteria= "Cust";
temp.NameCriteria= "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index", temp);
}
[HttpPost]
public ActionResult Index(IndexViewModel vm, FormCollection formCollection)
{
return View();
}
}
Here is my view
#model TRIOSoftware.Magnum.Models.IndexViewModel
#{
ViewBag.Title = "Search";
}
#if ((#Model.AdvancedSearchOption && #Model.ForceSimple != true) || #Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch")
}
else
{
#Html.Partial("SimpleSearch")
}
Here is my SimpleSearch partial view. I think if I can get this one working, the other will follow the same path. I do the post in the partial and I use jQuery to do it. I am not sure if either of these things could cause me issues or not. I only have all the hidden items in there because I didn't know if not having them was causing my issues.
#model TRIOSoftware.Magnum.Models.IndexViewModel
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
#using (Html.BeginForm("Index","Home"))
{
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
<div id="DefaultDiv" style="float:right">
<a id="DefaultAdvanced" href="#" class="ButtonClass">Default Simple Search</a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img src="../../Content/images/TRIO_transparent_image.gif"; alt="TRIO Software"; style="margin-left:150px; clear:left"/>
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
</div>
<div id="SearchSection" style="float: left" class="SearchText">
<img src="../../Content/images/Search.gif"; alt="Search"; style="float:left" />
</div>
<p style="clear:left;margin-left:400px">
#Html.ActionLink("Advanced Search", "AdvancedSearch", null, new { style = "clear:left" })
</p>
</div>
}
Here is the HTML code when viewing the simple search partial view:
<div id="main">
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
<form method="post" action="/">
<input type="hidden" value="False" name="ForceAdvanced" id="ForceAdvanced" data-val-required="The ForceAdvanced field is required." data-val="true">
<input type="hidden" value="False" name="AdvancedSearchOption" id="AdvancedSearchOption" data-val-required="The AdvancedSearchOption field is required." data-val="true">
<input type="hidden" value="False" name="ForceSimple" id="ForceSimple" data-val-required="The ForceSimple field is required." data-val="true">
<input type="hidden" value="Acct" name="AccountNumberCriteria" id="AccountNumberCriteria">
<input type="hidden" value="Cust" name="CustomerNumberCriteria" id="CustomerNumberCriteria">
<input type="hidden" value="Name" name="NameCriteria" id="NameCriteria">
<input type="hidden" value="Phone" name="PhoneNumberCriteria" id="PhoneNumberCriteria">
<div style="float:right" id="DefaultDiv">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="#" id="DefaultAdvanced" role="button"><span class="ui-button-text">Default Simple Search</span></a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img style="margin-left:150px; clear:left" alt="TRIO Software" ;="" src="../../Content/images/TRIO_transparent_image.gif">
<div class="SearchText" style="clear:left; float: left">
<label for="What_s_your_inquiry_:">What's your inquiry?:</label>
<input type="text" value="Testing" name="SimpleSearchCriteria" id="SimpleSearchCriteria" class="text-box single-line">
</div>
<div class="SearchText" style="float: left" id="SearchSection">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="SearchButton" ;="" href="#" role="button"><span class="ui-button-text"><img style="float:left" alt="Search" ;="" src="../../Content/images/Search.gif"></span></a>
</div>
<p style="clear:left;margin-left:400px">
<a style="clear:left" href="/Home/AdvancedSearch">Advanced Search</a>
</p>
</div>
</form>
</div>
How do I fix this problem?
Although you're selecting a partial to render, you're not passing it the model. There's an overloaded version of Html.Partial that takes a second argument that allows you to pass a model to it:
#Html.Partial("ViewName", Model);
So in your case, you'd use this:
#if ((Model.AdvancedSearchOption && Model.ForceSimple != true) || Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch", Model)
}
else
{
#Html.Partial("SimpleSearch", Model)
}
Also notice how I've removed the #s you were prefixing Model with. To better understand why, please see Introduction to ASP.NET Web Programming Using the Razor Syntax and a small reference for this same topic written by Phil Haack here.
I think #john-h hit the nail on the head with his answer. However, you might want to reduce the complexity you've created for yourself.
1) Since both ForceSimple and ForceAdvanced are Boolean, it would be assumed that when ForceAdvanced is true, then it's not "Simple", right? I'm not sure what other logic you have here.
2) Rather than creating two views and "posting" back to get the correct one, why not just use a parameter to set the search type? Or evaluate the security to set which one the user can execute. Here's an example:
Controller Actions:
//id is the search type: true is Advanced
public ActionResult Search(bool id) {
IndexViewModel viewModel = new IndexViewModel {
/* Do whatever logic here */
ForceAdvanced = (id) ? false : true,
AdvancedSearchOption = id
};
return View("search", viewModel);
}
[HttpPost]
public ActionResult Search(IndexViewModel model) {
//model.SimpleSearchCriteria = "Testing";
//model.PhoneNumberCriteria = "Phone";
return View("search", model);
}
Search View:
#using (#Html.BeginForm(new { id = #Model.AdvancedSearchOption })) {
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#if (Model.AdvancedSearchOption) {
<div>
#* if you really want, load your partial views here *#
<span>#Html.LabelFor(m => m.NameCriteria)</span>
#Html.EditorFor(m => m.NameCriteria, new { style = "width: 400px" })
<span>#Html.LabelFor(m => m.PhoneNumberCriteria)</span>
#Html.EditorFor(m => m.PhoneNumberCriteria, new { style = "width: 400px" })
</div>
}
else {
#* if you really want, load your partial views here *#
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
}
</div>
<div>
<input type="submit" value="Search" />
</div>
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
}
I had tried explicitly sending in the model to the partials with no luck. I believe that the partial views get the parent model by default if nothing is specified, so all I needed to do was to specify the model type in my partials, and I got the information.
I finally figured it out with a lot of trial and error. My issue was being caused by me trying to use jQuery to do a post. There must be some other things you need to do to update your model doing it this way. Once I changed it out and put an input control on the form for the post, I got all my data back from the parent and partial view in the controller.

Resources