Remove a Function from being repeated - javascript

Its hard to explain this so I'll try my best.
Is it possible to use .remove() to remove a javascript function from being repeated?
function
function readytouseCard() {
console.log(this);
$('.cardCVV input[name=cvv1]').keyup(function () {
console.log("s");
var checkCVV = $('.cardCVV input[name=cvv1]').filter(function () {
return $.trim(this.value).length < 3;
}).length === 0;
if (checkCVV) {
$("li.checkCode").addClass("checked");
} else {
$("li.checkCode").removeClass("checked");
}
checklistCheck();
});
function checklistCheck() {
var counting = $("li.checked:not(.title)").length;
if (counting == 6) {
console.log(counting);
$("input[name=purchase]").attr("disabled", false);
$("input[name=purchase]").removeClass("purchase-btn-disabled");
$("input[name=purchase]").addClass("purchase-btn");
} else {
$("input[name=purchase]").attr("disabled", true);
$("input[name=purchase]").removeClass("purchase-btn");
$("input[name=purchase]").addClass("purchase-btn-disabled");
}
}
}
The Main
$("li#usercurrentcc").click(function (e) {
e.preventDefault();
var selectedID = $(this).attr("data-id");
var qString = 'selectedID=' + selectedID;
$.post('/assets/inc/get-logged-info-card.php', qString, function (results) {
if ($("#usercurrentccbox, #addnewccbox").length != 0) {
$("#usercurrentccbox, #addnewccbox").fadeOut("fast", function () {
$(this).remove();
$("<div class='creditCardDetails' id='usercurrentccbox'><div class='creditCard'><div class='cardChoice'><span>Choose Card Type</span><input name='cctype1' type='radio' value='V' class='lft-field' id='visa' /><label for='visa'></label><input name='cctype1' type='radio' value='M' class='lft-field' id='mastercard' /><label for='mastercard'></label><input name='cctype1' type='radio' value='A' class='lft-field' id='amex' /><label for='amex'></label></div><!--cardChoice--><div class='cardNumber'><input name='ccn1' id='ccn' type='text' class='long-field' value='" + results[0].maskccn + "' maxlength='19' readonly /></div><div class='cardCVV'><input name='cvv1' id='cvv' type='text' maxlength='5' class='small-field' /></div><div class='creditCardName'><input name='ccname1' id='ccname' type='text' class='long-field' value='" + results[0].ccname + "' readonly/></div><div class='cardDate'><input name='exp11' id='exp1' type='text' maxlength='2' class='small-field' value='" + results[0].ccm + "' readonly /><input name='exp21' id='exp2' type='text' maxlength='4' class='small-field' value='" + results[0].ccy + "' readonly /></div></div><!--creditCard-->").insertAfter("#paymentCardChoice");
$('#usercurrentccbox .cardChoice input#' + results[0].cct + '').attr("checked", true);
$('#usercurrentccbox .cardChoice label').removeClass("active");
$('#usercurrentccbox .cardChoice label[for="' + results[0].cct + '"]').addClass("active");
$("li:not(.title,.checkCode)").addClass("checked");
});
readytouseCard();
} else {
$(".submit-btn").fadeIn();
$("<div class='creditCardDetails' id='usercurrentccbox'><div class='creditCard'><div class='cardChoice'><span>Choose Card Type</span><input name='cctype1' type='radio' value='V' class='lft-field' id='visa' /><label for='visa'></label><input name='cctype1' type='radio' value='M' class='lft-field' id='mastercard' /><label for='mastercard'></label><input name='cctype1' type='radio' value='A' class='lft-field' id='amex' /><label for='amex'></label></div><!--cardChoice--><div class='cardNumber'><input name='ccn1' id='ccn' type='text' class='long-field' value='" + results[0].maskccn + "' maxlength='19' readonly /></div><div class='cardCVV'><input name='cvv1' id='cvv' type='text' maxlength='5' class='small-field' /></div><div class='creditCardName'><input name='ccname1' id='ccname' type='text' class='long-field' value='" + results[0].ccname + "' readonly/></div><div class='cardDate'><input name='exp11' id='exp1' type='text' maxlength='2' class='small-field' value='" + results[0].ccm + "' readonly /><input name='exp21' id='exp2' type='text' maxlength='4' class='small-field' value='" + results[0].ccy + "' readonly /></div></div><!--creditCard-->").insertAfter("#paymentCardChoice");
$('#usercurrentccbox .cardChoice input#' + results[0].cct + '').attr("checked", true);
$('#usercurrentccbox .cardChoice label').removeClass("active");
$('#usercurrentccbox .cardChoice label[for="' + results[0].cct + '"]').addClass("active");
$("li:not(.title,.checkCode)").addClass("checked");
}
readytouseCard();
}, "json");
});
readytouseCard();
The function starts and works on the first click but after that it doesn't work again. console log just shows Window # and when I click again it show Window # Window #
So I was hoping there was a way to kill the function readytouseCard() using .remove();
Thanks in advance

