I have a form where i've replaced the submit button with an input (with type=button) with an onclick which calls an existing function:
<form accept-charset="UTF-8" action="/admin/message_campaigns" class="new_message_campaign" id="new_message_campaign" method="post">
<!-- some fields -->
<input onclick="confirmSubmit();" type="button" value="Send" />
</form>
In the confirmSubmit, i'd like to be able to dynamically get the form object (to submit it), instead of having to hardcode the form's id, or pass it as part of the call to confirmSubmit(). I'd have thought that i could do this by first getting the dom element that was clicked on, ie something like this:
var form = $(this).parents("form");
where $(this) is the object that called the function, ie the input with the onclick. This doesn't work though. I think it would work if i'd set it up with the .click(function(){ syntax. Can i get the element that called the function in a different way?
EDIT - got the answer from #claudio below, for clarity here's the complete function and call:
<form accept-charset="UTF-8" action="/admin/message_campaigns" class="new_message_campaign" id="new_message_campaign" method="post">
<!-- some fields -->
<input onclick="confirmSubmit($(this));" type="button" value="Send" />
</form>
and the function itself. Note that 'jConfirm' is a method of the jquery-alerts plugin (http://abeautifulsite.net/blog/2008/12/jquery-alert-dialogs/) but that's not really relevant to this question - the key thing was just to get the form object, not what's subsequently done with it:
function confirmSubmit(caller) {
var form = caller.parents("form");
jConfirm('Are you sure?', 'Please Confirm', function(result){
if (result) {
form.submit();
} else {
return false;
}
});
}
You can pass the inline handler the this keyword, obtaining the element which fired the event.
like,
onclick="confirmSubmit(this);"
If you don't want to pass the clicked on element to the function through a parameter, then you need to access the event object that is happening, and get the target from that object. This is most easily done if you bind the click event like this:
$('#sendButton').click(function(e){
var SendButton = $(e.target);
var TheForm = SendButton.parents('form');
TheForm.submit();
return false;
});
Try this
<input onclick="confirmSubmit(event);" type="button" value="Send" />
Along with this
function confirmSubmit(event){
var domElement =$(event.target);
console.log(domElement.attr('type'));
}
I tried it in firefox, it prints the 'type' attribute of dom Element clicked. I guess you can then get the form via the parents() methods using this object.
It's top google stackoverflow question, but all answers are not jQuery related!
$(".someclass").click(
function(event)
{
console.log(event, this);
}
);
'event' contains 2 important values:
event.currentTarget - element to which event is triggered ('.someclass' element)
event.target - element clicked (in case when inside '.someclass' [div] are other elements and you clicked on of them)
this - is set to triggered element ('.someclass'), but it's JavaScript element, not jQuery element, so if you want to use some jQuery function on it, you must first change it to jQuery element: $(this)
When your refresh the page and reload the scripts again; this method not work. You have to use jquery "unbind" method.
First Way: Send trigger element using this
<button id="btn01" onClick="myFun(this)">B1</button>
<button id="btn02" onClick="myFun(this)">B2</button>
<button id="btn03" onClick="myFun(this)">B3</button>
<script>
function myFun(trigger_element)
{
// Get your element:
var clicked_element = trigger_element
alert(clicked_element.id + "Was clicked!!!");
}
</script>
This way send an object of type: HTMLElement and you get the element itself. you don't need to care if the element has an id or any other property. And it works by itself just fine.
Second Way: Send trigger element id using this.id
<button id="btn01" onClick="myFun(this.id)">B1</button>
<button id="btn02" onClick="myFun(this.id)">B2</button>
<button id="btn03" onClick="myFun(this.id)">B3</button>
<script>
function myFun(clicked_id)
{
// Get your element:
var clicked_element = document.getElementById(clicked_id)
alert(clicked_id + "Was clicked!!!");
}
</script>
This way send an object of type: String and you DO NOT get the element itself. So before use, you need to make sure that your element already has an id.
You mustn't send the element id by yourself such as onClick="myFun(btn02)". it's not CLEAN CODE and it makes your code lose functionality.
Related
I have a multistep form, with 4 frameset. Each one must come in when I press the "Next" button (of course)
My ES6 modular code cointains something like this:
class FormController {
// 1. describe and initiate object
constructor() {
this.nextBtn = $(".next");
this.next_fs;
....
this.events();
}
// EVENTS LISTENER
events(){
this.nextBtn.on("click", this.nextClicked.bind(this));
// other listeners
}
nextClicked() {
this.next_fs = $(this)
.parent()
.next(); // this is the next fieldset
// some actions...
}
// rest of the code
}
My problem is the following:
I need to bind "this" inside nextClicked function to be able tu use all variables and methods like this.next_fs, this.saveData(), etc...
But I also need to know which button has been clicked, and I cannot know that because this is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target.
What's the matter with my code? I know that's something stupid that I'm not seeing.
Thanks!
But I also need to know which button has been clicked, and I cannot know that because "this" is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target
The browser's event triggering code passes that. You just need to read it.
nextClicked(e) {
"...and I cannot pass a variable (let's call it 'e') to trace the e.target"
Actually, you don't need to pass it as variable, because even if you don't pass the e you can get it in nextClicked because browsers do it by default, so it will come as parameter if you declare the function as nextClicked(e){...} and keep the bind as you have.
Or, you can pass parameters after this, such as ...bind(this, this.nextBtn), then the first parameter on nextCliked will be the button.
See below these two possibilities I mentioned:
$(".buttons").on("click", this.nextClicked.bind(this))
function nextClicked(e){
//here your context is the same as when you binded the function, but you have the event
let target = e.target;
console.log(target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">click me 1</button>
<button id="btn-2" class="buttons">click me 2</button>
let nextButton = $("#btn-1")[0];
$(".buttons").on("click", this.nextClicked.bind(this, nextButton))
function nextClicked(nextBtn, e) {
//here your context is the same as when you binded the function,
//but you have the button AND the event
console.log("NextButton Id: " + nextBtn.id);
console.log("Clicked button Id: " + e.target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">next</button>
<button id="btn-2" class="buttons">previous</button>
You are doing
this.next_fs = $(this)
But, earlier you set this to an instance of FormController
this.nextBtn.on("click", this.nextClicked.bind(this));
so what you are doing is
this.next_fs = $( (FormController)this);
You are expecting jQuery to work with a class instance, instead of the event object.
I strongly discourage you from using $(this) ever in a event handling context. this can change it's meaning as you have shown in your sample by the code breaking.
Always use event.target or event.currentTarget. I prefer currentTarget as it points to the element on which the event was bound, and not a deeper lying element within that element.
so your code should be
nextClicked(e) {
this.next_fs = $(e.currentTarget)
.parent()
.next(); // this is the next fieldset
// some actions...
}
I'm trying to create a simple form where i can add more text field after current text field.
And also i can add more field from the new field that ive added before (im using Recursion for this).
Problems come when i click the add on the first field, it creates more then 1 new fields (this happens because of recursion)
how do i refresh javascripts function without calling it again and again?
HTML :
<div class="line-input">
<input type='text' class='ipt-txt'>
<input type='submit' class='btn-smt' value="add new">
</div>
JS :
$(document).ready(function(){
callFunction();
});
function callFunction(){
$(".btn-smt").click(function(e){
$(this).parent(".line-input").clone().insertAfter($(this).parent(".line-input"));
callFunction();
});
};
JSFiddle : https://jsfiddle.net/1uofya3k/
Thanks!
Use event delegation:
$(function() {
$(document).on("click", ".btn-smt", function(e) {
$(this).parent(".line-input").clone().insertAfter($(this).parent(".line-input"));
});
});
That sets up an event handler at the document level that responds to clicks on your button class. You only have to add it once, and it'll work for all subsequent elements that are added dynamically.
(You don't really even have to do it in a "ready" handler; you can set it up before the DOM has been completed.)
Add true to the clone() function. From the jQuery API:
withDataAndEvents (default: false) Type: Boolean A Boolean indicating
whether event handlers should be copied along with the elements. As of
jQuery 1.4, element data will be copied as well.
https://api.jquery.com/clone/
$(document).ready(function() {
callFunction();
});
function callFunction() {
$(".btn-smt").click(function(e) {
e.stopPropagation();
$(this).parent(".line-input").clone(true).insertAfter($(this).parent(".line-input"));
});
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="line-input">
<input type='text' class='ipt-txt'>
<input type='submit' class='btn-smt' value="add new">
</div>
When I change the id of a button I cannot find the new id with on.("click"). The function console.log() does detect that it's changed but I cannot detect it with the on() function.
HTML:
<form id="formName" action="" method="post">
<input type="submit" id="submitBtn" value="Submit" />
</form>
<button id="change">Change</button>
JS:
$("#change").on("click", function(){
$("#submitBtn").attr("id", "NewBtn");
});
$("#formName").submit(function(e){
e.preventDefault();
});
$("#NewBtn").on("click", function(){
alert("Hello");
});
So I need it to alert "Hello" after I have clicked on change. It does change the id I checked that with inspect element.
Fiddle: http://jsfiddle.net/WvbXX/
Change
$("#NewBtn").on("click", function(){
to
$(document).on("click", "#NewBtn", function(){
The reason for this is that you're wanting to use the delegate form of .on(). This call is a little different in that it takes a "string" as the second parameter. That string is the selector for your "dynamic" element while the main selector need either be a parent container (not created dynamically) or the document itself.
jsFiddle
you are setting onclick event for newBtn on load of page for the first time but unfortunately newBtn not available that time. hence after changing the id it will not trigger onclick function for newBtn.
you can do one thing to make it work, set onclick event for newBtn inside the same function where you are changing the id like below.
$("#change").on("click", function(){
$("#submitBtn").attr("id", "NewBtn");
// set on click event for new button
$("#NewBtn").on("click", function(){
alert("Hello");
});
});
.attr() function does not have a callback and thus it cannot be checked unless you setup an interval using setInterval but the function itself executes pretty soon so you are not going to need it.
For solving the problem in hand event delegation proposed by tymeJV is the right way to do it.
I want to clear an input field when it's clicked, but only the first time you click. With jQuery, you can achieve it like this: putting the following snippet anywhere in the document (assuming the element with id=inputf has already been loaded):
$('#inputf').one("click", function() {
$(this).val("");
});
As you can see in the above snippet, the input field must have id attribute with value inputf.
But is there a way to move that snippet to the onclick attribute of the input field, like
<input type="text" onclick="$(this)....val('')" />
? It looks like I can't use the function .one(), because that function needs a string containing one or more JavaScript event types. But I just want .one() to be executed each time it is called, without specifying one or more event types.
Only posting this since you requested, I don't advocate inline handlers.
<input type="text" onclick="this.onclick = null; this.value = ''; " />
http://jsfiddle.net/aUmNK/
<input type="text" onclick="if(flagCount === 0){this.value='';flagCount++;}" />
declare the var flagCount = 0 as global variable in the script tag in head.
If you wanted to do it for all text input fields, you could do:
$("input[type=text]").each(function(){
$(this).one("click", function() {$(this).val = "";});
});
...or you can refine the selector to get every input field in a particular div for example:
$("#divId input[type=text]")
You don't need jQuery to do a event like one on the element tag. Just do something like this:
<input onclick="function(event) { /* do something */ this.onclick = function(){}; }" />
Your function will be executed only the first time, then a new void function will be attached to the onclick event callback.
You can just write your own simple jQuery plugin:
(function( $ ) {
$.fn.clearOnce = function() {
this.one("click", function() {
$(this).val("");
});
};
})( jQuery );
After this you can:
<input type="text" onclick="$(this).clearOnce();" />
Wrote in 3 min, not tested ;-)
I have a comment system where a user submits a comment, the comment is processed, then the HTML for the comment is returned. jquery then adds that retrieved HTML to the comment system. that whole system works, but the comment buttons that requir javascript do not work unless I refresh the page. How do make my javascript work on elements added through load, prepend, or append?
Not sure if my question is clear, but here's the javascript I have:
$(function () {
$(".replyform").submit( function (event) {
event.preventDefault();
id = $(this).attr("id").split('_')[1];
text = $('textarea#text_'+id).val();
$.post( "/api/add/comment/", {_csrf: _csrf, id: id, text: text, a: a},
function (data) {
$('#commentreplies_'+id).prepend(data);
$('#replyform_' + id).hide();
});
});
});
I then have elements such as "reply" for each comment that have functions in an external javascript that do not work unless I refresh the page. Hopefully that made sense.
Use jQuery live() (it is deprecated, see on()) function
jQuery has a live method to allow elements that are added on the page after loading to be able to have events already bound by jQuery. You can bind your events using live method as described here.
A second solution, and probably a more efficient one, would be using delegate method to handle events by existing containers and delegating them to the elements inside that container. You can read more about delegate here.
An example solution using live method is as follows assuming you have buttons with class 'reply' in your response data:
$(".reply").live('click', function(event) {
event.preventDefault();
id = $(this).attr("id").split('_')[1];
text = $('textarea#text_'+id).val();
// post won't work since url is missing, but that code remains the same.
// Assuming you get a response like this
// <div><input type="textarea" id="text2" /><input type="submit" id="reply_2" value="submitReply" class="reply" /></div>
// And if you append this to your document
var data = $('<div></div>').html('<input type="textarea" id="text2" /><input type="submit" id="reply_2" value="submitReply" class="reply" />');
$('#commentreplies_'+id).prepend();
$('#reply_' + id).hide();
});
There are few different approaches to this
1) Explicitly init the button inside returned HTML on AJAX success
2) Setup global handler for your button type using jQuery live() function (replaced by on() in 1.7)
3) define button handler right in the markup
Which one do you pick is really up to your specific task.