This question already has answers here:
jQuery dot in ID selector? [duplicate]
(6 answers)
Closed 2 years ago.
I'm working on a legacy web app, that's using JQuery.
There's a place where we're trying to save all of the form data to local storage, before we redirect to a different page, so that we can restore it when we return.
This pattern is working on a number of pages:
$(document).ready(function () {
var searchForm = $('form.full-investigation');
var searchFormElements = searchForm.find(':input');
var saveSearchElements = function saveSearchElements() {
var saveData = [];
searchFormElements.each(function(index, element) {
var item = $(element);
var name = element.name;
var value = item.val();
var type = element.type;
var add = true;
if (type === "checkbox") {
value = element.checked;
} else if (type === "radio") {
if (!element.checked) {
add = false;
}
}
if (add) {
saveData.push({ name: name, value: value });
}
});
var serialized = JSON.stringify(saveData);
sessionStorage.setItem('FullInvestigation_criteria', serialized);
};
var loadSearchElements = function loadSearchElements(serializedForm) {
var foundOne = false;
if (serializedForm) {
var saveData = JSON.parse(serializedForm);
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name;
var value = saveData[i].value;
try {
var element = searchForm.find(':input[name=' + key + ']');
if (element.length > 1) {
for (var j = 0; j < element.length; j++) {
var each = element[j];
var type = each.type;
if (type === 'radio' && each.value === value) {
each.checked = true;
foundOne = true;
}
}
} else {
element.val(value);
if (value)
foundOne = true;
}
} catch (e) {
var msg = e;
}
}
}
return foundOne;
};
$("#redirectbutton").on('click',
function(event) {
try {
saveSearchElements();
} catch (e) {
}
});
var fullInvestigation_criteria = sessionStorage.getItem('FullInvestigation_criteria');
loadSearchElements(fullInvesigation_criteria);
sessionStorage.setItem('FullInvesigation_criteria', '{}');
});
As I said, this is working on a number of pages.
But when I try to use it on a different page, where it had not been used before, I'm getting syntax errors. The problem is that on this new page, saveSearchElements() encounters :input elements with dotted names. E.g., ticketAndMarking.actualnearinter. So we're saving name/value pair with a key of "ticketAndMarking.actualnearinter"
So when we process that key in
And then when we call loadSearchElements, and it processes that key, the line:
var element = searchForm.find(':input[name=' + key + ']');
throws an exception with the message:
Syntax error, unrecognized expression: :input[name=ticketAndMarking.actualnearinter]
I was asking this question for the group, but found the answer before I posted.
So here it is, in case anyone else runs into something similar:
jQuery dot in ID selector?
Having a period in an element name is perfectly acceptable. But JQuery selector syntax requires that they be escaped.
The fix in the code above is simple:
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name.replace(".", "\\.");
var value = saveData[i].value;
Related
I have a script that is searching for duplicated text strings in an array and changing the colors.
function checkDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
} //endif
});
$input.each(function(key) {
if (values[this.value]>1) {
error++;
$(this).addClass('double-error');
}
});
return (error <= 0); //returns false or true
}
<style type="text/css">
.double-error {
color:red;
border:1px solid red;
}
</style>
This is working fine.
However, I need to count duplicated strings and add keep track of whether they are the first occurence of that word, the second occurence of that word, etc.
For example:
Given john, john, peter, doe, peter, john, the result would be john-1, john-2, peter-1, doe, peter-2, john-3.
This is what I currently have:
function eliminateDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
}
});
$input.each(function(key) {
if (values[this.value]>1) {
error++;
myArray = values[this.value];
for (var i = 0; i < myArray; i++) {
$(this).parent()
.find('input[type=\'text\']')
.val(this.value + '-' + i);
}
}
});
return error <= 0; //return error > 0 ? false : true;
}
But I got this result:
john-0-1-2, john-0-1-2, peter-0-1, doe, peter-0-1, john-0-1-2
What's wrong?
I make some modification:
function eliminateDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
}
});
$input.each(function(key) {
if (values[this.value]>1) {
var name=this.value;
var names = values[this.value];
values[this.value]++;
for (var i = 0; i < names; i++){
$(this).parent().find('input[type=\'text\']').val(name + '-' + i);
}
}
});
checkDoubles();
return error <= 0; //return error > 0 ? false : true;
}
now I getting counts in sequence but not from 1.
for example if I have 4 duplicated names (Peter) i getting:
Peter-3, Peter-4, Peter-5, Peter-6.
but I need
Peter-1, Peter-2, Peter-3, Peter-4.
what wrong?
I think you're looking for something like this:
function eliminateDuplicates() {
var repeats = {};
var error = false;
//cache inputs
var $inputs = $("input[type='text']");
//loop through inputs and update repeats
for (i = 0; i < $inputs.length; ++i) {
//cache current element
var cur = $inputs[i];
//remove class
$(cur).removeClass("double-error");
//get text of this element
var text = $(cur).val();
//no text -- continue
if (text === "") {
continue;
}
//first time we've came across this value -- intialize it's counter to 1
if ((text in repeats) === false) {
repeats[text] = 1;
}
//repeat offender. Increment its counter.
else {
repeats[text] = repeats[text] + 1;
}
//update the the value for this one
$(cur).val(text + "-" + repeats[text]);
}
return error; // always returns false since I'm not sure
// when it's supposed to return true.
}
PS: I didn't understand when error was supposed to be true, so it's always false. Nevertheless, this should be enough to get you going.
PPS: Plunker here.
I have a function which gets values from elements:
function getTransactionValues() {
var o = {};
o.reservations = [];
$('#custom-headers option:selected').each(function (i, selected) {
o.reservations[i] = $(selected).val();
});
o.amount = $('input[name=amount-price]').val();
o.currency_value = $('input[name=currency-value]').val();
o.currency_name = $('.currency_appendto option:selected').html();
o.actual_amount = $('input[name=actual-amount]').val();
o.actual_remaining = $('input[name=actual-remaining]').val();
o.funds_arrival_date = $('input[name=funds-arrival]').val();
o.paid_to = $('.paidto option:selected').html();
o.checkbox = $('.multi-transaction:checked').map(function () {
return this.value
}).get();
return o;
}
Now i want to check whether amount, actual_amount and funds_arrival_date are filled. if they are i will release the disabled class from a button. i've tried
var check_review = function () {
var a = getTransactionValues();
var options = [a.amount, a.actual_amount, a.funds_arrival_date];
for(i = 0; i < options.length; i++) {
if(options[i].length > 0) {
$('a[name=review_button]').removeClass('disabled');
}
else{
//this array is empty
alert('There is a problem!');
}
}
}
$('.test').click(function() {
check_review();
});
But it doesn't seems to be working..
Remove disabled attribute using JQuery?
Can you please look at above link, I think we should use $('.inputDisabled').prop("disabled", false);
Even if a single array element will be non empty then your code will remove the class disabled from the a. To make sure that all the elements of array are non empty and then only you want to remove the class then the way is:
for(i = 0; i < options.length; i++) {
if(options[i].length > 0) {
$('a[name=review_button]').removeClass('disabled');
}
else{
$('a[name=review_button]').addClass('disabled');
}
}
Or the other way is
var check = true;
for(i = 0; i < options.length; i++) {
if(options[i].length == 0) {
check = false;
}
}
if(check ) $('a[name=review_button]').removeClass('disabled');
Try using Array.prototype.every()
if (options.every(Boolean)) {
$("a[name=review_button]").removeClass("disabled");
} else {
// do other stuff
}
I'm trying to create a key mapping that keeps track of the frequency for each character of a string in my createArrayMap() function but I keep getting this error from firebug: TypeError: str.charAt(...) is not a function
I found the charAt() function on Mozilla's developer website it should be a function that exists.
var input;
var container;
var str;
var arrMapKey = [];
var arrMapValue = [];
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
}
function createArrayMap() {
str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.find(str.charAt(i)) == undefined) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
function keyPressHandler() {
createArrayMap();
console.log(arrMapKey);
console.log(arrMapValue);
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value == "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
The problem is not with String.charAt(), but with Array.find().
The first argument to find is a callback, but the result of str.charAt(i) is a character and not a callback function.
To search for an element in your array, you could use Array.indexOf() as #adeneo already suggested in a comment
function createArrayMap() {
var str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.indexOf(str.charAt(i)) == -1) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
See JSFiddle
You're not going about things in the most efficient manner... What if you changed it to look like this so you are continually updated with each keypress?
var keyMap = {};
...
input.onkeyup = keyPressHandler;
function keyPressHandler(e) {
var char = String.fromCharCode(e.keyCode);
if(!(char in keyMap))
keyMap[char] = 1;
else
keyMap[char]++;
}
This has been answered, but here's my version of your problem JSBIN LINK (also has an object option in addition to the array solution).
I moved some variables around so you'll have less global ones, added comments, and mocked with the output so it'll show it on the page instead of the console.
besides the Array.find() issues, you weren't initializing your arrays on the build method, and so, you would have probably ended with the wrong count of letters.
HTML:
<div id="container">
<textArea id="inputbox"></textArea></div>
<p id="output">output will show here</p>
JS:
var input, // Global variables
container, //
output; //
/**
* Initialize components
*/
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
output = document.getElementById("output");
}
/**
* Creates the letters frequency arrays.
* Note that every time you click a letter, this is done from scratch.
* Good side: no need to deal with "backspace"
* Bad side: efficiency. Didn't try this with huge texts, but you get the point ...
*/
function createArrayMap() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
arrMapKey = [], // our keys
arrMapValue = []; // our values
for (var i = 0 ; i <len ; i++) {
// These 2 change each iteration
tempChar = tempStr.charAt(i);
index = arrMapKey.indexOf(tempChar);
// If key exists, increment value
if ( index > -1) {
arrMapValue[index]++;
}
// Otherwise, push to keys array, and push 1 to value array
else {
arrMapKey.push(tempChar);
arrMapValue.push(1);
}
}
// Some temp output added, instead of cluttering the console, to the
// a paragraph beneath the text area.
output.innerHTML = "array keys: "+arrMapKey.toString() +
"<br/>array values:"+arrMapValue.toString();
}
function keyPressHandler() {
createArrayMap();
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value === "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
BTW, as the comments suggest, doing this with an object will is much nicer and shorter, since all you care is if the object has the current char as a property:
/**
* Same as above method, using an object, instead of 2 arrays
*/
function createObject() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
freqObj = {}; // our frequency object
for (var i = 0 ; i <len ; i++) {
tempChar = tempStr.charAt(i); // temp char value
if (freqObj.hasOwnProperty(tempChar))
freqObj[tempChar]++;
else
freqObj[tempChar] = 1;
}
}
I've made some new objects with object methods and I'm having trouble returning the information.
I intend for allPages to be a 2d array:
var allPages = [[]];
function textbox(type)
{
this.type=type;
this.getInfo = function () { return ( this.type ); };
}
function addTextbox(dropdown)
{
var myindex = dropdown.selectedIndex;
var SelValue = dropdown.options[myindex].value;
if(SelValue == "String")
{
var tb = new textbox("string");
allPages[allPages.length-1].push(tb);
var string = "";
for (i = 0;i < allPages.length;i++)
{
for(j = 0;j < allPages[i].length;j++)
{
string = string + allPages[i][j].getInfo;
}
}
<!-- Problem here: prints "function () { return this.type; }"-->
document.write(string);
}
}
}
You are not calling the function, you are referencing it
allPages[i][j].getInfo;
should be
allPages[i][j].getInfo();
3 lines above where you state the problems exists, it should be:
string = string + allPages[i][j].getInfo(); // mind the () at the end.
function checkSelect(field_id)
{
var oParent = document.getElementById(field_id);
alert(oParent);
var aElements = oParent.getElementsByTagName('input');
alert(aElements);
var c_value = "";
for (var i = 0; i < aElements.length; i++)
{
if (aElements[i].type == 'checkbox')
{
if(aElements[i].checked )
{
c_value=aElements[i].checked.value;
alert(c_value);
}
}
}
//alert(c_value);
}
The code i have searched from here. Please let me know what I'm doing wrong. I want to get the values of checkboxes by it's fieldname or fieldid passed through function. Javascript is not getting the value "fieldid" as the name of checkbox causes an error. If I give the hardcoded value then it works like function given below.
function checkSelect()
{
var bool=false;
var field=document.countryManagementForm.country_ids;
var length=1;
if(field.length==null)
{
//alert("yes");
}
else
{
///alert("No");
length=field.length;
}
for (i = 0; i < length; i++)
{
if(field[i].checked == true)
{
bool=true;
}
}
if(!bool)
{
alert("Please select atleast one country");
return false;
}
else
{
return true;
}
}
I would recommend using a javascript framework for this. It's a breeze to do what you want to do:
For ID:
$('#id').val();
For names:
$('[name="name"]').val();
Jquery and the Docs
change
c_value=aElements[i].checked.value;
to
c_value=aElements[i].value;
and try it again
Looks like country_ids is the name of your checkbox inputs. If so, you can replace this line
var aElements = oParent.getElementsByTagName('input');
by
var aElements = document.getElementsByName(field_id);
and ignore the lines above it. Call your function as checkSelect('country_ids')