Passing in parameter from html element with jQuery - javascript

I'm working with jQuery for the first time and need some help. I have html that looks like the following:
<div id='comment-8' class='comment'>
<p>Blah blah</p>
<div class='tools'></div>
</div>
<div id='comment-9' class='comment'>
<p>Blah blah something else</p>
<div class='tools'></div>
</div>
I'm trying to use jQuery to add spans to the .tools divs that call variouis functions when clicked. The functions needs to receive the id (either the entire 'comment-8' or just the '8' part) of the parent comment so I can then show a form or other information about the comment.
What I have thus far is:
<script type='text/javascript'>
$(function() {
var actionSpan = $('<span>[Do Something]</span>');
actionSpan.bind('click', doSomething);
$('.tools').append(actionSpan);
});
function doSomething(commentId) { alert(commentId); }
</script>
I'm stuck on how to populate the commentId parameter for doSomething. Perhaps instead of the id, I should be passing in a reference to the span that was clicked. That would probably be fine as well, but I'm unsure of how to accomplish that.
Thanks,
Brian

Event callbacks are called with an event object as the first argument, you can't pass something else in that way. This event object has a target property that references the element it was called for, and the this variable is a reference to the element the event handler was attached to. So you could do the following:
function doSomething(event)
{
var id = $(event.target).parents(".tools").attr("id");
id = substring(id.indexOf("-")+1);
alert(id);
}
...or:
function doSomething(event)
{
var id = $(this).parents(".tools").attr("id");
id = substring(id.indexOf("-")+1);
alert(id);
}

To get from the span up to the surrounding divs, you can use <tt>parent()</tt> (if you know the exact relationship), like this: <tt>$(this).parent().attr('id')</tt>; or if the structure might be more deeply nested, you can use parents() to search up the DOM tree, like this: <tt>$(this).parents('div:eq(0)').attr('id')</tt>.
To keep my answer simple, I left off matching the class <tt>"comment"</tt> but of course you could do that if it helps narrow down the div you are searching for.

You don't have a lot of control over the arguments passed to a bound event handler.
Perhaps try something like this for your definition of doSomething():
function doSomething() {
var commentId = $(this).parent().attr('id');
alert(commentId);
}

It might be easier to loop through the comments, and add the tool thing to each. That way you can give them each their own function. I've got the function returning a function so that when it's called later, it has the correct comment ID available to it.
The other solutions (that navigate back up to find the ID of the parent) will likely be more memory efficient.
<script type='text/javascript'>
$(function() {
$('.comment').each(function(comment) {
$('.tools', comment).append(
$('<span>[Do Something]</span>')
.click(commentTool(comment.id));
);
});
});
function commentTool(commentId) {
return function() {
alert('Do cool stuff to ' + commentId);
}
}
</script>

Getting a little fancy to give you an idea of some of the things you can do:
var tool = $('<span>[Tool]</span>');
var action = function (id) {
return function () {
alert('id');
}
}
$('div.comment').each(function () {
var id = $(this).attr('id');
var child = tool.clone();
child.click(action(id));
$('.tools', this).append(child);
});

The function bind() takes, takes the element as a parameter (in your case the span), so to get the id you want from it you should do some DOM traversal like:
function doSomething(eventObject) {
var elComment = eventObject.parentNode.parentNode; //or something like that,
//didn't test it
var commentId= elComment.getAttribute('commentId')
alert(commentId);
}

Related

Passing the correct context to a function with arguments from ready function

