Why is this javascript object referring to a previous object's properties? - javascript

I am creating a class that can create any number of captchas on a page.I have a captcha class that I am using to instantiate new captcha objects c1 and c2. Here is my JS:
$(function(){
var captcha = {
parentForm : '',
container : '',
captcha_input : '',
number1 : 0,
number2 : 0,
createCaptcha : function(form_ID){
var newHtml;
this.parentForm = $('#' + form_ID);
this.container = this.parentForm.find('.captchaContainer');
this.number1 = this.randomNumber(10);
this.number2 = this.randomNumber(10);
newHtml = 'What does ' + this.number1 + ' plus ' + this.number2 + ' equal? <b class="required goldenrod" title="Required Field">*</b><br/><br/><input type="text" name="captcha">';
this.container.html(newHtml);
},
isValid : function(){
console.log(this.container);
this.captcha_input = this.container.find('input[name="captcha"]');
if (this.number1 + this.number2 == this.captcha_input.val()) {
this.captcha_input.css('background-color', '')
return true;
} else{
this.captcha_input.css('background-color', '#FFCCCC')
alert(this.number1 + ' plus ' + this.number2 + ' does not equal ' + this.captcha_input.val() + '. Please try again.');
this.captcha_input.focus();
return false;
}
},
randomNumber : function(max){ return Math.floor(Math.random()*(max+1)); }
}
var c1 = captcha,
c2 = captcha;
c1.createCaptcha("form1");
c2.createCaptcha("form2");
$('#form1 input[type="submit"]').click(function() {
if(c1.isValid()){
alert('Captcha is valid!');
}else{
return false;
}
});
$('#form2 input[type="submit"]').click(function() {
if(c2.isValid()){
alert('Captcha is valid!');
}else{
return false;
}
});
});
And my HTML:
<form id="form1">
<div class="captchaContainer"></div>
<input type="submit">
</form>
<form id="form2">
<div class="captchaContainer"></div>
<input type="submit">
</form>
When I click on form1's submit button, it seems like the isValid method is being ran for c2 and not c1 like I expect. Any idea why this is doing so?
A few things to note:
If I add more captcha instances and HTML, each submit button will run isValid on the last instance of captcha on click.
This needs to work for IE8+
Here is a fiddle of the code in action.
Any help would be greatly appreciated. Thanks!

c1 and c2 are both the same object. Use Object.create to create different instances. Object.create is not supported in old browsers, however there's a polyfill in the link I provided.
var c1 = Object.create(captcha),
c2 = Object.create(captcha);

You can also perform a deep copy of the object.
function deepCopy(obj) {
var res = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = obj[key];
};
}
res.prototype = obj.prototype; // this would make it a deep copy.
return res;
};
var c1 = deepCopy(captcha);

While #plalx had a valid answer, it wasn't an ideal answer for my scenario. Since I cannot instantiate a class that was created from an object literal (without use of Object.create), I decided to refactor my class with a function instead:
$(function(){
var Captcha = function(){
var parentForm = '',
container = '',
captcha_input = '',
number1 = 0,
number2 = 0,
createCaptcha = function(form_ID){
var newHtml;
this.parentForm = $('#' + form_ID);
this.container = this.parentForm.find('.captchaContainer');
this.number1 = randomNumber(10);
this.number2 = randomNumber(10);
newHtml = 'What does ' + this.number1 + ' plus ' + this.number2 + ' equal? <b class="required goldenrod" title="Required Field">*</b><br/><br/><input type="text" name="captcha">';
this.container.html(newHtml);
},
isValid = function(){
this.captcha_input = this.container.find('input[name="captcha"]');
if (this.number1 + this.number2 == this.captcha_input.val()) {
this.captcha_input.css('background-color', '')
return true;
} else{
this.captcha_input.css('background-color', '#FFCCCC')
alert(this.number1 + ' plus ' + this.number2 + ' does not equal ' + this.captcha_input.val() + '. Please try again.');
this.captcha_input.focus();
return false;
}
},
randomNumber = function(max){ return Math.floor(Math.random()*(max+1)); }
return{
createCaptcha : createCaptcha,
isValid : isValid
}
}
// Instantiation of Captcha objects
var c1 = new Captcha,
c2 = new Captcha;
c1.createCaptcha("form1");
c2.createCaptcha("form2");
$('#form1 input[type="submit"]').click(function() { if(c1.isValid()){ alert('Captcha is valid!'); }else{ return false; } });
$('#form2 input[type="submit"]').click(function() { if(c2.isValid()){ alert('Captcha is valid!'); }else{ return false; } });
});
Here is the new working fiddle
TLDR: Since object literals cannot be instantiated without Object.create, I used a function to create the class instead, and then instantiated like so:
var c1 = new Captcha,
c2 = new Captcha;

