edit in place with jQuery selecting newly inserted elements - javascript

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.

Related

Capturing the anchor tag

I've written a JavaScript code which over-ride the native alert() method.
I need to capture the HTML element which comprises the code of alert() execution.
First two cases are examples. I have printed the elements in console.log.
Case 1 - Capturing the <script> tag:
HTML: <script> alert(1); </script>
JS:
window.alert = function()
{
console.log(document.currentScript); // <script> is printed
}
Case 2 - Capturing the <img> tag:
HTML: <img src='1' onerror="alert(1)">
JS:
window.alert = function()
{
console.log(arguments.callee.caller.arguments[0].target);
// arguments.callee --> console.log()
// arguments.callee.caller --> onerror(event) {}
// arguments.callee.caller.arguments[0] --> event
// arguments.callee.caller.arguments[0].target --> <img>
}
Case issue - Capturing the <a> tag:
HTML: Click here for alert
JS:
window.alert = function()
{
console.log( // how to find <a> element)
}
Please don't suggest me to modify the HTML by including IDs for <a> or something similar. Consider that the HTML is purely static, and I can't modify anything. I can just add a JavaScript, and I just wan't to know how this can be done.
You might be able to find such alerts and convert them to click events. Something like this. Note the click event alert call could be made much more sophisticated and potentially use eval(), but i leave that for you to risk.
window.alert = (function(){
var selected = document.querySelectorAll("a[href^='javascript:alert('");
Array.from(selected).forEach(function(item){
var old = item.href
item.addEventListener("click", function(){ alert(old.substring(11)); });
item.href="javascript:void(0);";
});
var _alert = function(msg) {
console.log(msg);
console.log(arguments.callee.caller.arguments[0].target);
};
return _alert;
})();
test
You can use load event at window; click event at selector "a[href='javascript:alert(1);']" to get value of href attribute; call event.preventDefault() within click handler; String.prototype.match() to create array of values withing href attribute; define matches globally; new Function(); Function.prototype.call() to set this to <a> element; call .click() on selector : <a> element with matched parameters returned by .match()
window.alert = function() {
console.log(arguments, this)
}
window.addEventListener("load", function() {
a = document.querySelector("a[href='javascript:alert(1);']");
a.addEventListener("click", function(event) {
event.preventDefault();
var data = this.href.replace(/javascript/, "");
matches = data.match(/\w+(?=\()|(\(.*\))/g);
matches[1] = matches[1].replace(/\(|\)/g, "");
var fn = new Function(matches[0] + ".call(a, matches[1])");
fn();
});
a.click();
});
Don't use the href attribute to call JavaScript. It should be avoided. It is not recommended usage. Use the onclick event instead. See here: https://stackoverflow.com/a/10242595/5969411
<script>
window.alert = function(msg, element) {
console.log('Msg:', msg);
console.log('Element:', element);
};
</script>
Test 1
Test 2
Test 3
I've returned false from the onclick event above in order to repress the anchor from going to '#' URL directive, but you could easily return true instead here, if you wish.

jQuery nested functions

I am still new to JavaScript and jQuery, so I am confused as to why the following code is not working as I anticipated. All I am trying to do is save input on a button click (id=recordInput) and display it with another button click (id=displayInput). What I observe is that tempInput is stored, (the code works until that point) but assignment of displayInputs onclick attribute is not executed. My question is, can you not nest a $().click() call inside of another &().click() call?
<script>
$(document).ready(function () {
$('#recordInput').click(function(event) {
var tempInput = $('#testInput').val();
&('#displayInput').click(function(event) {
console.log(tempInput);
});
});
});
</script>
My thinking is this in pseudocode:
assign recordInput onclick attribute to the following function:
store tempInput
set displayInput onclick to alert the tempInput value
what is wrong with my thinking?
NOTE: I did not include any html tags but all of the ids are referenced correctly
It's not working because you have put & instead of $ here
$('#displayInput').click(function(event) {
Fixing this may work, but you shouldn't set event handlers this way. Because every time your first handler function is called it will set an event handler for the second one. You can try with your console.log and you will see that the number of console.log is increasing by every click on #recordInput. So you should better set it like this :
var tempInput;
$('#recordInput').click(function(event) {
tempInput = $('#testInput').val();
});
$('#displayInput').click(function(event) {
console.log(tempInput);
});
I would change
$(document).ready(function () {
$('#recordInput').click(function(event) {
var tempInput = $('#testInput').val();
&('#displayInput').click(function(event) {
console.log(tempInput);
});
});
});
to
$(function(){
var testInput = '';
$('#recordInput').click(function(){
testInput = $('#testInput').val();
});
$('#displayInput').click(function(){
if(testInput !== ''){
console.log(testInput);
}
});
});
You are using & instead of $. Of course, you don't have to format the code exactly like I did.

jQuery pointer to element which is clicked

I hope it's stupid, but my head is today right overloaded:) I have this code and I need to store the pointer on the element which is clicked on and pass it to the callback function. Exactly is it a submit button and after correct ajax submit of the form I want to delete content of them. I've tried lot of these parent(),children(),.. combinations, but it does not work:
$("form :submit").click(function () {
var element = this;
$(this).ajaxSubmit(function(payload, element){
$.nette.success(payload);
$(element).parent().children(".addStatusTextArea").val("");
hideMessage();
}
);
return false;
});
The problem is that element is also specified in your parameters for the callback, leave this out, like this:
$("form :submit").click(function() {
var element = this;
$(this).ajaxSubmit(function(payload) { //no element here in params
$.nette.success(payload);
$(element).parent().children(".addStatusTextArea").val("");
hideMessage();
});
return false;
});
When it's in the parameters a more local element is defined, not what you set it to just before. I'm not sure if your relative .parent().children() call is correct (it could be .siblings(".addStatusTextArea") if it is) without seeing your markup...but your main issue is element not being what you want.
Remove the element parameter from the function passed to ajaxSubmit.
i.e.
$("form :submit").click(function () {
var element = this;
$(this).ajaxSubmit(function(payload){
$.nette.success(payload);
$(element).parent().children(".addStatusTextArea").val("");
hideMessage();
});
return false;
});

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

Passing in parameter from html element with jQuery

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);
}

Categories

Resources