How to check if all controls on the page are empty? - javascript

I have a method that is supposed to loop over all of the controls on my page and return false if any one of them has a value other than empty string / null. This gets called as part of an OnSaveValidation. If the form is empty, they should be able to save.
function IsFormEmpty()
{
var ancestor = document.getElementById('PAIQIFunc'); //PAIQIFunc is the id of a div
var descendents = ancestor.getElementsByTagName('*');
var i = 0;
for (i = 0; i < descendents.length; ++i)
{
var e = descendents[i];
try
{
var eVal = $("#" + e).val();
// just check to make sure eVal has *some* value
if (eVal != '' || eVal != undefined || eVal != null)
return false;
}
catch (err){
//simply move on to next control...
}
}
return true;
}
Code sourced from Loop through all descendants of a div - JS only
In most cases, var eVal = $("#" + e).val(); throws an exception because it's a div or something like that. I'm only interested in the 108 drop down menus and 1 textbox on my form.
I set a breakpoint on my if statement and it was never hit. But descendents has like 1200 elements in it; I couldn't possibly step through it all trying to find what I'm looking for...
How else could I modify the code to check each control on the page?
EDIT: I should note that the web application is a C# / ASP.NET project using Razor views and we're using Telerik's Kendo web UI controls, not "vanilla" .NET controls if that makes a difference. So all of the controls are defined in the .cshtml file like so:
#(Html.Kendo().DropDownListFor(m => m.SomeProperty).HtmlAttributes(new { id = "cmbSomeProperty", #class = "k-dropdown-width-30", #tabIndex = "1", style = "width:60px" }).BindTo(ViewBag.SomePropertyDataSource).OptionLabel(" "))

You could try the following:
var hasValue = false;
var div = document.getElementById('PAIQIFunc');
$(div).find('input')
.each(function() { // iterates over all input fields found
if($.trim($(this).val()).length != 0) {
hasValue = true; // if field found with content
break;
}
});
if(hasValue === false) {
// save logic here
}
Hope this helps.

Related

Custom validation not firing client-side

