Imagine a table (actually constructed of divs) with rows and in the final cell in each row, I have an input text and a link that look like this:
<input type="text" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
After each row (the parent div), I have a chunk of code like the following to ajaxify the link and text input:
$('#send_#Model.IncidentId').click(function () {
var msg = $('#message_#Model.IncidentId').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("#msg_#Model.IncidentId").html("Sent...");
} else {
window.location.href = json.jsonResult;
}
});
return false;
});
It works. However, there are at least 10 of these on each page. What I'm trying to do is consolidate the jquery into one function to handle all the links. Can I use jquery "this" or pass the IncidentId to the jquery function or something? It seems like "this" would not work because the input text is outside of the link? How can I do this to have one function for the entire page?
Keep in mind it's not imperative that I splash everything with the IncidentId. So, if I need to make one or more of the ids or names generic, that would be ok. It just needs to not get confused about what pair it's handling. I've seen some comments that a form might help, but 10+ forms on a page is ok? Plus, as it stands, there will never be any other input fields than what is shown above.
I appreciate your help. Thanks.
Update: So, I basically used Søren's recommended html5 data-* (data-id) attribute in my link, gave it a class name, and then moved my url down to the function as well...and then simply replaced all my #Model.IncidentIds. The one catch is that I had to use the following to register my click event:
$(document).on('click', ".ajax-link", function () {
I guess because I'm using handlebars to dynamically generate the page? I hadn't tested the original function since I moved it to my infinite scroll layout mentioned in the comments. Thanks all for replying.
Try this:
<input type="text" name="message" data-input-id="1" value="">
<a class="ajax-link" href="#" data-link-id="1">Send a Comment</a>
$('.ajax-link').click(function () {
var id = $(this).attr('data-link-id');
var msg = $('[data-link-id='+id+']').val();
if (msg != '') { $(this).attr('href', this.href + '?msg=' + msg) }
$.post(this.href, function (json) {
if (json.jsonResult === null) {
$("[data-link-id='+id+']").html("Sent...");
} else {
console.debug(json.jsonResult);
}
});
return false;
});
Make sure the link and field have the same id
First, make sure you have some useful class name's in place. E.g.,
<input type="text" class="incident-message" name="message" id="message_#Model.IncidentId" value="">
Send a Comment
That should allow you to create a nice, row-generic script like this:
$('.incident-link').click(function(e) {
e.preventDefault();
var $this = $(this),
$row = $this.closest('div'),
$msg = $row.find('.incident-message');
var msg = $msg.val();
if (msg != '') {
$this.attr('href', $this.attr('href') + '?msg=' + msg);
}
$.post($this.attr('href'), function (json) {
if (json.jsonResult === null) {
// I didn't see any markup for your #msg element, but assuming
// that you give it a useful classname, you can do something
// similar to this:
$row.find('.some-msg-className').html('Sent...');
} else {
window.location.href = json.jsonResult;
}
});
});
As far as grouping the events to a single handler, just use a class instead of id's.
$('.thisKind').click(function () {
or if the content is dynamic, use a single event for the parent with a selector in the on() method
$('#parentId').on("click", ".thisKind", function() {
As far as the this usage, you should familiarize yourself with jquery's DOM traversal using closest() to go up the tree and find() to go down
Related
I have a form with a conditional field that is only shown if the user selects a radio button for "other." If I remove the conditional on this field, my original javascript function works; however, with the conditional I can not get it to fire correctly.
The form has an event "cf.add" that fires when a conditional field is made visible, and using this jquery I get a correct response in the console:
jQuery( document ).on( 'cf.add', function(){
console.log('cf.add triggered' );
});
And if I remove the conditional so that this field is rendered when the page is rendered, I get the correct response in this field, which is to add a '$':
$("#fld_3169487_4").on("blur", handleChange);
function handleChange() {
var myValue = document.getElementById("fld_3169487_4").value;
if (myValue.indexOf("$") != 0)
{
myValue = "$" + myValue;
}
document.getElementById("fld_3169487_4").value = myValue;
}
I've tried putting this second function within the first, but no luck. I feel like I'm adding them in the incorrect order when I try to combine the two, I'm not sure what I'm doing wrong though.
I've also tried to call the function handleChange() on the 'cf.add' trigger, but that did not work for me either.
After some playing around, I figured it out:
jQuery( document ).on( 'cf.add', function(){
var otherField = $("#fld_3169487_3");
otherField.focus();
var dollarValue;
$(otherField).on("blur", function() {
dollarValue = otherField.val();
if (dollarValue.indexOf("$") != 0) {
dollarValue = "$ " + dollarValue;
}
$(otherField).val(dollarValue);
});
});
Since cf.add is an custom even that is published by your form, you can have other elements subscribe to the event:
$("#fld_3169487_4").on('cf.add', function(event){
if ($(this).val().indexOf("$") != 0)
{
$(this).val("$" + $(this).val());
}
});
Using $(this), we can target just the field the event is attached to. Additionally, data from the event publisher can be passed to the subscribers via the event argument.
I'm trying to make a HTML button trigger a function called switch_user, but every time I try clicking it, the console says switch_user is not a function.
This is the button:
<input type="button" class="btn btn-login" onclick="switch_user()" id="switch_user" value="{%trans%}Switch{%endtrans%}">
At the bottom of the page I have a script tag, with this function in it:
function switch_user(){
$("#switch-success, #switch-error").addClass("hide");
$.getJSON("/api/business/admin/swaproles?module="+$("#module").val()+"&user_from="+$("#user_from").val()+"&user_to="+$("#user_to").val(), function(data){
if(data) {
if(data["error"]){
$("#switch-error").html( "{%trans%}There was an error{%endtrans%}: " + data["error"]);
$("#switch-error").removeClass("hide");
}
else {
$("#switch-success").html("{%trans%}User was switched successfully{%endtrans%}");
$("#switch-success").removeClass("hide");
}
if(data["success"] == "ok") {
$("#elements").html("");
}
} else {
$("#switch-error").html("Critical failure - Please contact support");
$("#switch-error").removeClass("hide");
}
});
}
When I try to run the function manually from the console, it can find it just fine, but the buttons onclick refuses to recognize it. What am I doing wrong?
The issue is because the id of the element and the function name are the same. As they both exist under the window scope, there is a conflict. To fix the immediate problem either change the name of the function or the id of the element.
Better still, remove the outdated on* event attribute completely and use unobtrusive JS code to attach the event handler. As you're using jQuery already, here's how to do that:
<input type="button" class="btn btn-login" id="switch_user" value="{%trans%}Switch{%endtrans%}">
$(function() {
$('#switch_user').on('click', function() {
var $switchSuccess = $('#switch-success').addClass('hide');
var $switchError = $('#switch-error').addClass('hide');
$.getJSON("/api/business/admin/swaproles?module=" + $("#module").val() + "&user_from=" + $("#user_from").val() + "&user_to=" + $("#user_to").val(), function(data) {
if (data) {
if (data["error"]) {
$switchError.html("{%trans%}There was an error{%endtrans%}: " + data["error"]).removeClass("hide");
} else {
$switchSuccess.html("{%trans%}User was switched successfully{%endtrans%}").removeClass("hide");
}
if (data["success"] == "ok") {
$("#elements").html("");
}
} else {
$switchError.html("Critical failure - Please contact support").removeClass("hide");
}
});
})
});
Change the id . don't keep the id of element and function name same.
The JavaScript DOM bindings allow indexing by HTML id. Functions and properties share the same namespace in JavaScript. So, when an id in your HTML has the same name as one of your functions or properties, you can get logic errors that are hard to track down. While this is more of a CSS best practice issue, it’s important to remember when you can’t solve your javascript issue.
Now, If I hit the button, it clears all in the input field, and it automatically inputs "#marry" to it.
But, I don't want it to be cleared:(
What if I want to add "#marry" to the end of the strings that already exists in the input field?
How can I customize my javascript part?
Input field
<textarea class="box text_area" cols="10" id="input" name="comment[body]"></textarea>
button
<a href="#topic" id="username" value="#marry”><span class='btn'>reply</span></a>
javascript
$(document).on('click', 'a#username', function() {
$(".box#input").val($(this).attr('value'));
}
val() has a callback with the arguments index and value, you can use that to easily add something to the value.
$(".box#input").val(function(_, val) {
return this.value + 'some extra string';
});
$(document).on('click', 'a#username', function() {
var self = this;
$(".box#input").val(function(_, val) {
return val + self.value;
});
});
First of all adeneo's answer is good and you should read it. Here is an alternative solution that does not use jQuery:
I assume that both these elements are a part of a form. Let's say for instance the form has an ID of "post". We can access it using document.forms and then its fields as such:
var input = document.forms.post["comment[body]"];
Now, we can add to its value whenever the button is clicked. First select username with getElementById or querySelector and then add the event:
username.addEventListener("click", function(ev){
input.value += ev.target.value;
});
Or with jQuery (this also delegates if the element is not in the DOM yet):
$(document).on('click', 'a#username', function() {
input.value += this.value;
});
It might be desirable to append an extra space between the current text and the username.
append #marry at the end of text area. you can use bellow code its working fine.
$(document).on('click', 'a#username', function () {
var txtvalue = $(".box#input").val();
$(".box#input").val(txtvalue + $(this).attr('value'));
});
see jsfiddle link http://jsfiddle.net/F6mkh/1/
I have several jQuery click functions- each is attached to a different DOM element, and does slightly different things...
One, for example, opens and closes a dictionary, and changes the text...
$(".dictionaryFlip").click(function(){
var link = $(this);
$(".dictionaryHolder").slideToggle('fast', function() {
if ($(this).is(":visible")) {
link.text("dictionary ON");
}
else {
link.text("dictionary OFF");
}
});
});
HTML
<div class="dictionaryHolder">
<div id="dictionaryHeading">
<span class="dictionaryTitle">中 文 词 典</span>
<span class="dictionaryHeadings">Dialog</span>
<span class="dictionaryHeadings">Word Bank</span>
</div>
</div>
<p class="dictionaryFlip">toggle dictionary: off</p>
I have a separate click function for each thing I'd like to do...
Is there a way to define one click function and assign it to different DOM elements? Then maybe use if else logic to change up what's done inside the function?
Thanks!
Clarification:
I have a click function to 1) Turn on and off the dictionary, 2) Turn on and off the menu, 3) Turn on and off the minimap... etc... Just wanted to cut down on code by combining all of these into a single click function
You can of course define a single function and use it on multiple HTML elements. It's a common pattern and should be utilized if at all possible!
var onclick = function(event) {
var $elem = $(this);
alert("Clicked!");
};
$("a").click(onclick);
$(".b").click(onclick);
$("#c").click(onclick);
// jQuery can select multiple elements in one selector
$("a, .b, #c").click(onclick);
You can also store contextual information on the element using the data- custom attribute. jQuery has a nice .data function (it's simply a prefixed proxy for .attr) that allows you to easily set and retrieve keys and values on an element. Say we have a list of people, for example:
<section>
<div class="user" data-id="124124">
<h1>John Smith</h1>
<h3>Cupertino, San Franciso</h3>
</div>
</section>
Now we register a click handler on the .user class and get the id on the user:
var onclick = function(event) {
var $this = $(this), //Always good to cache your jQuery elements (if you use them more than once)
id = $this.data("id");
alert("User ID: " + id);
};
$(".user").click(onclick);
Here's a simple pattern
function a(elem){
var link = $(elem);
$(".dictionaryHolder").slideToggle('fast', function() {
if (link.is(":visible")) {
link.text("dictionary ON");
}
else {
link.text("dictionary OFF");
}
});
}
$(".dictionaryFlip").click(function(){a(this);});
$(".anotherElement").click(function(){a(this);});
Well, you could do something like:
var f = function() {
var $this = $(this);
if($this.hasClass('A')) { /* do something */ }
if($this.hasClass('B')) { /* do something else */ }
}
$('.selector').click(f);
and so inside the f function you check what was class of clicked element
and depending on that do what u wish
For better performance, you can assign only one event listener to your page. Then, use event.target to know which part was clicked and what to do.
I would put each action in a separate function, to keep code readable.
I would also recommend using a unique Id per clickable item you need.
$("body").click(function(event) {
switch(event.target.id) {
// call suitable action according to the id of clicked element
case 'dictionaryFlip':
flipDictionnary()
break;
case 'menuToggle':
toggleMenu()
break;
// other actions go here
}
});
function flipDictionnary() {
// code here
}
function toggleMenu() {
// code here
}
cf. Event Delegation with jQuery http://www.sitepoint.com/event-delegation-with-jquery/
can someone show me how to take an input value and append it to a div once the user clicks on an Add link?
This is the best I could do.
HTML:
<div id="customUtility-container"></div>
Add
jQuery:
$(function() {
var addDiv = $('#customUtility-container');
var i = $('#customUtility-container').size() + 1;
$('#addUtility').live('click', function() {
$('#customUtility').val().appendTo(addDiv);
$('<p><label for="customUtility-container"><input type="text" id="customUtility" size="20" name="customUtility_' + i +'" value="" placeholder="" /></label> Remove</p>').appendTo(addDiv);
i++;
return false;
});
$('#removeUtility').live('click', function() {
if( i > 2 ) {
$(this).parents('p').remove();
i--;
}
return false;
});
This creates another input field however; I just want to have one input box, have the user click Add, then it takes that value, puts it into the list, and clears the input box so the user can add something else again.
Use jQuery's append() function
addDiv.append($('#customUtility').val());
Here's a working fiddle.
Warning: opinion below
When creating a variable to store a jQuery object, I think it's helpful to prefix the variable with $. This way, you know that you're working with a jQuery object. It also makes it easier for those coming behind you to recognize what you're doing:
var $addDiv = $('#customUtility-container');
$addDiv.append($('#customUtility').val());
Something like:
addDiv.html(addDiv.html() + whateveryouwanttoadd)
addDiv.append($('#customUtility').val());
Change
$('#customUtility').val().appendTo(addDiv);
To
addDiv.append($('#customUtility').val());
val() method gives the value of the input element and you cannot call a jQuery method on a string which will throw an error.
Working demo - http://jsfiddle.net/t9D8R/
I ended up scrapping everything and redoing it:
$(function() {
var i = $('#customUtility-container').size() + 1;
$("#addUtility").on("click", function() {
$("#customUtility-container").append('<div id ="customUtility_' + i +' " name="customUtility_' + i +' ">'+ $("#customUtility").val() + 'Remove</div>');
});
$('#removeUtility').live('click', function() { $(this).closest('div').remove();
i--;
});
});