You can't "remove" functions, you can just override them, e.g. readytouseCards = function(){}.
However I don't understand, why you want to to that. And Console logging Window is correct, because you have console.log(this); on the first line of your function. Since you call readytouseCards from global context, this is bound to window.
Your actual problem is that you attach an eventhandler inside your readytouseCards(). Thus calling the function the second time attaches the eventhandler twice. This results in checklistCheck() being called twice on every keyup. This is indicated by your console logging window twice.
You need to refactor your whole code:
Attach the eventhandler ONCE in the beginning via .on() (jQuery on()) so that elements added to the dom later on have the eventhandler attached too.
$(document).on('keyup', '.cardCVV input[name=cvv1]', function () { ... }
and kill the function readytouseCard() by moving the checklistCheck() out of it. Finally, omit the readytouseCard(); calls.

It's global, which means that we can access it through the window.
window.readytouseCard() = function(){
return false;
}
Now that we've done that, the functions contents have been replaced with return false; which will mimic nothing happening.

I have reindented your code. As you can see now, when there are #usercurrentccbox, #addnewccbox found after the Ajax request, the function will be called twice. Just remove the first one.
If you want to remove an event listener automatically after it was executed once, jQuery offers .one().
You can't delete a function. If the function is determined by an identifier each time it is invoked, you may be able to overwrite that variable with a different function. However, that won't work when the reference to the function is stored in a inaccessible variable, e.g. when added as an event listener. Then you'd need to code:
var called = false;
function executeOnlyOnce(...) {
if (called) return;
called = true;
...
}

Related

jQuery variable is not updating on dynamic created textbox

I am trying to detect the current button click to assign values to its respective textboxes. Each time I select any of the button, it will detect the first button click and assign the value to the first textbox. Meaning to say that, the second and third button values are assigned to the first textbox. The upload_textbox variable is not changing its value.
I did some error testing, when upload_textbox variable enters custom_uploader.on('select', function(), the value stays and will not change. I am not sure on why it doesn't.
What have I done wrong here? Below are my codes:
function dynamic_image( button )
{
var custom_uploader;
$(button).on('click','input.button',function(e)
{
e.preventDefault();
var $clickedInput = $(this);// JQuery Object of section2_2
var clickedInputId = $clickedInput.attr('id'); // section2_2
var upload_textbox = '#' + 'upload_image_' + clickedInputId;
//If the uploader object has already been created, reopen the dialog
if (custom_uploader) {
custom_uploader.open();
return;
}
//Extend the wp.media object
custom_uploader = wp.media.frames.file_frame = wp.media(
{
title: 'Choose Image',
button: {
text: 'Choose Image'
},
multiple: false
});
//When a file is selected, grab the URL and set it as the text field's value
custom_uploader.on('select', function()
{
attachment = custom_uploader.state().get('selection').first().toJSON();
$(upload_textbox).val(attachment.url);
//console.log(upload_textbox);
});
//Open the uploader dialog
custom_uploader.open();
})
}
dynamic_image('#TextBoxesGroup');
HTML
<tr class="form-field">
<th scope="row">
<label for="component1"> Component 1</label>
<br></br>
<input type='button' class="button button-large" value='+' id='addButton'>
<input type='button' class="button button-large" value='-' id='removeButton'>
<input type='button' class="button button-large" value='Get TextBox Value' id='getButtonValue'>
</th>
<td>
<div id='TextBoxesGroup'>
<div id="ImageDiv1">
<input id="section2_1" class="button" type="button" value="Upload Image" name="upload_s2_1"/>
</div>
<div id="TextBoxDiv1">
<label>Title #1 : </label>
<input type='text' id='title1' />
</div>
<div id="DescDiv1">
<label>Description #1 : </label>
<input type='text' id='description1' /><br></br>
</div>
</div>
</td>
</tr>
script
<script type="text/javascript">
$(document).ready(function(){
var counter = 2;
$("#addButton").click(function () {
if(counter>5){
alert("Only 5 components are allowed");
return false;
}
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + counter);
var newDescDiv = $(document.createElement('div'))
.attr("id", 'DescDiv' + counter);
var newImageDiv = $(document.createElement('div'))
.attr("id", 'ImageDiv' + counter);
var newUploadDiv = $(document.createElement('div'))
.attr("id", 'UploadDiv' + counter);
newTextBoxDiv.after().html('<label>Title #'+ counter + ' : </label>' +
'<input type="text" name="textbox' + counter +
'" id="title_section2_' + counter + '" value="" >');
newDescDiv.after().html('<label>Description #'+ counter + ' : </label>' +
'<input type="text" name="descbox' + counter +
'" id="desc_section2_' + counter + '" value="" ><br></br>');
newImageDiv.after().html('<input class="button" type="button" name="upload_s2_' + counter +
'" value="Upload Image" id="section2_' + counter + '" >');
newUploadDiv.after().html('<input type="text" name="image_url_' + counter +
'" id="upload_image_section2_' + counter + '" >');
newUploadDiv.appendTo("#TextBoxesGroup");
newImageDiv.appendTo("#TextBoxesGroup");
newTextBoxDiv.appendTo("#TextBoxesGroup");
newDescDiv.appendTo("#TextBoxesGroup");
counter++;
});
$("#removeButton").click(function () {
if(counter==1){
alert("No more component to remove");
return false;
}
counter--;
$("#TextBoxDiv" + counter).remove();
$("#DescDiv" + counter).remove();
$("#ImageDiv" + counter).remove();
});
$("#getButtonValue").click(function () {
var msg = '';
for(i=1; i<counter; i++){
msg += "\n Textbox #" + i + " : " + $('#textbox' + i).val();
}
alert(msg);
});
});
</script>
Then I suspect this could be the culprit.
//If the uploader object has already been created, reopen the dialog
if (custom_uploader) {
custom_uploader.open();
return;
}
This would always give you instance of first custom_uploader object.
Try to destroy the previous instance and generate new one.
There might be issue with the event binding within dynamic_image method.
Try
$(button).live('click',function(e) (deprecated as of jQuery 1.7 though)
or
$( document ).on( 'click', button, data, function(e)
instead of
$(button).on('click','input.button',function(e)
I hope it helps.
Can you try following.
$(button).change(function(){
//Write code here
});
I have solved my question. The culprit behind this was the custom_uploader mentioned by #Aman. There was a return statement there where it made the function not to take the new value that has been replaced. After doing so, the custom_uploader opens twice because there is two statement of it which it was called. Did it into an if else statement and had it the way I wanted. Below is my updated code.
function dynamic_image( button )
{
var custom_uploader;
var upload_textbox;
$(button).on('click','input.button',function(e)
{
e.preventDefault();
var $clickedInput = $(this);
var clickedInputId = $clickedInput.attr('id');
upload_textbox = '#' + 'upload_image_' + clickedInputId;
//Extend the wp.media object
custom_uploader = wp.media.frames.file_frame = wp.media(
{
title: 'Choose Image',
button: {
text: 'Choose Image'
},
multiple: false
});
//When a file is selected, grab the URL and set it as the text field's value
custom_uploader.on('select', function()
{
attachment = custom_uploader.state().get('selection').first().toJSON();
$(upload_textbox).val(attachment.url);
});
if (custom_uploader) {
custom_uploader.open();
}else
//Open the uploader dialog
custom_uploader.open();
})
}
#Aman, you have mentioned about optimizing it. It seems quite fast at the moment. Maybe if there is a way to optimize it for the better, it would be a great help.
Thank you all, #Regent, #Aman, #Bhushan Kawadkar, #Arindam Nayak, #Raj

Previous fields text disappears when adding new one with select2 ajax

I was using select2 plugin on my input box to search items from the database using AJAX based on what the user type on it. It was working fine, I can search Items on it and select it when its available, but my problem is whenever I add new rows on my table the previous item fields "text" will be gone, I'm making a table where you can add/remove rows dynamically so here is my HTML:
<td><input name='product[0][name]' class='form-control col-lg-5 itemSearch' type='text' placeholder='select item' /></td>
and my javascript:
function addRow(){
var toBeAdded = document.getElementById('toBeAdded').value;
if (toBeAdded=='')
{ toBeAdded = 2; }
else if(toBeAdded>10)
{
toBeAdded = 10;
}
for (var i = 0; i < toBeAdded; i++) {
var rowToInsert = '';
rowToInsert = "<tr><td><input name='product["+rowArrayId+"][name]' class='form-control col-lg-5 itemSearch' type='text' placeholder='select item' /></td>";
$("#tblItemList tbody").append(
rowToInsert+
"<td><textarea readonly name='product["+rowArrayId+"][description]' class='form-control description' rows='1' ></textarea></td>"+
"<input type='hidden' name='product[" + rowArrayId + "][itemId]' id='itemId'>"+
"<td><input type='number' min='1' max='9999' name='product["+rowArrayId+"][quantity]' class='qty form-control' required />"+
"<input id='poItemId' type='hidden' name='product[" + rowArrayId + "][poContentId]'></td>"+
"<td><input type='number' min='1' step='any' max='9999' name='product["+rowArrayId+"][price]' class='price form-control' required /></td>"+
"<td class='subtotal'><center><h3>0.00</h3></center></td>"+
"<input type='hidden' name='product["+rowArrayId+"][delete]' class='hidden-deleted-id'>"+
"<td class='actions'><a href='#' class='btnRemoveRow btn btn-danger'>x</a></td>"+
"</tr>");
rowArrayId = rowArrayId + 1;
};
$(".itemSearch").select2({
placeholder: 'Select a product',
formatResult: productFormatResult,
formatSelection: productFormatSelection,
dropdownClass: 'bigdrop',
escapeMarkup: function(m) { return m; },
minimumInputLength:1,
ajax: {
url: '/api/productSearch',
dataType: 'json',
data: function(term, page) {
return {
q: term
};
},
results: function(data, page) {
return {results:data};
}
}
});
function productFormatResult(product) {
var html = "<table><tr>";
html += "<td>";
html += product.itemName ;
html += "</td></tr></table>";
return html;
}
function productFormatSelection(product) {
var selected = "<input type='hidden' name='itemId' value='"+product.id+"'/>";
return selected + product.itemName;
}
$(".qty, .price").bind("keyup change", calculate);
};
here are some screenshots:
1st state:
2nd state: when searching item on the input box
3rd state: after adding new row on my table
What can be the issue?
The same id value is used for the input elements as rows get added.
It is best to have unique id within the page.
I would guess that every time you call .select2(), that all the selects get reset to the original state. You could only call the constructor on the new box by limiting the scope.
To update only the new select2s you should change the following.
See this example (untested, please adjust):
var newHtml = $("<h1>Code to be appended here</h1>");
newHtml.appendTo('#tblItemList tbody');
$('.itemSearch', newHtml).select2(/* ... */)
As an alternative you could try "freezing" the state by applying the "selected" attribute to all boxes before you call the constructor.
See this example (untested, please adjust)
$('.itemSearch').each(function(){
var val = $(this).val();
$(this).find('option[value='+val+']').attr('selected', 'selected');
})

join two html block variables in javascript

I am trying to join two blocks of html code with javascript and call a dialog afterwards. I have done some research and tried concat and + but that doesnt work. Here is a simplified version of my code:
var html =
"<div class=\"dialog-form\" title=\"Edit\">" +
"<form class=\"insertaplato\" method=\"POST\" action=\"edit.php\">" +
"<fieldset>" +
"<label>Plate: </label> <input type=\"text\" value=\"" + plate + "\" >" +
"<label>Price: </label><input type=\"text\" value=\""+ price +"\" >";
"Spicy: <br> ";
if (spicy==1)
{var varP=
"<label> Yes </label><input value= \"yes\" type=\"radio\" checked>"+
"<label> No </label><input value=\"no\"><br><br>";
} else {
var varP=
"<label> Yes </label><input value=\"yes\" type=\"radio\">"+
"<label> No </label><input value=\"no\" checked type=\"radio\"><br><br>";
}
var html2 = "<br>"+
"<br><input id=\"insert\" type=\"submit\" value=\"Edit\" name=\"send\"> " +
"</fieldset>"+
"</form>"+
"</div>";
var div = $(html)+$(varP)+$(html2);
div.dialog(
{
title:"Edit Plate",
close: destroy_this_dialog
});
As it is right now the dialog doesnt come up. If I do this with only the first html variable it come up Ok but when I try to add or concatenate the others nothing happens. I am evidently not using these variables as I should. Any ideas?
Concatenate the strings and not the jQuery objects
var div = $(html + varP + html2);
div.dialog(
{
title:"Edit Plate",
close: destroy_this_dialog
});
Remove the $ where you're appending the pieces together. You want to append the strings into a single object.
var div = $(html + varP + html2);
intead of
var div = $(html)+$(varP)+$(html2);
div.dialog(
{
title:"Edit Plate",
close: destroy_this_dialog
});
try this:
var div = html+varP+html2;
$('.dialog-form').dialog(
{
title:"Edit Plate",
close: destroy_this_dialog
});

Adding a button with innerHTML property

I'm trying to add html code inside a <span id="options"></span> so I'm trying to use this:
function editTextArea(element) {
var options = document.getElementById("options");
options.innerHTML = options.innerHTML + "Cols: <input type='text' id='colsTextArea' maxlength='3' /><br>Rows: <input type='text' id='rowsTextArea' maxlength='2' /><br><button type='button' onclick='updateTextArea('" + element.id + "')' >Add</button><br>";
}
But this is what I got,
<button type="button" onclick="updateTextArea(" textarea0')'="">Agregar</button>
My problem is with the quotes, so I later tried using createElement("button"), but now I can't add the onclick attribute.
I'm not using jQuery, so it would be nice to have a solution without it.
You need to use different quotes for the function call to updateTextArea than you do for the onclick attribute. You can't do onclick='alert('hi');', because the single quote terminates the onclick attribute.
function editTextArea(element) {
var options = document.getElementById("options");
options.innerHTML = options.innerHTML + "Cols: <input type='text' id='colsTextArea' maxlength='3' /><br>Rows: <input type='text' id='rowsTextArea' maxlength='2' /><br><button type='button' onclick='updateTextArea(" + '"' + + element.id + '"' + ")' >Add</button><br>";
}
You should definately consider doing this at least with the proper DOM API calls. You are right to try document.createElement
To set an onclick, do something like this:
var button = document.createElement('button').
button.onclick = function(){
alert('I was clicked');
}
Can be done with escaping the quotes also:
options.innerHTML = options.innerHTML + "Cols: <input type='text' id='colsTextArea' maxlength='3' /><br>Rows: <input type='text' id='rowsTextArea' maxlength='2' /><br><button type='button' onclick=\"updateTextArea(\'" + id + "\')\" >Add</button><br>";
if you are going with second option you can use setAttribute() method.
var ele = document.createElement('button');
ele.setAttribute('onclick','method_name');

jquery incrementing number in html name=""

I want the variable inputname to go up by 1 every time a new <input /> is added
e.g.
<input name="1" />
<input name="2" />
<input name="3" />
---html---
<p class="add">Add</p>
<div class="added"></div>
---jQuery/javascript---
$(document).ready(function() {
$("p.add").click(function() {
var inputname = somevar;
var added = "<input type=\"text\" name=\""+inputname+"\" />";
$("div.added").append(added);
});
});
here it is on jsfiddle.net if it helps -> http://jsfiddle.net/gamepreneur/54kzw/
Set inputname like this:
var inputname = $('.added input').length + 1;
This gets the total number of added inputs and increments by one, resulting in the new name.
Change the variable scope
Use this:
// declare your variable here so it exists throughout every call, instead of being
// delcared new with every call.
var inputname = somevar;
$(document).ready(function() {
$("p.add").click(function() {
var added = "<input type=\"text\" name=\""+(inputname++)+"\" />";
$("div.added").append(added);
});
});
Alternatives:
Grab the number of inputs ($('div.added input').length) and use that for a counter.
Grab the id of the last item $('div.added input:last').prop('name')) and increment it.
You need to declare inputname in the global scope so that it lasts longer than just the duration of the click function and then you need to increment it each time you use it.
I modified your fiddle to this: http://jsfiddle.net/jfriend00/54kzw/2/
var inputname = 1;
$(document).ready(function() {
$("p.add").click(function() {
var added = "<input type='text' name='" + inputname++ + "' />";
$("div.added").append(added);
});
});
Try
$(document).ready(function() {
$("p.add").click(function() {
var inputname = $('input', $("div.added")).length + 1;
var added = "<input type=\"text\" name=\"" + inputname + "\" />";
$("div.added").append(added);
});
});
Consider adding some other selectors to choose those inputs (like a class selector)

Categories

Resources