I have spent a day trying to find the way to pass the correct context to the removeForm. The goal is to use the removeForm which is called when pressing <a class="remove_2"> remove </a> link to remove the content of the class passed to removeForm in this case "subform2". Here is what I tried:
function removeForm(tgsubf) {
var $removedForm = $(this).closest(tgsubf);
var removedIndex = parseInt($removedForm.data('index'));
$removedForm.remove();
}
$(document).ready(function() {
$('.remove_2').click(function(e){
e.preventDefault();
removeForm('.subform2')
});
}
<div class="subform2">
<a class="remove_2"> remove </a>
</div>
I know that the context depends on how I call the function but also if I call the function using removeForm('subform2') I still have this problem.
The full example is hosted here.
If you want to remove the .subform2 element that contains the .remove_2 which was clicked, you can do the following.
When your are inside an event callback you pass to jQuery, this (generally) holds the element that received the event. So you should change your code to have the following:
$('.remove_2').click(function(e){
e.preventDefault();
removeForm(this) // <-- 'this' will refer to $('.remove_2')
});
Then you can change your removeForm() to get the immediate ancestor of the element passed to it (which would be .remove_2) that has .subform2 for class and remove it, like this:
function removeForm(anchor) {
var $removedForm = $(anchor).closest('.subform2');
$removedForm.remove();
}
UPDATE
You should be able to pass a selector to removeForm to identify the ancestor, like this:
function removeForm(el, ancestorSelector) {
// Do check to ensure ancestorSelector is provided, before using it.
var $removedForm = $(el).closest(ancestorSelector);
$removedForm.remove();
}
You can update how you call it like this:
$('.remove_2').click(function(e){
e.preventDefault();
removeForm(this, '.subform2') // <-- 'this' will refer to $('.remove_2')
});

How to use THIS in child function which is outside of a parent JS

I have an onclick function
$('.modal-trigger').on('click', function() {
$('#'+$(this).data('modal')).show();
calc();
})
<a class="modal-trigger" data-modal="ft-modal">Link</a>
<div id="ft-modal"></div>
I want to add calc() function inside
function calc() {
var tt = document.getElementById('#'+this.getAttribute('data-modal')).document.getElementsByClassName("name-line")[0];
}
The second function is outside (above) the onclick one, and my problem is that I can't figure it out how to perform a search inside the <div> by class name and get the first one that matches the class on plain JS.
And I think that I don't know how to use this properly for this particular case.
You can pass this to the calc function with .call:
calc.call(this);
The calc function needs no change then.
You have to pass this object to the function so that you can refer that inside the function. You can simplify your code by using jQuery:
$('.modal-trigger').on('click', function() {
$('#'+$(this).data('modal')).show();
calc(this); // pass this here
})
function calc(el) {
var tt = $('#'+$(el).data('modal')).find('.name-line')[0];
console.log(tt);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a class="modal-trigger" data-modal="ft-modal">Link</a>
<div id="ft-modal">
<span class="name-line"></span>
</div>
as suggested in the comments...
$('.modal-trigger').on('click', function() {
...
calc(this);
});
function calc(ele) {
...
}
using document.getElementById in a jQuery script is questionable;
better use $(ele).data('modal') to obtain the data attribute.
of couse both ways would work, nevertheless the readability would be improved
... that's why it is called "write less, do more".

Why my jQuery extension's function act "static"?

I made a custom jQuery extension to handle files for upload.
My stripped version: http://jsfiddle.net/6huV6/
My full version: http://jsfiddle.net/LQrJm/
My problem is that buildBondye is called 2 times, but my extension is added 2 x 2 droppers and buttons..
How do I fix this?
You get four because for each element in your set of matched elements you're calling the buildBondye function, which in turn calls the addButton and addDropper functions. Those functions use $this, which is the entire set of matched elements (so both of them), not only the element for that iteration of .each().
You can fix this by passing a reference to a single element to those two functions, and using that instead:
var buildBondye = function () {
// inside buildBondye this refers to the specific element for the iteration of .each()
// different to the this inside the $.fn.bondye function
addButton(this);
addDropper(this);
}
var addDropper = function (element) {
$dropper = $('<input type="text" readonly />');
$dropper.val('drop here');
$(element).after($dropper);
}
var addButton = function (element) {
$button = $('<input type="button" />');
$button.val('browse');
$button.bind('click', function () {
$(element).trigger('click');
});
$(element).after($button);
}
Take a look at this updated jsFiddle.

edit in place with jQuery selecting newly inserted elements

I am trying to write my own edit-in-place using jQuery. My code is something like this;
$(".comment-edit").bind({
click: function(){
commentId = $(this).parent().parent().attr("id");
commentEditable = $("#"+commentId+" .comment-text");
if (commentEditable.hasClass('active-inline')) {
alert("already editable aq");
return false;
}
contents = $.trim($("#"+commentId+" .comment-text").text());
commentEditable.addClass("active-inline").empty();
var editBox = '<textarea id="newComment"cols="50" rows="6"></textarea><button class="newCommentSave">Save</button><button class="newCommentCancel">Cansel</button>';
$(editBox+" textarea").val(contents).appendTo(commentEditable).focus();
$.(".newCommentSave").live({
click: function(){
alert("Save");
return false;
}
});
$.(".newCommentCancel").click(function(){
alert("Cancel");
return false;
});
return false;
}
});
As you can see I tried both "live()" and "click()" for interacting with the newly created buttons. However this doesn't work.
I am getting XML filter is applied to non-XML value (function (a, b) {return new (c.fn.init)(a, b);})
Any ideas? What seems to be going wrong?
Edit:
Html looks something like this:
<div class="comment" id="comment-48">
<div class="comment-author">
defiant
<span class="date">2010-11-09 01:51:09</span>
</div>
<div class="comment-text">Comment Text....</div>
</div>
The problem is here:
var editBox = '<textarea id="newComment"cols="50" rows="6"></textarea><button class="newCommentSave">Save</button><button class="newCommentCancel">Cancel</button>';
$(editBox+" textarea").val(contents).appendTo(commentEditable).focus();
editBox is a string, so you're getting this as a result:
$("<textarea/><button /> textarea")
...which isn't XML or a valid selector, throwing an error. Instead you want this:
$(editBox).filter("textarea").val(contents)
.end().appendTo(commentEditable).focus();
This gets the <textarea> from that object you just created via .filter() (since it's a root level element), sets the contents, then uses .end() to hop back in the chain to $(editBox) which contains both elements to append. This would focus the button though, so you may want this instead:
$(editBox).appendTo(commentEditable).filter("textarea").val(contents).focus();
As it turns out, the reason for XML error was a "."
$.(".newCommentSave").live({
// stuff
})
The dot after the dollar sign is what causing this error. At least the code was working fine without it.
I tend to do something like this to attach a click event (to a span in my example)
var span = $("<span>some text</span>");
span.click( function() { alert('yay'); });
I'd break down your editBox variable into three different variables and see what happens then.
The .live() syntax is .live('event', function), I don't think it accepts a map of event:function pairs.
So would something like this work?
$.(".newCommentSave").live('click', function(){
alert("Save");
return false;
});
I'm not sure why your .click() handler didn't work though.

Is there an easier way to reference the source element for an event?

I'm new to the whole JavaScript and jQuery coding but I'm currently doing this is my HTML:
<a id="tog_table0"
href="javascript:toggle_table('#tog_table0', '#hideable_table0');">show</a>
And then I have some slightly ponderous code to tweak the element:
function toggle_table(button_id, table_id) {
// Find the elements we need
var table = $(table_id);
var button = $(button_id);
// Toggle the table
table.slideToggle("slow", function () {
if ($(this).is(":hidden"))
{
button.text("show");
} else {
button.text("hide");
}
});
}
I'm mainly wondering if there is a neater way to reference the source element rather than having to pass two IDs down to my function?
Use 'this' inside the event. Typically in jQuery this refers to the element that invoked the handler.
Also try and avoid inline script event handlers in tags. it is better to hook those events up in document ready.
NB The code below assumes the element invoking the handler (the link) is inside the table so it can traverse to it using closest. This may not be the case and you may need to use one of the other traversing options depending on your markup.
$(function(){
$('#tog_table0').click( toggle_table )
});
function toggle_table() {
//this refers to the element clicked
var $el = $(this);
// get the table - assuming the element is inside the table
var $table = $el.closest('table');
// Toggle the table
$table.slideToggle("slow", function () {
$el.is(":hidden") ? $el.text("show") : $el.text("hide");
}
}
You can do this:
show
and change your javascript to this:
$('a.tableHider').click(function() {
var table = $(this.name); // this refers to the link which was clicked
var button = $(this);
table.slideToggle("slow", function() {
if ($(this).is(':hidden')) { // this refers to the element being animated
button.html('show');
}
else {
button.html('hide');
}
});
return false;
});
edit: changed script to use the name attribute and added a return false to the click handler.
I'm sure this doesn't answer your question, but there's a nifty plugin for expanding table rows, might be useful to check it out:
http://www.jankoatwarpspeed.com/post/2009/07/20/Expand-table-rows-with-jQuery-jExpand-plugin.aspx

Categories

Resources