Related

How can I delete Items from json string without using $.grep

I have a cart variable and I am storing the cart inside it like this.
[{"course_id":"24","doc_id":"211","doc_title":"PDF Notes","doc_price":"500"},{"course_id":"25","doc_id":"217","doc_title":"PDF Notes","doc_price":"500"},{"course_id":"25","doc_id":"218","doc_title":"PDF Solved Past Papers","doc_price":"500"},{"course_id":"26","doc_id":"224","doc_title":"PDF Solved Past Papers","doc_price":"595"}]
I created a RemoveFromCart function. It works in simple JQUERY But it is not working in Framework 7 because of $.grep. Is there any other way I can do it without using $.grep?
This is my Function
function removeFromCart(course_id, doc_id) {
var x = confirm("Are you sure you want to remove this item from your cart?");
if (x) {
$$('#cart_body').html('');
existing_cart = localStorage.getItem("cart");
if (existing_cart == '') {
existing_cart = [];
} else {
existing_cart = JSON.parse(existing_cart);
}
existing_cart = $.grep(existing_cart, function (data, index) {
return data.doc_id != doc_id
});
ex_cart = JSON.stringify(existing_cart);
localStorage.setItem('cart', ex_cart);
existing_cart = localStorage.getItem("cart");
if (existing_cart == '') {
existing_cart = [];
} else {
existing_cart = JSON.parse(existing_cart);
}
if (existing_cart !== null && existing_cart.length > 0) {
var total = '';
$$('#cart_div').show();
existing_cart.forEach(function (arrayItem) {
var text = '';
text = '<li class="item-content"><div class="item-inner"><div class="item-title">' + arrayItem.doc_title + '</div><div class="item-after">' + arrayItem.course_id + '</div><div class="item-after">' + arrayItem.doc_price + '</div><div class="item-after"><i class="icon icon-cross" onclick="removeFromCart(' + arrayItem.course_id + ',' + arrayItem.doc_id + ')"></i></div></div></li>';
total = Number(total) + Number(arrayItem.doc_price);
$$('#cart_body').append(text);
});
text = '<tr><td></td><td class="text-center"><b>Total: </b></td><td class="text-center">' + total + '</td><td></td></tr>';
$$('#cart_body').append(text);
} else {
$$('#cart_div').hide();
text = '<p>Your cart is empty.</p>';
$$('#cart_body').append(text);
}
} else {
return false;
}
}
Instead of:
$.grep(existing_cart, function ...
You can use:
existing_cart.filter(function ...
var new_courses = existing_cart.map( v=> {
if(v.doc_id != doc_id)
return v
}).filter( v=> {return v})
// new_courses does not contain the course with doc_id
map loops through each member of an array. filter removes members not returned in map.

Javascript for showing Div on click using getElementsByClassName

I have a <div> in my page like this:
<div class="errordiv" style="display: none;">Username is empty</div>
I have an input field and a button like this:
<input type="textbox" id="txt1" />
<input type="button" value="Submit" id="btn1" onclick="validate();" />
I have tried this,
function validate() {
//alert('hi');
var inptextbox = document.getElementById('txt1');
//alert('level zero');
var errorMsg = document.getElementsByClassName('errordiv').item();
//alert('level ground');
if (inptextbox.value == '') {
//alert('hi2');
errorMsg.style.display = 'block';
} else {
errorMsg.style.display = 'none';
}
}
The above js code is not working. I am not getting the level ground alert. I don't know what is missing.
P.S : I don't want Jquery as my page has some restriction to use library files.
You need to return false in validate to stop the form from submitting, which reloads the page
EDIT
added polyfill for getElementsByClassName with support for IE7 from https://gist.github.com/2299607
// Add a getElementsByClassName function if the browser doesn't have one
// Limitation: only works with one class name
// Copyright: Eike Send http://eike.se/nd
// License: MIT License
if (!document.getElementsByClassName) {
 document.getElementsByClassName = function(search) {
var d = document, elements, pattern, i, results = [];
if (d.querySelectorAll) { // IE8
 return d.querySelectorAll("." + search);
}
if (d.evaluate) { // IE6, IE7
 pattern = ".//*[contains(concat(' ', #class, ' '), ' " + search + " ')]";
 elements = d.evaluate(pattern, d, null, 0, null);
 while ((i = elements.iterateNext())) {
results.push(i);
 }
} else {
 elements = d.getElementsByTagName("*");
 pattern = new RegExp("(^|\\s)" + search + "(\\s|$)");
 for (i = 0; i < elements.length; i++) {
if ( pattern.test(elements[i].className) ) {
 results.push(elements[i]);
}
 }
}
return results;
 }
}
function validate() {
//alert('hi');
var inptextbox = document.getElementById('txt1');
//alert('level zero');
var errorMsg = document.getElementsByClassName('errordiv')[0];
//alert('level ground');
if (inptextbox.value == '') {
//alert('hi2');
errorMsg.style.display = 'block';
return false;
} else {
errorMsg.style.display = 'none';
}
}
Your code works in chrome. This is the demo.
document.getElementsByClassName will not work for some old browsers, check here.
First off you'll need to return a value from your function to stop the page posting back if a validation even occurs, change your HTML to:
<input type="button" value="Submit" id="btn1" onclick="return validate();" />
Then your script to:
function validate() {
var inptextbox = document.getElementById('txt1');
var errorMsg = document.getElementsByClassName('errordiv').item();
if (inptextbox.value == '') {
errorMsg.style.display = 'block';
return false;
}
return true;
}

JavaScript isCurrency() failing

hey guys should be a easy one...I have some javascript that is turning my input values into currency values. Problem is it will fail if I try to type in .5 heres is my code:
function handleCurrency(formName,fieldName)
{
var enteredValue = document.forms[formName].elements[fieldName].value;
if ( enteredValue.isCurrency() )
{
alert("This is currency " + enteredValue )
// Put the nicely formatted back into the text box.
document.forms[formName].elements[fieldName].value = enteredValue.toCurrency();
}
}
jsp:
<td><input type="text" name="replacementCost" onchange="handleCurrency('NsnAdd','replacementCost')" value="<ctl:currencyFormat currency='${form.replacementCost}'/>" onkeypress="javascript:return noenter();" <c:if test="${!lock.locked}">disabled="disabled"</c:if> /></td>
How can I make it so that .5 is allowable also to be formatted?
custom javascript:
var patternWithCommas = new RegExp("^\\s*\\$?-?(\\d{1,3}){1}(,\\d{3}){0,}(\\.\\d{1,2})?\\s*$");
var patternWithoutCommas = new RegExp("^\\s*\\$?-?\\d+(\\.\\d{1,2})?\\s*$");
function stringIsCurrency()
{
if (patternWithoutCommas.test(this))
{
return true;
}
else if (patternWithCommas.test(this))
{
return true;
}
return false;
}
function stringToCurrency()
{
if (this == '') return this;
var str = this.replace(/[$,]+/g,'');
sign = (str == (str = Math.abs(str)));
str = Math.floor(str*100+0.50000000001);
cents = str%100;
str = Math.floor(str/100).toString();
if (cents<10) cents = "0" + cents;
for (var i = 0; i < Math.floor((str.length-(1+i))/3); i++)
{
str = str.substring(0,str.length-(4*i+3))+','+
str.substring(str.length-(4*i+3));
}
str = '$' + ((sign)?'':'-') + str + '.' + cents;
return str;
}
String.prototype.isCurrency = stringIsCurrency;
String.prototype.toCurrency = stringToCurrency;
basically it needs to allow .5 and not just 0.5
this needs to be updated:
var patternWithCommas = new RegExp("^\\s*\\$?-?(\\d{1,3}){1}(,\\d{3}){0,}(\\.\\d{1,2})?\\s*$");
You have not shown your code for isCurrency.
Here's how I would do it:
function isCurrency( val )
{
return /^\$?(?:\d[\d,]*)?(?:.\d\d?)?$/.test( val );
}
See it here in action: http://regexr.com?3103a
Now that you have provided your code, here's my proposed solution.
While there are many things I would have done differently,
in order to keep the spirit of your code, just change this:
var patternWithCommas = new RegExp("^\\s*\\$?-?(\\d{1,3}){1}(,\\d{3}){0,}(\\.\\d{1,2})?\\s*$");
var patternWithoutCommas = new RegExp("^\\s*\\$?-?\\d+(\\.\\d{1,2})?\\s*$");
to this:
var patternWithCommas = /^\s*\$?-?((\d{1,3}){1}(,\d{3})?)?(\.\d{1,2})?\s*$/;
var patternWithoutCommas = /^\s*\$?-?(\d+)?(\.\d{1,2})?\s*$/;
which would make the dollar amount optional.

Why is my backbone view render putting "undefined" at the top?

Most of the render function in the following view is irrelevant, I think but I'm leaving it for completeness. I'm stepping through a list of workflow steps, noting switching the class of the li depending on various states of the thing.
var WorkStepView = Backbone.View.extend({
className: "workflowStep",
render: function() {
var output;
var arrowPlaced = false;
var self = this;
i = 0;
_.each(this.collection.models, function(s) {
var post = "";
var classname = '';
if (s.attributes["complete"] != 1) {
if (! arrowPlaced) {
classname = "current";
if (s.attributes["adminCompletable"] == 1 ) {
post = ' - <input onClick="completeStep(' + i + ');" type="button" value="Completed" />';
}
arrowPlaced = true;
}
else {
classname = "future";
}
}
else {
classname = "past";
}
output += '<li class="' + classname + '">' + s.attributes["description"] + post + '</li>';
i++;
});
this.el.innerHTML = output;
return this;
},
});
When the user selects an asset from a list elsewhere on the page, it brings up a bunch of data including this stuff. An asset "has" a workflow, which "has" many steps. The step data is stored in window.Steps, and then this is called:
function populateSteps() {
window.workStepLists = new WorkStepView({
collection: window.Steps,
el: $('#workflowSteps')[0],
});
workStepLists.render();
}
But then I get this:
There's this extraneous "undefined" up there at the top of the list. It wasn't there before fetching and rendering this model. I don't know what's up with that at all.
Help?
You are not initializing output to be anything. So, output += "foo" becomes "undefinedfoo".
Simply initialize your output variable with an empty string:
var output = '';

How to write the keypress event in Jquery/ Javascript?

I am new to Jquery and Javascript. Need a help regarding this problem:
There is a div named Profile , If I click that then a new popup window will open. Now this is only possible by a mouse click. I need it to be done by key press (enter) also.
JSP CODE FOR THE DIV
<div tabindex="0" style="text-decoration:underline" onmouseover="this.style.cursor='pointer';" id="<%=namespace%>_pmProfileName_<%=i%>_" onclick="perfChartConfig_<%=namespace%>.doShowProfilesForElement(this);">Profile</div>
JQUERY/JAVASCRIPT CODE
doShowProfilesForElement : function(source){
var callback = {
success : function(r) {
MO.globals.popups.hideWorkingMsg();
this.argument[0].pe = eval("("+r.responseText+")");
var pe = this.argument[0].pe;
var pStr = '';
if(this.argument[1].indexOf("pmProfileName") > 0){
if(pe == null || pe._mosol_AllPerfProfileNames.length==0){
pStr = pStr + "<li>There are no profiles available for the element you selected.</li>";
} else {
for(var i=0; i<pe._mosol_AllPerfProfileNames.length;i++){
var profile = pe._mosol_AllPerfProfileNames[i];
var onClick = "onClick=\"perfChartConfig_<%=namespace%>.doProfileSelection(this,'"+this.argument[1]+"');\"";
pStr = pStr + "<div style=\"text-decoration:underline\" onmouseover=\"this.style.cursor='pointer';\" "+onClick+" >"+profile+"</div>";
//alert('For profile ['+profile+'] there are '+pe[profile].length+' expressions.');
}
}
}
if(this.argument[1].indexOf("slaProfileName") > 0){
if(pe == null || pe.offers.length==0){
pStr = pStr + "<li>There are no SLAs available for the element you selected.</li>";
} else {
for(var i=0; i<pe.offers.length;i++){
var profile = pe.offers[i];
var onClick = "onClick=\"perfChartConfig_<%=namespace%>.doProfileSelection(this,'"+this.argument[1]+"');\"";
pStr = pStr + "<div style=\"text-decoration:underline\" onmouseover=\"this.style.cursor='pointer';\" "+onClick+" >"+profile+"</div>";
}
}
}
var rp = perfChartConfig_<%=namespace%>.rp;
rp.setHeader("Select a Profile you want to chart:");
rp.setBody(pStr);
rp.render();
rp.show();
},
failure : function(r) {
MO.globals.popups.hideWorkingMsg();
MO.globals.popups.showMsg("Error", "<h2><span class=\"portlet-msg-error\">Your submission failed</span>"+"<br />Status: " + r.status + "</h2>");
},
argument: [this, source.id]
};
Would you tell me how to write the function for keypress(enter) ?
bind the keypress or keyup event with you div
<div tabindex="0" class="someClass" style="text-decoration:underline" onmouseover="this.style.cursor='pointer';" id="<%=namespace%>_pmProfileName_<%=i%>_" onclick="perfChartConfig_<%=namespace%>.doShowProfilesForElement(this);">Profile</div>
add some class
$("div.someClass").bind("keyup",function(e){
if(e.keyCode == 13)
{
$(this).click();
}
});
$("#Profile").keyup(function(e){
var code = e.which;
if(code==13){
e.preventDefault();
//Do Stuff
}
});

Categories

Resources