Passing parameters to Anonymous function inside click event - javascript

var div_raw_id = 'acf-download-link';
var div_id = '#' + div_raw_id;
var chapter_index = 1;
var chapter = 'chapter-' + chapter_index;
$('button[name=addnewchapter]').click(function(chapter, div_id ,div_raw_id){
$(div_id).append('<div class="acf-input-wrap"><input id="' + div_raw_id +'" class="text" name="fields[field_55951fb44c1d6][' + chapter + '][]" value="" placeholder="" type="text"><span class="remove_btn"></span></div>');
return false;
});
The problem is I cannot pass div_id, chapter_index, chapter as a parameter to the anonymous function inside the click event. I used the debugger and the debugger represents them as undefined values even though they are defined in above code. It seems there is a variable scope problem, however, I cannot figure out any other way to pass the defined variables as a parameter to the anonymous function inside the click event.

You don't need to pass the variables defined at the beginning as parameters, simply use it inside the function:
var div_raw_id = 'acf-download-link';
var div_id = '#' + div_raw_id;
var chapter_index = 1;
var chapter = 'chapter-' + chapter_index;
$('button[name=addnewchapter]').click(function(){
$(div_id).append('<div class="acf-input-wrap"><input id="' + div_raw_id +'" class="text" name="fields[field_55951fb44c1d6][' + chapter + '][]" value="" placeholder="" type="text"><span class="remove_btn"></span></div>');
return false;
});

You can pass anything (no string as it would be used as selector, preferable an object) you want to your event handler.
See the documentation of .on( events [, selector ] [, data ], handler ) for further infos on the data parameter
var eventData = {
"div_id": "acf-download-link"
,"chapter": 1
};
$('button[name=addnewchapter]').on("click", eventData, function(e){
$("#" + e.data.div_id)
.append('<div class="acf-input-wrap"><input id="' + e.data.div_id + '"'
+ ' class="text" name="fields[field_55951fb44c1d6][chapter-' + e.data.chapter + '][]"'
+ ' value="" placeholder="" type="text"><span class="remove_btn"></span></div>');
return false;
});

Thanks to JS Closures Your click handler is defined at the same level as the variables div_raw_id, div_id, div_raw_id, chapter_index, chapter.
This means that if you give the callback function arguments with the same name the callback function can no longer see the external ones with the same name.
So chapter_index Should still be defined. The first argument chapter will be the first parameter that jQuery passes through (The Event Object) the last 2 will be set to undefined.

Related

How can I get a time value from HTML using JavaScript?

