Question about selecting form children jquery - javascript

Again I'm asking question about comment form, I'm making an image website and every image has its own comment form, so when I submit form I do like this :
$('#comment_form').live('submit', function() {
...
So in order to select only this form textearea value I tried using this but I get undefined error here is how I tried :
$('#comment_form').live('submit', function() {
image_comment_text=$(this).closest("#comment_text").val(); //textarea id is comment_text
I tried to used find(), its working but when I submit comments for few images I get comments 2 or 3 times as I should, because find finds all occurrences of textarea with comment_text id .. how can I do this ?
#molf , here is HTML generated by javascript:
var xHTML = "<div class=\"addComment\">";
xHTML += "<form action=\"<?=base_url()?>images/post_comment/" + post + "\" method=\"post\" class=\"comment_form\" name=\"comment_form\">";
xHTML += "<input type=\"hidden\" class=\"comment_post_id\" name=\"comment_post_id\" value=\"" +post + "\"/>";
xHTML += "<textarea class=\"comment\" name=\"comment_text\" rows=\"8\" cols=\"40\"></textarea>";
xHTML += "<input type=\"submit\" name=\"submit\" class=\"post_image_comment\" value=\"Comment\"><span> Don't make it too big!</span>";
xHTML += "</form></div>";
EDIT
When I print to console log the value of textarea I get only one result as I should, now when I try to append the ul comments I get 2 of the same values .. here how it goes ..
<ul class="comments"></ul>
below is the comment form which is not in the document at all, when certain anchor is clicked the form pops out below .comments , when form submits I want to append the comments to add the new comment to list items of existing unordered list comments , here is the whole code :
$('form[name^="comment_form"]').live('submit', function(event) {
r= $(this).find('> .comment').val();
$('<div class="overlay"></div>')
.appendTo('.addComment')
.fadeIn(200, function() {
$('.comments')
.append('<li id="new_append">' + r + '</li>')
.children(':last')
.height($('.comments li:last').height())
.hide()
.slideDown(800, function() {
var bodyHeight = $('html').height();
$('.addComment').fadeOut(500, function() {
$('html').height(bodyHeight);
$('h2#leaveAComment').fadeOut(200, function(){$(this).text('Thank you for your comment!').fadeIn(200)});
});
});
$('html, body').scrollTo( $('#new_append'), 800 );
});
event.preventDefault();
});
EDIT II #patrick
The javascript which loads the comment form is above .. here is HTML :
-------------BEGIN FOR EACH--------------
<div id="image-12" class="image_content">
<img src="..." />
<ul class="comments hidden"> //This is where the comments are appended to <li></li>
</ul>
<div style="float: left; display: block; width: 100%;">
<a id="image_comment-12" class="image_comment" onclick="showComments('12');" href="javascript:;">Add Comment</a>
</div>
<div id="addComment-12">//this is where the comment form loads
</div>
</div>
----------END--- FOR EACH--------- image ...

First of all, change your selector for your form. I think you can select form by name using the id selector, but you're not supposed to duplicate ids on a page, so jQuery live is probably only watching the first form. This is just a guess, though.
Also, it doesn't matter what class/id you use for your textarea. If you're only going to have one textarea per form, you can use the :text selector. When finding children, I like to use the children selector.
$('form[name="comment_form"]').live('submit', function() {
image_comment_text = $(this).find('> :text').val();
});
If you're using name instead of id because you're going to have multiple forms, I would suggest changing the name to comment_form_'image_id', then your selector would be: $('form[name^="comment_form"]')
Notice the ^ which requires the name to start with 'comment_form'. That way, you can have unique form names (comment_form_234, comment_form_235) and still have the desired effect.
Edit:
I looked at your code update, and it looks to me like you're ignoring the context of the current form in your function. For instance, when you use the selector $('.comments').append(... you're appending to all elements on your page which match that selector. In order to retrieve the proper elements, you'll have to always use your selector as $(this).find(' > .comments').append(... which will work within the context of the submitted form.
I took a few minutes to edit your code, I haven't run it or anything, but it should be close to what you're trying to do. I hope it at least gets you started in the right direction:
$('form[name^="comment_form"]').live('submit', function (event) {
r = $(this).find('> .comment').val();
/* get addComment-classed element */
var addComment = $(this).find(' > .addComment:first');
/* get comments-classed element */
var comments = $(this).find(' > .comments:first');
$('<div class="overlay"></div>').appendTo(addComment).fadeIn(200, function () {
/* note comments element, not selector */
$(comments).append('<li id="new_append">' + r + '</li>').children(':last').height(
/* again, element */
$(comments).find(' > li:last').height()).hide().slideDown(800, function () {
var bodyHeight = $('html').height();
/* again, element */
$(addComment).fadeOut(500, function () {
$('html').height(bodyHeight);
$('h2#leaveAComment').fadeOut(200, function () {
$(this).text('Thank you for your comment!').fadeIn(200)
});
});
});
$('html, body').scrollTo($('#new_append'), 800);
});
event.preventDefault();
});
I added comments in the code, but notice that the addComments and comments selectors are 'cached'. If you're going to be accessing these elements multiple times, storing them in a variable before using them will cut back on DOM traversals. This should really solve your comments being added to multiple elements on your page.

How many comment_forms do you have on a each page? For correct HTML you should only have one id='comment_text' and one id='comment_form' per page.
Consider changing your ids to class='comment_text' and finding with .comment_text rather than #comment_text
I think from your latest comments the issue may be the way you are dynamically adding your form/comments textbox to the page.
Once you've entered comments and submitted them do you then remove the form you've dynamically added? I would recommend this as if not I think your DOM structure is getting confused causing the problems you are experiencing.

First, the find() method was the correct way to go if used within the proper context.
Second, it sounds like you are re-using IDs. This is not allowed. An ID can be used only once on a page.
The closest() function searches 'up' from (and including) the DOM element. The find() function searches the content of the element.
EDIT:
I assume the form is being submitted when the user clicks the submit button. I also assume that there's more to your submit() handler than is shown. Is that correct?
Sometimes you need to add $(this).preventDefault(); in order to keep the form from being submitted in your code, as well as by the default behavior of the 'submit' button.
The following does the same thing (essentially) as find(). It will find the item with the .comment_text class within the form being submitted. So it should only grab the value of one item:
image_comment_text=$(".comment_text", this).val();

You are getting duplicate comments because you aren't removing the previous add comment form. Try adding this to the end of your .slideDown callback function:
$(this).remove();
Here is the full submit function, I made a few changes/additions:
I removed the > from the find('.comment') as it isn't necessary
Changed the new append to a class, then removed it after you scroll to it.
Removed the form when complete
Changed the event.preventDefault(); to return false;... this is more of a personal preference than anything.
I hope this helps :)
$('form[name^="comment_form"]').live('submit', function(event) {
r = $(this).find('.comment').val();
$('<div class="overlay"></div>')
.appendTo('.addComment')
.fadeIn(200, function() {
$('.comments')
.append('<li class="new_append">' + r + '</li>')
.children(':last')
.height($('.comments li:last').height())
.hide()
.slideDown(800, function() {
var bodyHeight = $('html').height();
$('.addComment').fadeOut(500, function() {
$('html').height(bodyHeight);
$('h2#leaveAComment').fadeOut(200, function(){$(this).text('Thank you for your comment!').fadeIn(200)});
$(this).remove();
});
});
$('html, body').scrollTo( $('.new_append:last'), 800 );
$('.new_append').removeClass('new_append');
});
return false;
});

Related

dynamically created form depending on <select> does not work

I'm developing a website which must display particular forms for various products depending on the value that the user selects (in <select>) - so a number various forms are created dynamically in a loop by means of a javascript function (buildform() ). The code does not work, e.g. the forms are not created/appended to the wrappers. I narrowed down the problem where i think the problem relates to a different values for the jquery selectors/div-id's (#ecorpproductwrapper"+ecorp_eprodselectid).
When I use (just as a test) #ecorpproductwrapper" (without the variable ecorp_eprodselectid; see also in code below under ALTERNATIVE WORKS) the code works fine, e.g. the forms are built. I checked by means of the console that the ecorpproductwrapper"+ecorp_eprodselectid values are the same for the div-id's and jquery selectors, so I dont understand what goes wrong?
Pls see the simplified code below:
for(var i=0;i<5;i==){
var ecorp_eprodselectid; //will have various values
//function to build form depending on selected value in <select class= eprodtype"+ecorp_eprodselectid >
$(".eprodtype"+ecorp_eprodselectid).focus(function () {
var previous;
// Store the current value on focus and on change
previous = this.value; //old select value
}).change(function() {
var optionsform = buildform(this.value);
console.log('append form'+optionsform);
//NEXT 2 lines doe NOT WORK
$("#ecorpproductwrapper"+ecorp_eprodselectid).children().remove(); //remove previous form
$("#ecorpproductwrapper"+ecorp_eprodselectid).append(optionsform);
//ALTERNATIVE works: $('#ecorpproductwrapper').children().remove(); //remove previous tariif struct form
//ALTERNATIVE works: $('#ecorpproductwrapper').append(optionsform);
var str = "#ecorpproductwrapper"+ecorp_eprodselectid;
console.log('STRING ECORP PRODUCT APPEND: '+str);
console.log('change eprod val: '+this.value);
previous = this.value;
});//$("").focus(function () {
}//for i
//function to build form
var buildform = function(ecorp_eproductid) {
//some code here
//NEXT LINE does not work:
form += '<td> <div id="ecorpproductwrapper'+ ecorp_eprodselectid+'"> </div> </td> </tr>'; //cell with wrapper for ecorp product info
//ALTERNATIVE WORKS: form += '<td> <div id="ecorpproductwrapper"> </div> </td> </tr>'; //cell with wrapper for ecorp product info
//some code here; returns form
}//function buildform
I think you forgot to add ecorp_eprodselectid in your function.
var buildform = function(ecorp_eprodselectid ) {
Few things we assume concerning given text above:
You know this.value works
console.log shows optionsform have HTML that it should have. Not said in OP but if not, the function does not work. function seems to be missing already var buildform = function(someVar) as noted by buysDB
As I cannot see your code, I would try first clear everything 100% by chaning this:
$("#ecorpproductwrapper"+ecorp_eprodselectid).children().remove();
to:
$("#ecorpproductwrapper"+ecorp_eprodselectid).html("");
Then:
$("#ecorpproductwrapper"+ecorp_eprodselectid).html(optionsform);
No need for append if you have no intention to keep anything in DIV.
If you have text also in (#ecorpproductwrapper"+ecorp_eprodselectid) which is why you use children(), consider selecting the DIV that can be cleared.
If that still does not work, something is left out that needs consideration.

How do you 'replace' numbers with 'x's' in jQuery with one button?

Does anyone know how to do replace multiple text by clicking a button with jQuery?
I've built a website that displays some text/data eg; "£100.00", but I what I need is to be able to 'replace' those monetary values with "£XXX.XX" with a 'Hide' button like you get on some banking websites. For example one web page has:
£100.00, £200.00, £130.00 etc etc..
...so when a user presses the Hide button, all of the numbers on the page turn to £XXX.XX. Ideally, the button should then display "Show" instead of "Hide" and switch back when toggled.
This is for a static dummy site, so no data base.
I suspect this is best handled with jQuery?
Thanks for your time,
D.
Case 1: Controlled Input
Assuming you can at least wrap all monetary values with something like this:
<span class="money-value">£200.00</span>
<span class="money-value">£300.50</span>
And that you can add button declared with:
<button id="secret-button">hide</button>
Then you could have some jQuery code doing this:
/**
* Simple search and replace version.
*/
$(function() {
$("#secret-button").click(function() {
$(".money-value").html($(".money-value").html().replace(/[0-9]/g,"X"));
});
});​
or a more advanced one with:
/**
* Complet version.
*
* 1) on button click, if asking to hide:
* 1.1) iterate over all entries, save their text, and replace it with markers
* 1.2) toggle the button's text to "show"
* 2) on button click, if asking to show:
* 2.1) iterate over all entries, restore previous text
* 2.2) clear the hidden store
* 2.3) toggle the button's text to "hide"
*/
$(function() {
var hiddenStore = [];
$("#secret-button").click(function() {
if ($(this).html() == "hide") {
$(".money-value").each(function () {
var text = $(this).html();
hiddenStore.push(text);
$(this).html(text.replace(/[0-9]/g,"X"));
});
$(this).html("show");
} else {
$(".money-value").each(function (i) {
var text = hiddenStore[i];
$(this).html(text);
});
hiddenStore = [];
$(this).html("hide");
}
});
});​
Complete solution is here: See here: http://jsfiddle.net/u79FV/
Notes:
this won't work for input field values
this assumes your text entries have been marked as shown above
Does what you want with the button's changing state.
Saves the values and puts them back.
Meant to work even if new fields are added dynamically.
Shankar Sangoli's answer uses a different way of saving the stored data, which you could as well consider (using the jQuery .data() method).
you may want to switch the button to an <input type="button" /> tag, in which case you'd use .val() instead of .html() to toggle its text.
Case 2: Uncontrolled Input
Assuming you don't have control over where the values may show up, then you need to do something a bit more complicated, which is to look in the whole page for something that would look like a currency format. I'd advise against it.
But, the jQuery Highlight plugin could be something to look at, as its code does something similar (in that it searches for pieces of code to modify), and you could then reuse some of solution 1 to make it fit your purpose.
That would be harder to design in a fool-proof fashion though.
You could use a regular expression:
var expression = /\d{1}/g;
var newString = myString.replace(expression,"X");
Then just dump newString into whatever control you need it to appear in.
Edit:
A jQuery idea for something like this would be to give all of the controls that have these numbers a common class identifier to make them easy to grab with the selector:
$(".numbers").each(function() {
$(this).text($(this).text().replace(/\d{1}/g, "X"));
}
... more readable ...
$(".numbers").each(function() {
var text = $(this).text();
var newText = text.replace(/\d{1}/g, "X");
$(this).text(newText);
}
If your markup is something like this you can try this.
<span>£1000.00</span><span class="showhide">Hide</span>
JS
$('.showhide').click(function(){
var $this = $(this);
var $prev = $this.prev();
if(!$prev.data('originalvalue')){
$prev.data('originalvalue', $prev.text());
}
if($this.text() == 'Hide'){
$this.prev().text($prev.data('originalvalue').replace(/\d{1}/g,"X"));
$this.text('Show');
}
else{
$prev.text($prev.data('originalvalue'));
$this.text('Hide');
}
});
In the above code I am basically storing the original value using jQuery data method within the span element itself which is used to display the actual value.
Once you click on Hide, get the previous span using prev() method and set its text with original value replacing all the numbers in it by X. Then change the link text from Hide to Show.
Next when you click on Show get the previous span using prev() method and set its text with the original value and change the link text from Show to Hide.
References: .prev(), .data()
$('#yourButton').click(function(){
var saveText = $('body').text();
$(this).data('oldText', saveText);
if ($(this).text() == "Hide"){
$('body').text($('body').text().replace(/\d{1}/, "X"));
$(this).text('Show');
}
else{
$('body').text($(this).data('oldText'));
$(this).text('Hide');
}
});
This is kind of a complicated problem actually. You will need to be able to save the state of the text when its in number form so you will be able to toggle back and forth. The above code is untested but hopefully it will give you an idea what you need to do.
function toggleMoney() {
$('.money').each(function() {
var $$ = $(this), t = $$.text();
$$.text($$.data('t') || t.replace(/\d/g, 'X')).data('t', t);
});
$('#toggleButton').text($('.money').text().match(/\d/) ? 'hide' : 'show');
}
http://jsfiddle.net/DF88B/2/

jQuery Clone inputs in two forms on the same page?

I have been trying to get two forms on the same page to work and the only issue i'm having is not getting the clone inputs to work, they seem to conflict with each other due to the div elements.
I have been using this tutorial as a guide:
http://www.9lessons.info/2009/06/submit-multiple-forms-jquery-ajax.html
Here is the code working with one form:
http://jsfiddle.net/yBdTA/
And this is what i want to achieve:
http://jsfiddle.net/c4Uce/
Notice when you click on the second 'Add More' link the first input clones rather than the second.
I know i could duplicate the jQuery function for the clone to match the second form:
$(function(){
var removeLink = ' <a class="remove" href="#" onclick="jQuery(this).parent().slideUp(function(){ jQuery(this).remove() }); return false">remove</a>';
jQuery('a.add').relCopy({ append: removeLink});
});
but i want this to be, how can i call it, dynamic? like the 9lessons guide, i can use PHP to create unique identifiers for the clone elements and want the jQuery to match the ID's,
Hope i made this clear.
Help appreciated.
U can try it , it work to multi form
http://jsfiddle.net/yBdTA/2/
(function($) {
function remove(){
$('.clone').each(function(i){
var input= $(this);
input.find('a.remove').click(function(){
input.remove();
});
});
}
$('form').each(function(i){
var form = $(this);
var removeLink = '<a class="remove" href="#">remove</a>';
var iputclone = form.find('p.clone').append(removeLink);
form.find('a.add').click(function(){
iputclone.clone().insertBefore(this);
remove();
});
});
})(jQuery);
Update :
iputclone.clone().insertBefore(this).find('.input').attr('value','');
//So easy, U can think a object when we start will is ifself, use it next, and next

jQuery + InnovaStudio WYSIWYG Editor

I am trying to avoid hard-coding each instance of this WYSIWYG editor so I am using jQuery to create an each() loop based on function name. Annoyingly InnovaStudio seems to explode when I try.
Documentation
Attempt #1
<script type="text/javascript">
/*
id = $(this).attr('id');
if(id.length == 0)
{
id = 'wysiwyg-' + wysiwyg_count;
$(this).attr('id', id);
}
WYSIWYG[wysiwyg_count] = new InnovaEditor('WYSIWYG[' + wysiwyg_count + ']');
WYSIWYG[wysiwyg_count].REPLACE(id);
*/
var demo = new InnovaEditor('demo');
demo.REPLACE('wysiwyg-1');
console.log('loop');
</script>
Effect
Works fine, but of course only works for a single instance of the editor. If I want multiple instances I need to use an each.
Attempt #2:
<script type="text/javascript">
var wysiwyg_count = 1;
//var WYSIWYG = [];
var demo;
(function($) {
$(function() {
$('.wysiwyg-simple').each(function(){
/*
id = $(this).attr('id');
if(id.length == 0)
{
id = 'wysiwyg-' + wysiwyg_count;
$(this).attr('id', id);
}
WYSIWYG[wysiwyg_count] = new InnovaEditor('WYSIWYG[' + wysiwyg_count + ']');
WYSIWYG[wysiwyg_count].REPLACE(id);
*/
demo = new InnovaEditor('demo');
demo.REPLACE('wysiwyg-1');
console.log('loop');
});
});
})(jQuery);
</script>
Effect
Replaces the entire HTML body of my page with JUST WYSIWYG related code and complains as no JS is available (not even Firebug, so can't debug).
Notice that I am hardcoding the name still. I only have one instance on the page I am testing it on, so when I get this hard-coded name working I will get the commented out code working along the same lines.
Does anybody know what the hell is going on here?
Solution: Don't bother trying to use InnovaStudio, went with CKEditor instead.
Even though you went for CKEditor you might be interested in a solution. You can supply a second argument to the REPLACE function. This second argument should also be a id, id from a element able to accept html output (like div, span, p).
demo = new InnovaEditor('demo');
demo.REPLACE('wysiwyg-1', 'wysiwyg-1-replaceDiv');
When the second argument is left out, InnovaStudio, writes the html output to the document by simply using:
document.write();
Hope this helps!
Why don't you use their own initialization code since version 4.3:
<textarea class="innovaeditor">
content here...
</textarea>
<script>
oUtil.initializeEditor("innovaeditor",
{width:"700px", height:"450px"}
);
</script>
The method is oUtil.initializeEditor(selector, option). The first parameter is selector and second is editor properties in JSON format.
The selector can be:
Css class name, if class name is specified all textareas with specified class name will be replaced with editor.
Textarea Id. If it is an Id, a prefix '#' must be added, for example oUtil.initializeEditor("#mytextarea").
Textarea object.
The second parameter is editor's properties. All valid editor's properties can be specified here for example width, height, cmdAssetManager, toolbarMode, etc.
Note that this method can be called from page onload or document ready event or during page load (as long as the object referred by selector are already rendered). This method available automatically when the page include the editor script.

JQuery Copy text & paste into textarea

I've created a javascript function that will take a hidden span, copy the text within that span and insert it into a single textarea tag on a website. I've written a function in JavaScript that does this (well, kinda, only after a few clicks), but I know there's a better way - any thoughts? The behavior is similar to a Retweet for twitter, but using sections of a post on a blog instead. Oh, and I'm also calling out to jquery in the header.
<script type="text/javascript">
function repost_submit(postID) {
$("#repost-" + postID).click(function(){
$("#cat_post_box").empty();
var str = $("span#repost_msg-" + postID).text();
$("#cat_post_box").text(str);
});
}
</script>
Based on the comment in your question, I am assuming you have something like this in your HTML:
copy post
And I am also assuming that because you are passing a post ID there can be more than one per page.
Part of the beauty of jQuery is that you can do really cool stuff to sets of elements without having to use inline Javascript events. These are considered a bad practice nowadays, as it is best to separate Javascript from your presentation code.
The proper way, then, would be to do something like this:
<a href="#" id='copy-5' class='copy_link'>copy post</a>
And then you can have many more that look similar:
<a href="#" id='copy-5' class='copy_link'>copy post</a>
<a href="#" id='copy-6' class='copy_link'>copy post</a>
<a href="#" id='copy-7' class='copy_link'>copy post</a>
Finally, you can write code with jQuery to do something like this:
$(function() { // wait for the DOM to be ready
$('a.copy_link').click(function() { // whenever a copy link is clicked...
var id = this.id.split('-').pop(); // get the id of the post
var str = $('#repost_msg-' + id); // span not required, since it is an ID lookup
$('#cat_post_box').val(str); // empty not required, and val() is the proper way to change the value of an input element (even textareas)
return false;
});
});
This is the best way to do it even if there is only one post in the page. Part of the problem with your code is that on the first click it BINDS the function, and in the subsequent clicks is when it finally gets called. You could go for a quick and dirty fix by changing that around to just be in document.ready.
$("#repost-" + postID).click(function(){
$("#cat_post_box").val(''); // Instead of empty() - because empty remove all children from a element.
$("#cat_post_box").text($("#repost_msg-" + postID).text());//span isn't required because you have and id. so the selector is as efficient as it can be.
});
And wrap everything in a $(document).ready(function(){ /Insert the code here/ }) so that it will bind to $("#repost-" + postID) button or link when the DOM is loaded.
I had a problem with Paolo's example when I clicked on the link the text that appeared in #cat_post_box was "object Object". Once I added ".text()" to the end of that statement I worked.
var str = $('#repost_msg-' + id).text();
Thanks for you example Paolo!

Categories