I am writing a custom attribute to require a property in a viewmodel if another property has a specified value.
I used this post for reference: RequiredIf Conditional Validation Attribute
But have been encountering issues with the .NET Core revisions for IClientModelValidator. Specifically, the server side validation works as expected with ModelState.IsValid returning false, and ModelState errors containing my custom error codes. I feel that I am missing something when translating between the differing versions of validator.
The old (working) solution has the following:
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = ErrorMessageString,
ValidationType = "requiredif",
};
rule.ValidationParameters["dependentproperty"] =
(context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
rule.ValidationParameters["desiredvalue"] = DesiredValue is bool
? DesiredValue.ToString().ToLower()
: DesiredValue;
yield return rule;
}
Based on the changes to IClientModelValidator outlined here: https://github.com/aspnet/Announcements/issues/179 I have written the following methods:
public void AddValidation(ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-requiredif", errorMessage);
MergeAttribute(context.Attributes, "data-val-requiredif-dependentproperty", PropertyName);
var desiredValue = DesiredValue.ToString().ToLower();
MergeAttribute(context.Attributes, "data-val-requiredif-desiredvalue", desiredValue);
}
private bool MergeAttribute(
IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
These are being called as expected, and values are properly populated, yet the following JS is ignored. Leaving me to suspect I am missing something between the two.
$.validator.addMethod("requiredif", function (value, element, parameters) {
var desiredvalue = parameters.desiredvalue;
desiredvalue = (desiredvalue == null ? "" : desiredvalue).toString();
var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
var actualvalue = {}
if (controlType === "checkbox" || controlType === "radio") {
var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
actualvalue = control.val();
} else {
actualvalue = $("#" + parameters.dependentproperty).val();
}
if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
var isValid = $.validator.methods.required.call(this, value, element, parameters);
return isValid;
}
return true;
});
$.validator.unobtrusive.adapters.add("requiredif", ["dependentproperty", "desiredvalue"], function (options) {
options.rules["requiredif"] = options.params;
options.messages["requiredif"] = options.message;
});
Any ideas?
EDIT: Just to erase doubt that the server side is working properly and the issue almost certainly lies client side, here is a snip of the generated HTML for a decorated field:
<input class="form-control" type="text" data-val="true" data-val-requiredif="Profession Other Specification is Required" data-val-requiredif-dependentproperty="ProfessionTypeId" data-val-requiredif-desiredvalue="10" id="ProfessionOther" name="ProfessionOther" value="" placeholder="Please Specify Other">
So I had the same setup and same result as the original questioner. By stepping through a project where custom validators were being fired and where they weren't, I was able to determine that when the page is initially loaded, jquery.validate.js attaches a validator object to the form. The validator for the working project contained the key for the custom validator I had created. The validator for the one that did not work was missing that key (which was later added and available at the time I was posting my form).
Unfortunately, as the validator object had already been created and attached to the form without my custom validator, it never reached that function. The key to solving this issue was to move my two JS functions outside of the jQuery ready function, as close to the top of my main script as possible (just after I set my jQuery validator defaults). I hope this helps someone else!
My project is written in TypeScript, so my structure is a bit different but the JavaScript for actually adding the validator remains unchanged.
Here is the code for my "SometimesRequired" validator Typescript class:
export class RequiredSometimesValidator {
constructor() {
// validator code starts here
$.validator.addMethod("requiredsometimes", function (value, element, params) {
var $prop = $("#" + params);
// $prop not found; search for a control whose Id ends with "_params" (child view)
if ($prop.length === 0)
$prop = $("[id$='_" + params + "']");
if ($prop.length > 0) {
var ctrlState = $prop.val();
if (ctrlState === "EditableRequired" && (value === "" || value === "Undefined"))
return false;
}
return true;
});
$.validator.unobtrusive.adapters.add("requiredsometimes", ["controlstate"], function (options) {
options.rules["requiredsometimes"] = options.params["controlstate"];
options.messages["requiredsometimes"] = options.message;
});
// validator code stops here
}
}
Then in my boot-client.ts file (the main file which powers my application's JavaScript), I instantiate a new copy of the validator above (thus calling the constructor which adds the custom validator to the validator object in memory) outside of document.ready:
export class Blueprint implements IBlueprint {
constructor() {
// this occurs prior to document.ready
this.initCustomValidation();
$(() => {
// document ready stuff here
});
}
private initCustomValidation = (): void => {
// structure allows for load of additional client-side validators
new RequiredSometimesValidator();
}
}
As a very simple example not using TypeScript, you should be able to do this:
<script>
$.validator.addMethod("requiredsometimes", function (value, element, params) {
var $prop = $("#" + params);
// $prop not found; search for a control whose Id ends with "_params" (child view)
if ($prop.length === 0)
$prop = $("[id$='_" + params + "']");
if ($prop.length > 0) {
var ctrlState = $prop.val();
if (ctrlState === "EditableRequired" && (value === "" || value === "Undefined"))
return false;
}
return true;
});
$.validator.unobtrusive.adapters.add("requiredsometimes", ["controlstate"], function (options) {
options.rules["requiredsometimes"] = options.params["controlstate"];
options.messages["requiredsometimes"] = options.message;
});
$(function() {
// document ready stuff
});
</script>
The key to solving this issue was to move my two JS functions outside of the jQuery ready function, as close to the top of my main script as possible (just after I set my jQuery validator defaults). I hope this helps someone else!
Credit goes to #Loni2Shoes

javascript input value changes not taking effect? Calculation field value does not change?

I am using javascript to populate a page which has a calculation field. The calculation field only gets set when i click on the page or tab manually. I don't think javascript is populating the fields until i click tab.
Iv tried runing a methoud to foucus on all the inputs.
function PushTab()
{
//could not get this working as i could not select a input with js and run the trigger function of jq .. mixing js with jquery is bad.
//$(this).trigger({
// type: 'keypress',
// which: 9
//});
var doc = window.frames['main'].window.frames['content'].document;
var tabbables = doc.querySelectorAll("input");
for (var i = 0; i < tabbables.length; i++) {
tabbables[i].focus();
}
}
Could someone tell me how i could trigger all my javascript changes to take affect, something that simulates a users tab or click on page?
Edit
How i change the values.
function SetElementValue(name, value) {
var elementType = "input";
element = GetElement(elementType, name);
if (element != null) {
element.value = value;
return;
}
function GetElement(type, name) {
var doc = window.frames['main'].window.frames['content'].document;
if (doc != null) {
var aTags = doc.getElementsByTagName(type);
var searchText = name;
var found;
for (var i = 0; i < aTags.length; i++) {
if (aTags[i].name.trim() == searchText) {
found = aTags[i];
//alert(found.type);
return found;
break;
}
}
}
return found;
}

Is this the correct way to express no value in this function?

I have a accordion which has been set up to open to a specific panel by appending this string to the URL?panel=0
farfegnugen = jQuery.noConflict();
farfegnugen(document).ready(function($) {
var defaultPanel = parseInt(getParam('panel'));
farfegnugen("#st-accordion").accordion({
open: defaultPanel
});
function getParam(name) {
var query = location.search.substring(1);
if (query.length) {
var parts = query.split('&');
for (var i = 0; i < parts.length; i++) {
var pos = parts[i].indexOf('=');
if (parts[i].substring(0, pos) == name) {
return parts[i].substring(pos + 1);
}
}
} else if(query.length === undefined){
window.location.href = "#topOfPage";
}
return false;
}
});
However, I have noticed it scrolls slightly to the body of the accordion on load despite not having selected a specific panel. To fix this behavior I figured adding this else if block would check to see if the parameter was empty, if so we would force the window to scroll where that anchor is situated.
<a id="topOfPage" href='#'></a>
So wouldn't else if(query.length === undefined) work because you're saying nothing, is there?
P.S. I tried null too, and that didn't work!
Try running location.search.substring(1).length in your console and you will see what the issue is. It is equal to 0 which is not undefined. In your case, you don't need an else if, you can simply use an else

CRM Xrm.Page.ui.formSelector.items.get() Returning Null

I wrote javascript code and added it as a form on load event of entity(contact). In that Code I want to navigate from the opening form to another form.
For previous developments, I'm trying to get the id of the opening form which I need in order to navigate.
Code as shown below.
var id = Xrm.Page.ui.formSelector.getCurrentItem().getId();
if (itemid != null)
Xrm.Page.ui.formSelector.items.get(id).navigate();
Xrm.Page.ui.formSelector.getCurrentItem() function returns a null value. It doesn't get the item so I can't get the value. What's wrong with that code, what am I missing?
Thanks for replies in advance.
You are assigning the value to id variable but checking itemid in your IF condition.
In if condition just replace the if (itemid != null) with if (id != null)
To test your JavaScript. You can run following function:
var formItem = Xrm.Page.ui.formSelector.getCurrentItem();
if (formItem != null)
{
var itemId = formItem.getId();
var itemLabel = formItem.getLabel();
alert(itemId + " | " itemLabel);
}
else
{
alert("Unable to get current form");
}
Finally, to switch between form, following is very useful function which takes the form name as parameter. you can make changes to use form Id if you like.
function redirectToForm(formName) {
var currentForm = Xrm.Page.ui.formSelector.getCurrentItem();
if (currentForm != null) {
if (currentForm.getLabel().toLowerCase() != formName.toLowerCase()) { //make sure it's not already this form
var availableForms = Xrm.Page.ui.formSelector.items.get();
for (var i in availableForms) {
var form = availableForms[i];
if (form.getLabel().toLowerCase() == formName.toLowerCase()) {
form.navigate();
}
}
}
}
}
In My case, i prefer send the form name as parameter of a kind function such as constructor via load form function.
in the javascript code:
var Formname = "Default";
function Initialize(formname)
{
Formname = formname;
}
In customization of Form, in the onload function, you set this variable and this way remove the dependece from for selector component.
I hope that this solution can help many.
I took it up a notch and wrote the following post. You might find it interesting.
http://totbcrm.blogspot.co.il/2014/08/working-with-multiple-forms.html

Check if team already added

I have a page where you can invite teams. Clicking "Invite teams" makes a popup box appear showing a search input. The search-function is AJAX based. When a team is found through your search word(s), you'll have to click on the team whereupon the team will be showed in a "Invited-teams"-box.
It works in a way that when you "add" the team, a hidden input field is generated containing the team's ID as a value. The problem is that with my current code, it is possible to add the same team as many times as you wish. I should be possible to check, if the team can be found in the hidden-input-data. If it already exists, it should not be possible to add the sane team.
My current javascript-code can be found beneath here. Please notice that I have tried to make the code that checks the team, but it doesn't work.
function addTeam(tid) {
// Grab the input value
var teamName = document.getElementById(tid).innerHTML;
var teamID = document.getElementById(tid).id;
// If empty value
if(!teamName || !teamID) {
alert('An error occured.');
} else {
//Tried to do the "team-adlready-added"-test, but it doesn't work
var stored_teams = $t('#store-teams').getElementsByTagName('input');
for (var i = 0; i < stored_teams.length; i++) {
var stored_team = stored_teams[i];
if(stored_team.value == teamID) {
break;
var team_already_added = 1;
}
alert(team_already_added);
}
if((team_already_added) || team_already_added != 1) {
// Store the team's ID in hidden inputs
var store_team = document.createElement('input');
store_team.type = 'hidden';
store_team.value = teamID;
// Append it and attach the event (via onclick)
$t('#store-teams').appendChild(store_team);
// Create the teams with the value as innerHTML
var div = document.createElement('div');
div.className = 'team-to-invite';
div.innerHTML = teamName;
// Append it and attach the event (via onclick)
$t('#teams').appendChild(div);
}
div.onclick = removeTeam;
}
return false;
}
Thanks in advance.
I just want to give you a hint for a possible solution without html elements.
You can create a new functional object for team:
var Team = function (id, name) {
this.name = name;
this.id = id;
}
Create an array which will contain teams:
var TeamList = [];
Add you Teams:
TeamList.push(new Team(1, "Team 1"));
TeamList.push(new Team(2, "Team 2"));
TeamList.push(new Team(3, "Team 3"));
TeamList.push(new Team(4, "Team 4"));
Write a function which loops trough the list of teams and checks with the id if a team already exists:
function containsTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
return true;
}
}
return false;
}
Just check it:
containsTeam(1); //returns true
containsTeam(5); //returns false
Have a look at the jsFiddle DEMO and open the console to see the output.
EDIT: In addition, to remove an element you can write a function which looks pretty much the same as the containsTeam function. Just use array.splice instead of returning true:
function removeTeam(id) {
for (var i = 0; i < TeamList.length; i++) {
if (TeamList[i].id == id) {
TeamList.splice(i, 1);
}
}
}
And remove a team:
removeTeam(3);
Your variable scope is off.
You declare team already added in the wrong spot.
Declare it with team name and team id and it will get you in the right direction

Categories

Resources