I'm trying to get the value of a time input element via JavaScript. When I try using getElementById the value that is displayed is:
[object HTMLInputElement]
If use querySelectorAll, the value is:
[NodeList]
I also tried to use the index, but nothing new happens.
Here is my HTML:
<div class="principal-grid">
<title>Hour Control</title>
<label class="description-values">In</label>
<input id="data-in" type="time" class="values">
<label class="description-values">Interval - Saída</label>
<input id="data-interval-s" type="time" class="values">
<label class="description-values">Interval - Volta</label>
<input id="data-interval-v" type="time" class="values">
<label class="description-values">Out</label>
<input id="data-out" type="time" class="values">
<input id="submit" type="submit" class="send" value="Send">
</div>
And this is the script:
var dataIn = document.getElementById(['data-in']);
var dataInterval_out = document.getElementById(['data-interval-s']);
var dataInterval_in = document.getElementById(['data-interval-v']);
var dataOut = document.getElementById(['data-out']);
document.getElementById("submit").onclick = function (e) {
//test
document.getElementById("test").innerHTML = dataIn + ' ' + dataInterval_out +
' ' + dataInterval_in + ' ' + dataOut;
}
A couple of things to note here:
First up, when you use: var dataIn = document.getElementById(...)
It's returning a reference to the html element identified by the Id string and storing it in the dataIn variable you created. If you want the value of that element, you need to use: dataIn.value.
Here's an updated version of your script that does what I think you want:
var dataIn = document.getElementById('data-in');
var dataInterval_out = document.getElementById('data-interval-s');
var dataInterval_in = document.getElementById('data-interval-v');
var dataOut = document.getElementById('data-out');
document.getElementById("submit").onclick = function (e) {
//test
document.getElementById("test").innerHTML = dataIn.value + ' ' + dataInterval_out.value +
' ' + dataInterval_in.value + ' ' + dataOut.value;
}
The second thing is that getElementById takes a string value. You're wrapping it in []'s, which is unnecessary.
One last note: type="time" is not supported on all browsers. (Safari doesn't support it for example). So you may want to look for an alternative method for collecting dates, if supporting macOS and iOS devices is important to you.
To get value of input using vanilla js, use .value property.
var dataIn = document.getElementById('data-in').value;
var dataInterval_out = document.getElementById('data-interval-s').value;
var dataInterval_in = document.getElementById('data-interval-v').value;
var dataOut = document.getElementById('data-out').value;
Also, getting element by id, use document.getElementById('elementId')

Is there a simpler way to do this script?

I'm learning and trying to put together a little bit of jquery. Admittedly I'm finding it difficult to find a good basics guide, particularly, when adding multiple actions to one page.
I read somewhere that the document listener should only be used once. I believe I'm using it twice here, but not 100% sure how to bring it into one listener.
Also because I've been hacking bits of script together, I think I'm using parts of javascript and parts of jQuery. Is this correct?
A critique of the code below [which does work] and any advice on how best to approach learning jQuery would be most helpful. Thanks.
Script 1 styles a group of 3 radio buttons depending on which one is clicked.
Script 2 appends new inputs to the bottom of a form.
var stateNo = <?php echo $HighestPlayerID; ?> + 1;
$(document).on('click', 'input', function () {
var name = $(this).attr("name");
if ($('input[name="' + name + '"]:eq(1)')[0].checked) {
$('label[name="' + name + '"]:eq(1)').addClass('nostate');
$('label[name="' + name + '"]').removeClass('selected');
}
else {
$('label[name="' + name + '"]').removeClass('nostate selected');
if ($('input[name="' + name + '"]:eq(0)')[0].checked) {
$('label[name="' + name + '"]:eq(0)').addClass('selected');
}
else {
$('label[name="' + name + '"]:eq(2)').addClass('selected');
}
}
});
$(document).on('click', 'button[name=btnbtn]', function () {
var stateName = 'state[' + stateNo + ']';
var newPlayerAppend = `` +
`<tr><td>` +
`<input type="hidden" name="state['` + stateNo + `'][PlayerID]" value="` + stateNo + `" /></td>` +
`<td><input name="` + stateName + `[Name]" value="Name"></td>` +
`<td><input name="` + stateName + `[Team]" type="radio" value="A">` +
`<td><input name="` + stateName + `[Team]" type="radio" value="">` +
`<td><input name="` + stateName + `[Team]" type="radio" value="B">` +
`</td></tr>`;
$("tbody").append(newPlayerAppend);
stateNo++;
});
HTML for the 3 radio button inputs
<td class="Choice">
<label name="state[1][Team]" class="teampick Astate ">A
<input name="state[1][Team]" type="radio" value="A" />
</label>
<label name="state[1][Team]" class="smallx nostate ">X
<input name="state[1][Team]" type="radio" value="" checked />
</label>
<label name="state[1][Team]" class="teampick Bstate">B
<input name="state[1][Team]" type="radio" value="B" />
</label>
</td>
Some of the code can be written more concisely, or more the jQuery way, but first I want to highlight an issue with your current solution:
The following would generate invalid HTML, if it were not that browsers try to solve the inconsistency:
$("tbody").append(newPlayerAppend);
A tbody element cannot have input elements as direct children. If you really want the added content to be part of the table, you need to add a row and a cell, and put the new input elements in there.
Here is the code I would suggest, that does approximately the same as your code:
$(document).on('click', 'input', function () {
$('label[name="' + $(this).attr('name') + '"]')
.removeClass('nostate selected')
.has(':checked')
.addClass(function () {
return $(this).is('.smallx') ? 'nostate' : 'selected';
});
});
$(document).on('click', 'button[name=btnbtn]', function () {
$('tbody').append($('<tr>').append($('<td>').append(
$('<input>').attr({name: `state[${stateNo}][PlayerID]`, value: stateNo, type: 'hidden'}),
$('<input>').attr({name: `state[${stateNo}][Name]`, value: 'Name'}),
$('<input>').attr({name: `state[${stateNo}][Team]`, value: 'A', type: 'radio'})
)));
stateNo++;
});
There is no issue in having two handlers. They deal with different target elements, and even if they would deal with the same elements, it would still not be a real problem: the DOM is designed to deal with multiple event handlers.
There are 2 places you are using anonymous functions. If the code block moves to a named function, the entire code becomes more maintainable. It also helps better in debugging by telling you upfront which function name the error may lie in.
Once you have named functions you will realise that you really do have 2 event listeners for click. So there isn't much benefit of moving them in one listener (or one function you may be referring to). These both event listeners attach on document object and listen to a click event.
Class names are always better when hyphenated. a-state over Astate.
If it works it is correct code, for once you asked about correctness.
It is absolutely fine to have multiple listeners but I usually prefer making everything under one roof. Consider making code as simple as possible which saves lot of time during maintenance.
you can use $(function() {}) or document.ready().
$(document).ready(function() {
$('input[type="radio"]').click(function() {
var thisa = $(this).parent();
var name = $(this).attr("name");
// Remove :selected class from the previous selected labels.
$('label[name="' + name + '"]').removeClass('selected');
// Add conditional class with tenary operator.
thisa.parent().hasClass("smallx") ? thisa.addClass('nostate') : thisa.addClass('selected');
});
$('button[name=btnbtn]').click(function() {
var stateName = 'state[' + stateNo + ']';
// Add TR and TD before appending the row to tbody
var newPlayerAppend = `<tr><td>` +
`<input type="hidden" name="state['` + stateNo + `'][PlayerID]" value="` + stateNo + `" />` +
`<input name="` + stateName + `[Name]" value="Name">` +
`<input name="` + stateName + `[Team]" type="radio" value="A"></td></tr>`;
$("tbody").append(newPlayerAppend);
stateNo++;
});
});
Hope this helps.

Change attributes dynamically using jquery

I am running a loop which is appending input fields. Now, as I am using a loop, all the attributes are similars. So, when I need to grab any one of the then I am grabbing more than one field.
How do I dynamically change the attributes according to the index, so that I can grab the correct input field ?
ebs_no = data.number_ebs;
for(i=0;i<ebs_no;i++){
$('form.ebs').append("<br>EBS"+(i+1)+"</br>");
$('form.ebs').append('<br> SNAPSHOTNO <input type="text" name="'+i+'"></br>');
$('form.ebs').append('<input type="submit" name="submit">');
$('[name='+i+']').on('submit',function(){
alert($('[name='+i+']').val());
});
}
Replace this:
alert($('[name='+i+']').val());
by this:
alert($(this).val());
The code $(this) refers to the element being treated
Your are looking for event delegation.It is used for created Dynamically DOM elements and use class instead of iterare i in the loop
ebs_no = data.number_ebs;
for (i = 0; i < ebs_no; i++) {
$('form.ebs').append("<br>EBS" + (i + 1) + "</br>");
$('form.ebs').append('<br> SNAPSHOTNO <input type="text" class="someClass" name="' + i + '"></br>');
$('form.ebs').append('<input type="submit" name="submit">');
$('[name=' + i + ']').on('submit', function () {
alert($('[name=' + i + ']').val());
});
}
$(document).on('submit', '.someClass', function () {
alert($(this).val());
});

Dynamic variable creation using eval JavaScript

I need something like an associative array that contains pairings of variable name / element ID.
Looping through this array/object, assign the element ID to the variable name that is its counterpart. Something like this:
jsFiddle
HTML:
<input id="fld_1" class="input" type="text" value="bob" /><br>
<input id="fld_2" class="input" type="text" value="fred" /><br>
<input id="fld_3" class="input" type="text" value="pat" /><br>
<input id="mybutt" class="btn" type="button" value="Test" />
JS:
objFields = {'f1':'fld_1', 'f2':'fld_2', 'f3':'fld_3'};
arrErrors = [];
$('#mybutt').click(function(){
alert('iii');
for (var key in objFields){
// eval(key = objFields[key]);
eval(key) = objFields[key];
alert('f1: ' +f1);
}
});
There is no requirement to using eval, I just need to turn the key into the variable name.
Where have I gone wrong?
Solution
JCOC611 got it right, but I wasn't clear in how I asked the question. As demo'd in this revised fiddle which implements JCOC611's solution, the variable/field names had to be used to get the value of the field contents, like this:
$('#mybutt').click(function(){
for (var key in objFields){
var tmp = objFields[key];
eval('var ' + key+ ' = $("#' +tmp+ '").val()');
}
});
If you know what you are doing and are absolutely sure about it, then use this:
eval(key + " = " + JSON.stringify(objFields[key]));
Or, if you want local variables:
eval("var " + key + " = " + JSON.stringify(objFields[key]));
Otherwise, I advice you implement one of the other answers.
You don't need that eval() at all, and you want to avoid it. All you really need to do is:
for (var key in objFields){
alert(key+': '+objFields[key]);
window[key] = objFields[key];
}
Will give you:
'f1':'fld_1'
'f2':'fld_2'
'f3':'fld_3'
Where:
f1 = 'fld_1';
f2 = 'fld_2';
f3 = 'fld_3';
If it is a global variable, it is as simple as:
window[key] = objFields[key];
or
window.key = objFields[key];
The second one is a bit less weird name immune.
The eval function runs a string add code and returns the result.
What your code did was evaluate the vague of key which is undefined and then tried to set it to a new value.
Is like writing 5=4;
Correct syntax:
eval('var ' + key + ' = ' + objFields[key]);

jQuery .each() index value

I’ve been teaching my self JavaScript and jQuery for a few months, but I’m still getting confused with JavaScript objects and jQuery objects.
In the following example I assigned a jQuery object to the variable $target. The $target should consist of an array of two objects.
My question is why I have to wrap the value variable again into the jQuery object in .each() function ?
$('select.to_append').change(function(){
var $target = $('select.to_append');
var $form = $('#anotherForm');
$.each($target, function(key, value){
$form.append('<input name="' + $(value).attr('name') + '" type="hidden" value="' + $(value).val() + '"></input>');
});
});
The sample code I use to append values from selects which are not parts of the form being submitted;
because $target is a jQuery object, but when you iterate you will get a dom element reference in your iteration handler not a jQuery object. So if you want to access jQuery methods on that object you need to wrap the object again.
By the way to iterate over a jQuery object you can use .each() instead of jQuery.each()
$('select.to_append').change(function () {
var $target = $('select.to_append');
var $form = $('#anotherForm');
$target.each(function (index, el) {
$form.append('<input name="' + $(el).attr('name') + '" type="hidden" value="' + $(el).val() + '"></input>');
});
});

Categories