Guys I'm new to JavaScript, so not sure where the error is. Basically I've two submit buttons in my cshtml. one with the id = email and other id = sms. I've set value=" ". I'm using these buttons in a form.
what I want to do is; by clicking on these button I want to pass them a value so that I can use that value in model and controller, like in switch statement. tried various ways but still its passing null value. please advise!
function GetVal() {
var input = document.getElementsByTagName('input');
for (i = 0; i < input.length; i++) {
if (input[i].type == 'submit') {
if (input[i].id == 'email') {
//input[i].value = 'submitEmail';
//input[i].setAttribute("value", "subEmail");
document.getElementById("email").setAttribute("subEmail", "value");
break;
}
}
}
}
<input id="email" type="submit" class="#( Model.UnsubscribedEmail == null ? "unsubscribe" : "subscribe")" onclick="GetVal();" />
Model
public static void susbscription(MyModel model, string submitButton)
{
switch (submitButton)
{
case "subEmail":
//Code here
break;
}
}
Controller
[HttpPost]
public ActionResult MarketingPreferences(MyModel model, string submitButton)
{
MarketingPreferencesModel.susbscription(model, submitButton);
return View(model);
}
Try this:
<input id="email" type="submit" name="submitButton" onclick="GetVal(this);" class="#( Model.UnsubscribedEmail == null ? "unsubscribe" : "subscribe")" />
In JavaScript:
function GetVal(element) {
element.value = "subEmail";
}
In Action:
public ActionResult MarketingPreferences(MyModel model, string submitButton)
{
MarketingPreferencesModel.susbscription(model, submitButton);
return View(model);
}
Related
I'm trying to create a checkbox list where a user is supposed to be able to choose one or more options, based on the choice: this is supposed to be inserted to a database table, where the id of the choice is inserted. (This is on a page where a user can "edit garage"), therefore the garageid is also supposed to be fetched and both the garageid and the choice id should be inserted to a cross table, that I have created as following:
[ID]
,[GarageID]
,[RequestProperty]
,[CreatedDate]
,[CreatedBy]
,[UpdatedDate]
,[UpdatedBy]
I also have a stored procedure for the insert:
ALTER PROCEDURE [dbo].[spGarageGetRequestTypes]
-- Add the parameters for the stored procedure here
#GarageID INT,
#RequestType INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
INSERT INTO GarageCrossRequestType
(GarageID, RequestProperty)
VALUES (#GarageID, #RequestType)
END
And the "edit page" is working and functioning, it's where I get the garageId as well. It looks like following in view:
<div class="form-group">
<div class="row">
<label class="col-xs-2 control-label">Garage</label>
<input type="text" class="col-lg-10 form-control" name="GarageName" id="GarageName" placeholder="Name" required="" />
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-2 control-label">Contact person</label>
<input type="text" class="col-lg-10 form-control" name="ContactPerson" id="ContactPerson" placeholder="ContactPerson" required="" />
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-2 control-label">Email</label>
<input type="email" class="col-lg-10 form-control" name="Email" id="Email" placeholder="Email" required="" onblur="validateEmail(this.value);" /><p id="InvalidMeg" style="font-size: 25px; color: red">Invalid e-mail address</p>
</div>
</div>
<script type="text/javascript">
function editGarage(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var garageId = dataItem.GarageId;
countryId = dataItem.CountryId;
var email = dataItem.Email;
var contactperson = dataItem.ContactPerson;
if (garageId != 0) {
$("#EditGarageBtn").show();
$("#saveNewGarageBtn").hide();
$("#GarageName").val(name);
$("#Country").val(countryId);
$("#ContactPerson").val(contactperson);
$("#Email").val(email);
}
}
$("#EditGarageBtn").click(function () {
var customerNumber = customerNumberOfEditingGarage;
name = $("#GarageName").val();
countryId = $("#Country").val();
var garageId = $("#garageId").val();
var contactperson = $("#ContactPerson").val();
var email = $("#Email").val();
$("#EditGarageBtn").hide();
if (name.length > 0 && email.length > 0 && contactperson.length > 0) {
$.ajax({
url: '#Url.Action("EditGarage", "Garage")',
dataType: 'JSON',
data: {
name: name, countryId: countryId, garageId: garageId,
contactperson: contactperson, email: email
},
success: function (data) {
if (data == "Failure") {
toastr["error"]("Error editing Garage");
}
else {
toastr["success"]("Garage successfully updated");
customerNumberOfEditingGarage = null;
refreshGrid();
}
},
error: function () {
}
});
} else {
toastr["error"]("Error editing Garage");
}
});
</script>
Model:
public class GarageModel
{
public int GarageTypeId { get; set; }
public int CountryId { get; set; }
public string ContactPerson { get; set; }
public string Email { get; set; }
public int GarageId { get; set; }
// for the choices in the checkbox
public int ScheduledService { get; set; } = 1;
public int Tires { get; set; } = 2;
}
Method:
public bool EditGarage(GarageModel model)
{
var valid = false;
var cmd = new SqlCommand("spGarageEditGarage", Connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#GarageId", model.GarageId);
cmd.Parameters.AddWithValue("#CountryId", model.CountryId);
cmd.Parameters.AddWithValue("#Name", model.Name);
cmd.Parameters.AddWithValue("#ContactPerson", model.ContactPerson);
cmd.Parameters.AddWithValue("#Email", model.Email);
try
{
int result = cmd.ExecuteNonQuery();
if (result == 1)
valid = true;
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
finally
{
Connection.Close();
}
// for the choices in the checkbox (not working!)
List<int> newlist = new List<int>();
newlist.Add(model.Tires);
newlist.Add(model.ScheduledService);
foreach (var item in newlist)
{
if (newlist != null)
{
var cmd1 = new SqlCommand("spGarageGetRequestTypes", Connection);
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.AddWithValue("#GarageId", model.GarageId);
cmd1.Parameters.AddWithValue("#RequestType", newlist.First());
int result = cmd1.ExecuteNonQuery();
if (result == 1)
valid = true;
}
}
return valid;
}
If you look at my comments in the model and the method, you can see what I've added for the "choices" function I'm trying to implement. Here's the html i created for the input type as well:
#foreach (var items in Model)
{
<div class='form-group' style="margin-left: 60%;">
<div class="row">
<label class="ab">Tires</label>
<input type="checkbox" class="checkbclass" name="#items.Tires" id="Tires" placeholder="Tires" required="" value="#items.Tires" />
</div>
</div>
<div class='form-group' style="margin-left: 60%;">
<div class="row">
<label class="ab">Scheduled Service</label>
<input type="checkbox" class="checkbclass" name="#items.ScheduledService" id="Scheduled" placeholder="Scheduled" required="" value="#items.ScheduledService" />
</div>
</div>
}
Now, to the problems:
1: I need some sort of method for making sure which or if a checkbox is checked, and this needs to be returned to the model or controller in some way. I only want to return it's numeric value, as seen in the model I want Tires to have the numeric value of 2 etcetera.
The datebase insert works (so at least that's something), but the table only accepts RequestProperty and GarageID, meaning that if a user chooses 2 of the checkboxes, I need to update the database twice, creating 2 rows, but with the same garageid.
I tried posting a question about this earlier, but it was poorly explained from my side, so I'm trying again, and hoping I included everything this time. I'm open to any help/solutions that can help me solve this.
First, You need to remove all GarageCrossRequestType that containe current GarageID as the checkbox may be checked and unhacked later on edit.
This how I would do it.
Note: make sure to read the comment
javascript
$("#EditGarageBtn").click(function() {
var customerNumber = customerNumberOfEditingGarage;
// I assumed that you want name as the int of RequestType eg 1 or 2 that are checked
var garageCrossRequestType = $(".checkbclass:checked").map(function(x) {
return parseInt($(x).attr("name"));
});
name = $("#GarageName").val();
countryId = $("#Country").val();
var garageId = $("#garageId").val();
var contactperson = $("#ContactPerson").val();
var email = $("#Email").val();
$("#EditGarageBtn").hide();
if (name.length > 0 && email.length > 0 && contactperson.length > 0) {
$.ajax({
url: '#Url.Action("EditGarage", "Garage")',
dataType: 'JSON',
data: {
name: name,
countryId: countryId,
garageId: garageId,
contactperson: contactperson,
email: email,
garageCrossRequestType: garageCrossRequestType // here send the checked checkedboxes
},
success: function(data) {
if (data == "Failure") {
toastr["error"]("Error editing Garage");
} else {
toastr["success"]("Garage successfully updated");
customerNumberOfEditingGarage = null;
refreshGrid();
}
},
error: function() {
}
});
} else {
toastr["error"]("Error editing Garage");
}
});
C#
// create an sqlProcedure or something instead of this, this is only to show how it work
// You have to clear all GarageCrossRequestType that containe the current GarageID
// An after insert the newly checked items
new SqlCommand("delete GarageCrossRequestType where GarageID = " + model.GarageId, Connection).ExecuteNonQuery();
List <int> newlist = new List<int>();
if (model.garageCrossRequestType != null)
newlist.AddRange(model.garageCrossRequestType);
foreach(var item in newlist) {
//newlist cant be null becouse you are already in a loop.
// and also newlist is never null
// if (newlist != null)
var cmd1 = new SqlCommand("spGarageGetRequestTypes", Connection);
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.AddWithValue("#GarageId", model.GarageId);
// instead of newlist.First() you are looping throw newlist eg checkboxes then it should be item
cmd1.Parameters.AddWithValue("#RequestType", item);
int result = cmd1.ExecuteNonQuery();
if (result == 1)
valid = true;
}
cshtml code for one of the textboxes. I'm trying to trigger a function on form submit that checks whether there's anything typed in the textboxes. If there isn't anything typed in the textboxes, the border should turn red.
#model WebForum.Models.AccountViewModel
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="~/Scripts/Custom.js"></script>
</head>
<h2 style="font-size:larger">CreateAccount</h2>
<p style="font-size:large">Please enter BOTH an account name and a password.</p>
<div id="account_create">
#using (Html.BeginForm("AccountCreated", "Home", FormMethod.Post, new { #id = "accountform" }, ))
{
#Html.TextBoxFor(Model => Model.Account_Name, new { #id = "account_name", #placeholder = "Your Account Name" })
<br />
<br />
#Html.TextBoxFor(Model => Model.Password, new { #id = "account_password", #placeholder = "Type Password Name" })
<br />
<br />
#Html.ValidationMessageFor(m => Model.Account_Name)
#Html.ValidationMessageFor(m => Model.Password)
<form id="accountform" onsubmit="accountform()">
<input type='submit' id="accountform" name="Create Account">
</form>
}
</div>
Heres the javascript file. The function should be triggered on ="onsubmit". I've tried various forms of .onsubmit, but they've haven't worked.
//run on form submit
function loginform() {
if ($('#account_name').val() == '') {
$('#account_name').css('border-color', 'red');
}
else {
$('#account_name').css('border-color', '');
}
if ($('#account_password').val() == '') {
$('#account_password').css('border-color', 'red');
}
else {
$('#account_password').css('border-color', '');
}
};
function accountform() {
if ($('#account_name').val() == '') {
$('#account_name').css('border-color', 'red');
}
else {
$('#account_name').css('border-color', '');
}
if ($('#account_password').val() == '') {
$('#account_password').css('border-color', 'red');
}
else {
$('#account_password').css('border-color', '');
}
};
function postform() {
if ($('#poster_name').val() == '') {
$('#poster_name').css('border-color', 'red');
}
else {
$('#poster_name').css('border-color', '');
}
if ($('#poster_text').val() == '') {
$('#poster_text').css('border-color', 'red');
}
else {
$('#poster_text').css('border-color', '');
}
};
function logwithoutform() {
if ($('#poster_text').val() == '') {
$('#poster_text').css('border-color', 'red');
}
else {
$('#poster_text').css('border-color', '');
}
};
And heres the controller code but that shouldn't be too important:
[HttpPost]
public ActionResult AccountCreated(Models.AccountViewModel model)
{
String Account_Name = model.Account_Name;
String Account_Password = model.Password;
if (!ModelState.IsValid)
{
return RedirectToAction("CreateAccount");
}
//if (Account_Name == null || Account_Password == null)
// return RedirectToAction("CreateAccount");
WebForumEntities2 db = new WebForumEntities2();
foreach(Account eachAccount in db.Accounts)
{
if (eachAccount.Account_Name.Equals(Account_Name))
{
return RedirectToAction("AccountCreatedMessage");
}
}
int nextiD = 0;
if (db.Accounts.ToList().Count > 0)
{
nextiD = db.Accounts.ToList().Last().Id + 1;
}
var newAccount = new Account();
newAccount.Account_Name = Account_Name;
newAccount.Password = Account_Password;
newAccount.Id = nextiD;
db.Accounts.Add(newAccount);
db.SaveChanges();
return RedirectToAction("CreateAccount");
}
Please help me make the textboxes turn red.
I've tried debugging, and the javascript functions are never called.
First I would use data attributes for field validation.
public class AccountViewModel
{
[Required] // data attribute
public string Account_Name;
[Required]
public string Password;
}
You can then submit your form normally. If the ASP.NET engine picks up any data validation errors it will put the class .field-validation-error on your inputs.
You can style this class to your liking, like so:
.field-validation-error
{
border-color: red;
}
A few other notes:
You have a form nested in another form, I would remove the form
around your button.
Not sure why you put your inputs into a string
in your controller instead of using your ViewModel.
I typically put my DbContext outside of my ActionResults, be sure to dispose of it.
I need to be able to require certain fields if someone selects a value of "Yes" from a dropdown. I've used the following code but it doesn't seem to work.
$(function () {
$('#anyAdditionalInc').keyup(function () {
if ($(this).val() == "No") {
$('#additionalIncomeSource').removeAttr('required');
$('#additionalIncomeAmt').removeAttr('required');
} else {
$('#additionalIncomeSource').attr('required', 'required');
$('#additionalIncomeAmt').attr('required', 'required');
}
});
});
My dropdown looks like this
<div class="form-group">#Html.LabelFor(m => m.anyAdditionalInc, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
<div class="col-sm-4">#Html.DropDownListFor(m => m.anyAdditionalInc, new SelectList(new List
<Object>{ new { value = "", text = "----"}, new { value = "Yes", text = "Yes"}, new { value = "No", text = "No"}, }, "value", "text"), new { #class = "form-control", id = "anyAdditionalInc" }) #Html.ValidationMessageFor(m => m.anyAdditionalInc)</div>
</div>
</div>
Any help is appreciated. It doesnt seem to want to require the validation on the source and amt fields when selecting yes.
A dropdown (I guess you mean a <select> element by that) doesn't have much keyup events. Try change instead:
$(function () {
$('#anyAdditionalInc').change(function () {
var active = $(this).val() != "No"),
fields = $('#additionalIncomeSource, #additionalIncomeAmt');
fields.prop('required', active);
if (!active) fields.val("");
});
});
Even though #Bergi answered the question from a client-side perspective, since you tagged the question asp.net-mvc-4 I presume you may wish to know how it's done on the server side (where it really matters!):
You can simply check it in your controller:
public ActionResult Foo(SomeModel someModel) {
if (someModel.anyAdditionalInc != "Yes") {
ModelState.AddModelError("", "You must select yes");
}
}
Or if you want to push the logic into your model itself:
public class SomeModel: IValidatableObject {
public string anyAdditionalInc {get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (this.anyAdditionalInc != "Yes") {
yield return new ValidationResult("You must select yes");
}
}
}
Notice how the model:
Implements IValidateableObject
Has a method named Validate which returns the type IEnumerable<ValidationResult>
During the model binding process this method will automatically be called and if a validation result is returned your ModelState will no longer be valid. So using this familiar code in your controller will make sure you don't take any action unless your custom conditions check out:
public class SomeController {
public ActionResult SomeAction() {
if (ModelState.IsValid) {
//Do your stuff!
}
}
}
I have two files: xml_database.xml and login.html. This is my HTML in login.html:
<h2>Login:</h2>
Username: <input type="text" id="login_username"> <input type="button" value="Sign in!" id="sign_in"><br><br><hr>
<h2>Create an account:</h2>
Username: <input type="text" id="create_username"><br><br>
Welcome text: <textarea id="create_welcome" style="vertical-align: text-top;"></textarea>
<br><br>
<input type="button" value="Create an account!" id="create_account">
And in my xml_database.xml:
<?xml version="1.0" encoding="utf-8"?>
<user username="chris97ong" welcomeText="htrftfd"></user>
So when I click on the button to login in login.html, if "chris97ong" is in the username text input, I want to have an alert saying "htrftfd". This is my Javascript for login.html:
document.getElementById("sign_in").onclick = function() {
xmlDoc = loadXMLDoc("xml_database.xml");
users = xmlDoc.getElementsByTagName("user");
var username = document.getElementById("login_username").value;
var bool = false;
for(var i = 0; i < users.length && bool == false; i++) {
if(users[i].getAttribute("username") == username) {
bool = true;
alert("Your welcome text is " + users[i].getAttribute("welcomeText"));
}
}
if(bool == false) { alert("Such username does not exist"); }
}
And it worked perfectly.
Now I want to be able to create an account with the second section. When the button to create an account is clicked, I want to create a node in xml_database.xml "<user>". I want the "username" attribute of this new element to be what is in the text input (with id "create_username") and the "welcomeText" of this new element to be what is in the textarea (with id "create_welcome").
This is what I have tried:
document.getElementById("create_account").onclick = function() {
xmlDoc = loadXMLDoc("xml_database.xml");
users = xmlDoc.getElementsByTagName("user");
var username = document.getElementById("create_username").value;
var bool = false;
for(var i = 0; i < users.length && bool == false; i++) {
if(users[i].getAttribute("username") == username) {
bool = true;
alert("Such username already exists");
}
}
if(bool == false) {
var welcomeText = document.getElementById("create_welcome").value;
new_user = xmlDoc.createElement("user");
new_user.setAttribute("username",username);
new_user.setAttribute("welcomeText",welcomeText);
alert("Account created");
}
}
But it does not work. When I try to login with this new username, the alert states that such a username does not exist. There were no error messages whatsoever and the xml file was not changed at all. What is wrong with my code that I didn't realise? Thx.
PS: I have this in my <head> tag:
<script src="http://www.w3schools.com/dom/loadxmldoc.js"></script>
The createElement method create element on DOM model build from xml loaded on to browser as you know, so this method does not offer access to read and write local files.
Using server side programs such as PHP will be suitable for this solution.
I am using kendoui widgets with knockoutjs for datasource. I have a checkbox that is data bound to StartClientFromWebEnabled observable variable. An input text box is visible only when the checkbox ic checked (StartClientFromWebEnabled is true). The input has a required attribute. I want the required validation to be triggered only when the checkbox is checked.
Here is my html:
<table>
<tr>
<td><label for="startClientFromWebEnabled">Client Launch From Web:</label></td>
<td><input type="checkbox" id="startClientFromWebEnabled" name="startClientFromWebEnabled" data-bind="checked: StartClientFromWebEnabled, enable: IsEditable" onchange="startClientFromWebToggleRequiredAttribute()" /></td>
</tr>
<tr data-bind="visible: StartClientFromWebEnabled">
<td><label for="mimeType">Protocol:</label></td>
<td>
<input id="mimeType" name="mimeType" data-bind= "value: MimeType, enable: IsEditable" />
<span class="k-invalid-msg" data-for="mimeType"></span>
</td>
</tr>
</table>
I tried some scenarios including setting onChange event on the checkbox with the following javascript function adding and removing the required attribute:
startClientFromWebToggleRequiredAttribute = function () {
var checkbox = document.getElementById("startClientFromWebEnabled");
var mimeType = document.getElementById("mimeType");
if (checkbox.checked) {
mimeType.setAttribute("required", "required");
}
else {
mimeType.removeAttribute("required");
}
}
The problem is I will need this functionality for many dependent properties in my application and my option is to make this function generic with some parameters and call it from the html with the corresponding paramater values like this:
toggleRequiredAttribute = function (checkboxElement, inputElement1, inputElement2 ... ) {
var checkbox = document.getElementById(checkboxElement);
var inputElement1 = document.getElementById(inputElement1);
if (checkbox.checked) {
inputElement1.setAttribute("required", "required");
}
else {
inputElement1.removeAttribute("required");
}
}
<input type="checkbox" id="startClientFromWebEnabled" name="startClientFromWebEnabled" data-bind="checked: StartClientFromWebEnabled, enable: IsEditable" onchange="toggleRequiredAttribute('startClientFromWebEnable', 'mimeType')" />
I really do not like this scenario. I wonder is there something like a conditional validation in kendoui that trigger only when some condition is satisfied. Any other suggestions are also welcome.
I had the same issue, I created a custom validator which also handles the server side validation, this example is not 100% complete but all the validation is working, this validates the string length dependant on a checkbox state, it also uses resources for error message etc so will need a little modification, it uses the kendo ui validation client side, let me know if this is useful:
Model Properties:
public bool ValidateTextField { get; set; }
[CustomValidator("ValidateTextField", 6, ErrorMessageResourceType=typeof(Errors),ErrorMessageResourceName="STRINGLENGTH_ERROR")]
public string TextField{ get; set; }
Custom Validator:
[AttributeUsage(AttributeTargets.Field|AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
public class CustomValidatorAttribute : ValidationAttribute, IClientValidatable {
private const string defaultErrorMessage="Error here.";
private string otherProperty;
private int min;
public CustomValidatorAttribute(string otherProperty, int min) : base(defaultErrorMessage) {
if(string.IsNullOrEmpty(otherProperty)) {
throw new ArgumentNullException("otherProperty");
}
this.otherProperty=otherProperty;
this.min=min;
this.ErrorMessage = MyResources.Errors.STRINGLENGTH_ERROR;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
bool valid = true;
var curProperty = validationContext.ObjectInstance.GetType().
GetProperty(otherProperty);
var curPropertyValue = curProperty.GetValue
(validationContext.ObjectInstance, null);
if(Convert.ToBoolean(curPropertyValue)) {
string str=value.ToString();
valid = str.Length >= min;
if(!valid) { return new ValidationResult(MyResources.Errors.STRINGLENGTH_ERROR); }
}
return ValidationResult.Success;
}
#region IClientValidatable Members
public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
var rule=new ModelClientValidationRule {
ErrorMessage = this.ErrorMessage,
ValidationType="checkboxdependantvalidator"
};
rule.ValidationParameters["checkboxid"]=otherProperty;
rule.ValidationParameters["min"]=min;
yield return rule;
}
public override string FormatErrorMessage(string name) {
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
name);
}
}
Javascript:
(function ($, kendo) {
$.extend(true, kendo.ui.validator, {
rules: { // custom rules
customtextvalidator: function (input, params) {
//check for the rule attribute
if (input.filter("[data-val-checkboxdependantvalidator]").length) {
//get serialized params
var checkBox = "#" + input.data("val-checkboxdependantvalidator-checkboxid");
var min = input.data("val-checkboxdependantvalidator-min");
var val = input.val();
if ($(checkBox).is(':checked')) {
if (val.length < min) {
return false;
}
}
}
return true;
}
},
messages: { //custom rules messages
customtextvalidator: function (input) {
// return the message text
return input.attr("data-val-checkboxdependantvalidator");
}
}
});
})(jQuery, kendo);
Helpful posts:
http://www.codeproject.com/Articles/301022/Creating-Custom-Validation-Attribute-in-MVC-3
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx