Jquery: How to reorder DIVs after removing a single Div? - javascript

I am working on an application in which contains a few DIVs having IDs like a1,a2,a3 etc.
There is option of navigation DIVs by hitting next and previous button which brings one Div on screen at a time. strong text There are two more actions: Add and Remove. Add adds a Div with ID greated than last ID, for instance if last DIV id was a3 then Add brings a4.
The real issue is removing current DIV. If the user is on Div a2 and hits Remove option then it deletes the current Div by using .remove() method of jQuery
Now navigation breaks because it is sequential. It tries to find Div a2 but does not find. What I think that Ids of all remaining DIVs should be renamed. Since there is no a2 so a3 should become a2 and so on. How can I do that? Code doing different tasks is given below:
function removeQuestion()
{
$("#_a"+answerIndex).remove();
if(answerIndex > 1)
{
if ($("#_a"+(++answerIndex)).length > 0)
{
$("#_a"+answerIndex).appendTo("#answerPanel");
}
else if($("#_a"+(--answerIndex)).length)
{
$("#_a"+answerIndex).appendTo("#answerPanel");
}
totalOptions--;
}
}
function addQuestion()
{
var newId = 0;
totalOptions++;
var d = 1;
newId = totalOptions;
var _elemnew = '_a'+newId;
$("#_a"+d).clone().attr('id', '_a'+(newId) ).appendTo("#answers_cache");
var h = '<input onclick="openNote()" id="_note'+newId+'" type="button" value=" xx" />';
$("#"+_elemnew+" .explain").html(h)
$("#"+_elemnew+" ._baab").attr("id","_baab"+newId);
$("#"+_elemnew+" ._fx").attr("id","_fasal"+newId);
$("#"+_elemnew+" .topic_x").attr("id","_t"+newId);
$("#"+_elemnew+" .topic_x").attr("name","_t"+newId);
$("#"+_elemnew+" .answerbox").attr("id","_ans"+newId);
$("#"+_elemnew+" .block").attr("onclick","openFullScreen('_ans"+newId+"')");
$('.tree').click( function()
{
toggleTree();
}
);
$('.popclose').click( function()
{
unloadPopupBox();
}
);
}
function next()
{
console.log("Next ->");
if(answerIndex < totalOptions)
{
answerIndex++;
console.log(answerIndex);
setInitialAnswerPanel();
}
}
function previous()
{
console.log("Next <-");
if(answerIndex > 1)
{
answerIndex--;
console.log(answerIndex);
setInitialAnswerPanel();
}
}
Html of Composite DIV is given below:
<div class="answers" id="_a1" index="1">
<input placeholder="dd" id="_t1" type="text" name="_t1" class="urduinput topic_masla" value="" />
<img class="tree" onclick="" src="tree.png" border="0" />
<label class="redlabel">
xx :
</label>
<label id="_baab1" class="baabfasal _baab">
</label>
<label class="redlabel">
xx :
</label>
<label id="_fasal1" class="baabfasal _fasal">
</label>
<a title=" ddd" class="block" href="#" onclick="openFullScreen('_ans1')">
<img src="fullscreen.png" border="0" />
</a>
<textarea id="_ans1" class="answerbox" cols="40" rows="15"></textarea>
<span class="explain">
<input onclick="openNote()" id="_note1" type="button" value=" xx" />
</span>
<span style="float:left;padding-top:5%">
plus | <a onclick="removeQuestion()" href="#">minus</a>
</span>
</div>

Why don't you keep currently opened page instead of the index and search for previous and next pages using prev() and next() jQuery tree traversal methods?

Select all div elements containing questions, preferable with a css class selector, use the each method, and assign new ids to them:
$('.questionDiv').each(function(index) { $(this).attr('id', 'a' + (index + 1)); })
That should be enough.

var originalSet = $('.answers');
var container = originalSet.up() ;
var byId = function(a, b){
return $(a).attr('id') > $(b).attr('id') ? 1 : -1;
}
originalSet
.order(byId)
.each(function rearrangeIds(position){
$(this).attr({
'index': poition,
'id': '_a'+position
});
}).appendTo(container)

Related

Change only one element after clicking other

I have the following problem:
I would like to change the value of an input field, which is next to an another element, which will be clicked.
HTML:
<div>
<a id="{$sArticle.articleID}" class="minus"><i class="icon-minus-wide"></i></a>
<input class="quantityNum--input quantity{$sArticle.articleID}" name="sQuantity"
type="text" value="{$sArticle.minpurchase}">
<a id="{$sArticle.articleID}" class="plus"><i class="icon-plus-wide"></i></a>
</div>
JS:
$(document).on('click', ".plus", function (event) {
let currentTarget = event.currentTarget;
let idOfClickedElement = $(currentTarget).attr('id');
let currentQuantity = Number($('.quantity' + idOfClickedElement).val());
$(this).parent().find(".quantity" + idOfClickedElement).val(currentQuantity + 1)
});
There are other input fields which are the same like in the example. Those value changes also, but I want only one.
As each input with +/- is inside a div wrapper, you can use
$(this).closest("div").find(".quantityNum--input")
to get the related input.
There's no need for the numeric IDs when using relative DOM traversal.
Combining the + and - into a single event gives:
$(document).on('click', ".minus,.plus", function() {
var delta = $(this).is(".plus") ? 1 : -1;
$(this).closest("div").find(".quantityNum--input").val((i, val) => {
console.log(val);
return (val * 1) + delta;
});
});
.minus,
.plus {
cursor: pointer
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a class="minus">[-]<i class="icon-minus-wide"></i></a>
<input class="quantityNum--input" name="sQuantity" type="text" value="100">
<a class="plus">[+]<i class="icon-plus-wide"></i></a>
</div>
<div>
<a class="minus">[-]<i class="icon-minus-wide"></i></a>
<input class="quantityNum--input" name="sQuantity" type="text" value="500">
<a class="plus">[+]<i class="icon-plus-wide"></i></a>
</div>
I thik you are looking for .next and .prev.
note: I like sharing information usingdata-attributes so I've used that. you can use anything else id/class to differentiate. that's upto you
Just created a demo script for you
$('.number-action-button').on('click', function(){
const direction = $(this).data('direction');
if(direction === 'decrement'){
const $input = $(this).next('input[type="number"]');
$input.val($input.val() - 1);
}
if(direction === 'increment'){
const $input = $(this).prev('input[type="number"]');
$input.val(parseInt($input.val()) + 1);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="number-action-button" data-direction="decrement">-</button>
<input type="number" value="0" />
<button class="number-action-button" data-direction="increment" >+</button>
simple solution: bundle the 3 elemts into 1 container, so your parent selector can easily catch the input, the way you already do it.
<div>
<a id="{$sArticle.articleID}" class="minus"><i class="icon-minus-wide"></i></a>
<input class="quantityNum--input quantity{$sArticle.articleID}" name="sQuantity"
type="text" value="{$sArticle.minpurchase}">
<a id="{$sArticle.articleID}" class="plus"><i class="icon-plus-wide"></i></a>
</div>
if you cant(or dont want) change the html use $(this).next() (or $(this).prev() for the plus button) in order to fint the input.
btw: maybe you'll try that funktion (havn't tested it, but at least it should give you an idea how to)
$(document).on('click', ".plus,.minus", function (event) {
let input_quantity=false;
if($(this).hasClass('plus'){
input_quantity=$(this).prev();
input_quantity.val(parseInt(input_quantity.val())+1);
}else{
input_quantity=$(this).next();
input_quantity.val(parseInt(input_quantity.val())-1);
}
});

jQuery show only divs matching multiple checkbox parameters

I am trying to create a system to filter through some tags by hiding and showing the appropriate items.
When .brandFilter is clicked, it needs to show the div using the id of the checkbox. When .prodFilter is clicked, it needs to show the corresponding colors but not show any deselected ID's (unless none have been selected, in which case show everything matching the color).
Right now when I click Epson and HP it works; but when I click Red it will show the red Lexmark product which is not desired; it was already filtered out when I selected the brand. Ideally clicking #brnd_HP, #brnd_Epson and #typ_Red will display Product A and F.
Deselecting a filter should "undo" whatever previous work it did.
Below is the markup I have now:
<h2>Brand</h2>
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Canon" />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Epson" />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_HP" />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Lexmark" />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Xerox" />
<h2>Color</h2>
<input type="checkbox" class="prodFilter" name="typeFilter" id="typ_Red" />
<input type="checkbox" class="prodFilter" name="typeFilter" id="typ_Blue" />
<div class="prdbx brnd_Epson typ_Red">Product A</div>
<div class="prdbx brnd_Canon typ_Red">Product B</div>
<div class="prdbx brnd_Epson typ_Blue">Product C</div>
<div class="prdbx brnd_Lexmark typ_Red">Product D</div>
<div class="prdbx brnd_Canon typ_Blue">Product E</div>
<div class="prdbx brnd_HP typ_Red">Product F</div>
The jQuery is not functioning as intended, but this is what I have so far. I really can't seem to wrap my head around the seemingly query like nature of toggling visibility with multiple parameters like this. The HP/Epson part works fine, but once the color is introduced it simply shows everything relating to the color ID.
<script>
jQuery(document).ready(function(){
$('.brandFilter').click(function(e) {
$('.brandbx').hide();
var thisFilter = "";
$('input[name=brandFilter]:checked').each(function(e) {
thisFilter += '.'+this.id;
});
$(thisFilter).show();
});
// when a filter is clicked
$('.prodFilter').click(function(e) {
$('.prdbx').hide(); // hide all products
var thisFilter = "";
var thisCounter = 0;
// for each clicked filter
$('.prodFilter:checked').each(function(e) {
thisFilter += '.'+this.id;
$('.'+this.id).show(); // show the products matching filter
thisCounter++;
});
if(thisCounter == 0){
$('.prdbx').show(); // if no clicked filters, show all products
$('.brandbx').show();
}
});
});
</script>
You need to combine the filters which means persisting the filter from the first checkbox somehow. This works.
var thisFilter1 = "";
jQuery(document).ready(function(){
$('.brandFilter').click(function(e) {
$('.brandbx').hide();
thisFilter1 = "";
var sep = ""
$('input[name=brandFilter]:checked').each(function(e) {
thisFilter1 = thisFilter1 + sep + '.'+this.id;
sep = ","
});
$(thisFilter1).show();
});
// when a filter is clicked
$('.prodFilter').click(function(e) {
$('.prdbx').hide(); // hide all products
var thisCounter = 0;
var thisFilter = "";
var sep=""
// for each clicked filter
$('.prodFilter:checked').each(function(e) {
thisFilter = thisFilter + sep + '.' + this.id;
sep=","
thisCounter++;
});
if(thisCounter == 0){
$('.prdbx').show(); // if no clicked filters, show all products
$('.brandbx').show();
}
else {
$('.prdbx').each(function() {
if ($(this).is(thisFilter1) && $(this).is(thisFilter)){
$(this).show()
}
})
}
});
});
EDIT: Updated for multiple selection combos. Say hello to jquery .is(). An interesting function that does not return a jq object so can't be chained but can be used inside an if test. You can now have Canon red, blue or red + blue, or HP + Canon blue, etc.
I might have not understand the desired functionality because in my code none of the products is shown at the beginning.
HTML:
<h2>Brand</h2>
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Canon" /> Canon
<br />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Epson" /> Epson
<br />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_HP" /> HP
<br />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Lexmark" /> Lexmark
<br />
<input type="checkbox" class="brandFilter" name="brandFilter" id="brnd_Xerox" /> Xerox
<br />
<h2>Color</h2>
<input type="checkbox" class="prodFilter" name="typeFilter" id="typ_Red" /> Red
<br />
<input type="checkbox" class="prodFilter" name="typeFilter" id="typ_Blue" /> Blue
<div class="prdbx brnd_Epson typ_Red show">Epson Red</div>
<div class="prdbx brnd_Canon typ_Red show">Canon Red</div>
<div class="prdbx brnd_Epson typ_Blue show">Epson Blue</div>
<div class="prdbx brnd_Lexmark typ_Red show">Lexmark Red</div>
<div class="prdbx brnd_Canon typ_Blue show">Canon Blue</div>
<div class="prdbx brnd_HP typ_Red show">HP Red</div>
CSS:
.prdbx {
display: none;
}
.prdbx.show {
display: block;
}
JavaScript:
jQuery(document).ready(function() {
$(".brandFilter").on('change', function() {
//Filter by brand first
filterByBrand();
//Then filter by color
filterByProd();
});
$(".prodFilter").on('change', function() {
filterByProd();
});
});
function filterByBrand() {
var $allBrands = $(".brandFilter");
if (!$allBrands.filter(':checked').length) {
//If all brand checkboxes are unchecked, show all prdbx divs
$('.prdbx').addClass('show');
} else {
for (var i = 0; i < $allBrands.length; ++i) {
var $brand = $allBrands.eq(i);
//If a brand is checked show it, otherwise hide it
if ($brand.is(':checked')) {
$('.' + $brand.attr('id')).addClass('show');
} else {
$('.' + $brand.attr('id')).removeClass('show');
}
}
}
}
function filterByProd() {
var $allProdFilters = $(".prodFilter");
var noneIsSelected = true;
for (var i = 0; i < $allProdFilters.length; ++i) {
var $prodFilter = $allProdFilters.eq(i);
var $prod = $('.' + $prodFilter.attr('id'));
//If the checkbox is checked
if ($prodFilter.is(':checked')) {
noneIsSelected = false;
if (!$prod.hasClass('show')) {
$prod.addClass('show');
}
} else {
$prod.removeClass('show');
}
}
//If no color is selected, filter by brand
if (noneIsSelected) {
filterByBrand();
}
}
And here is the fiddle: https://jsfiddle.net/mehmetb/m2zLt6Lo/

How do I add up values of buttons in jquery

I'm trying to sum up values of buttons if the buttons are clicked on. For example, there is "Button1". If this button is clicked, it should add its value to a sum which will be displayed at the bottom of the page. If "Button1" is clicked a second time it should substract its value from the sum.
Here is my attempt to do this but it's not doing anything at all:
var value_Buttons = 0;
var total = 0;
$("button[name=Button1],[name=Button2],[name=Button3],[name=Button4],[name=Button5],[name=Button6]").click(function() {
if($(this).hasClass('active') == false) {
value_Buttons += parseInt($(this).val());
} else if($(this).hasClass('active') == true) {
value_Buttons -= parseInt($(this).val());
}
total += value_Buttons;
alert(total);
});
total = value_Buttons + value_Optional_Button;
$("input[name=value_sum]").val(total);
Additionally, here is the code for an examplary button (Like "Button1"):
<div class="form-group col-md-2">
<button type="button" class="form-control btn btn-primary" name="Button1" value="300" title="300 €" data-toggle="button" aria-pressed="false" autocomplete="off">Button 1</button>
</div>
There will be more buttons, but they will only differ in their name and value.
Also, the box which will display the sum of the button-values currently looks like this:
<div>
<label class="control-label">Sum</label>
<div class="input-group">
<input class="form-control" name="value_sum" style="text-align:right" id="costs" value="" type="text" readonly>
<span class="input-group-addon">€</span>
</div>
</div>
I've searched all over Stackoverflow, as well as via Google, etc. yet I can't find anything or anyone with a similar problem
Blocking JS logic error is here :
$("input[name=value_sum]").val(total);
this line should be in the above code block. Added corrections for substraction :
var total = 0;
$("button[name]").on("click", function() {
if(!$(this).hasClass('active')) {
total += Number($(this).val());
$(this).addClass('active').html("remove " + $(this).attr("title"));
} else {
total -= Number($(this).val());
$(this).removeClass('active').html("add " + $(this).attr("title"));
}
$("input[name=value_sum]").val(total);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group col-md-2">
<button type="button" class="form-control btn btn-primary" name="Button300" value="300" title="300 €" data-toggle="button" aria-pressed="false" autocomplete="off">add 300 €</button>
<button type="button" class="form-control btn btn-primary" name="Button600" value="600" title="600 €" data-toggle="button" aria-pressed="false" autocomplete="off">add 600 €</button>
</div>
<div>
<label class="control-label">Sum</label>
<div class="input-group">
<input class="form-control" name="value_sum" style="text-align:right" id="costs" value="0" type="text" readonly>
<span class="input-group-addon">€</span>
</div>
</div>
Lines 14 and 15 need to be placed within the click event of the button to update the value_sum input on every click. Also your selection for the value attribute it a little bit off. The way to return the value attribute of a button using jQuery is:
$(this).attr('value');
So after these two points, stripping your code of the if and else check, and also selecting the buttons with a cleaner method, you should have something like this:
var total = 0;
$("button[name=Button1], button[name=Button2], button[name=Button3], button[name=Button4], button[name=Button5], button[name=Button6]").click(function() {
total += $(this).attr('value');
$("input[name=value_sum]").val(total);
});
To display the total, that is 0, in the input element on page load, you could use:
<input class="form-control" name="value_sum" style="text-align:right" id="costs" value="0" type="text" readonly>
start off by create a listener for a class that will be applied to all of your buttons.
$(.btn).click(function() {
//get value
var value = parseint($(this).attr("value"));
//check if already clicked
if($(this).hasClass('active') {
//set value of total
total = total - value;
//remove class active
$(this).removeClass('active');
}else {
//set value of total
total = total + value;
//addclass active
$(this).addClass('active');
}
)};
Is this what you need?
Working Demo
Here have added a classname 'add' for all buttons , on click its toggle class add, sub in you case you using active,inactive class
var total = 0;
$("button[name=button1],[name=button2],[name=button3]").on('click', function () {
var self = $(this);
var gValue = Number(self.val());
if (self.hasClass("add")) {
total += gValue;
self.removeClass("add").addClass("sub");
} else {
total -= gValue;
self.removeClass("sub").addClass("add");
}
$("#costs").val(total);
});
Check this fiddle.
Add as many buttons as you like, the only thing is that you'll have to add a data-value to them to figure out how much to add or substract. I would also do the search for buttons using a class instead of "button" but that's up to you.
var buttons = {};
$("button").each(function (index, item) {
buttons[index] = 0;
$(item).click(function () {
var value = +($(item).data("value")),
val = +($("#costs").val());
val += (!buttons[index]) ? value : -value;
buttons[index] = (!buttons[index]) ? 1: 0;
$("#costs").val(val);
});
});
Hope it helps.

dynamically creating div using javascript/jquery

I have two div called "answerdiv 1" & "answerdiv 2" in html.
now i want to give/create div id uniquely like "answerdiv 3" "answerdiv 4" "answerdiv 5" and so on.
Using javascript/jquery how can i append stuff in these dynamically created divs which id should be unique?
in my project user can add "n" numbers of div, there is no strict limit to it.
Help me out.
Thanks in Adv
================================================================================
My HTML code is:
<div id="answertextdiv">
<textarea id="answertext" name="answertext" placeholder="Type answer here" rows="2" cols="40" tabindex="6" onBlur="exchangeLabelsanswertxt(this);"></textarea>
</div>
My JS code:
function exchangeLabelsanswertxt(element)
{
var result = $(element).val();
if(result!="")
{
$(element).remove();
$("#answertextdiv").append("<label id='answertext' onClick='exchangeFieldanswertxt(this);'>"+result+"</label>");
}
}
function exchangeFieldanswertxt(element)
{
var result = element.innerHTML;
$(element).remove();
$("#answertextdiv").append("<textarea id='answertext' name='answertext' placeholder='Type answer here' rows='2' cols='40' tabindex='6' onBlur='exchangeLabelsanswertxt(this);'>"+result+"</textarea>");
}
Now from above code I want to append all stuff in unique "answertextdiv" id.
If your divs are in a container like:
<div id="container">
<div id="answerdiv 1"></div>
<div id="answerdiv 2"></div>
</div>
you could do something like:
//Call this whenever you need a new answerdiv added
var $container = $("container");
$container.append('<div id="answerdiv ' + $container.children().length + 1 + '"></div>');
If possible, try not to use global variables...they'll eventually come back to bite you and you don't really need a global variable in this case.
You can try something like this to create divs with unique ids.
HTML
<input type="button" value="Insert Div" onClick="insertDiv()" />
<div class="container">
<div id="answerdiv-1">This is div with id 1</div>
<div id="answerdiv-2">This is div with id 2</div>
</div>
JavaScript
var i=2;
function insertDiv(){
for(i;i<10;i++)
{
var d_id = i+1;
$( "<div id='answerdiv-"+d_id+"'>This is div with id "+d_id+"</div>" ).insertAfter( "#answerdiv-"+i );
}
}
Here is the DEMO
You should keep a "global" variable in Javascript, with the number of divs created, and each time you create divs you will increment that.
Example code:
<script type="text/javascript">
var divCount = 0;
function addDiv(parentElement, numberOfDivs) {
for(var i = 0; i < numberOfDivs; i++) {
var d = document.createElement("div");
d.setAttribute("id", "answerdiv"+divCount);
parentElement.appendChild(d);
divCount++;
}
}
</script>
And please keep in mind that jQuery is not necessary to do a lot of things in Javascript. It is just a library to help you "write less and do more".
I used below JQuery code for the same
$("#qnty1").on("input",function(e)
{
var qnt = $(this).val();
for (var i = 0; i < qnt; i++) {
var html = $('<div class="col-lg-6 p0 aemail1"style="margin-bottom:15px;"><input type="text" onkeyup= anyfun(this) class="" name="email1'+i+'" id="mail'+i+'" > </div><div id=" mail'+i+'" class="lft-pa img'+i+' mail'+i+'" > <img class="" src="img/btn.jpg" alt="Logo" > </div> <div id="emailer1'+i+'" class=" mailid "></div>');
var $html=$(html);
$html.attr('name', 'email'+i);
$('.email1').append($html);
}
}
my HTML contain text box like below.
<input type="text" name="qnty1" id="qnty1" class="" >
and
<div class="email1">
</div>
you need a global counter (more generally: a unique id generator) to produce the ids, either explicitly or implicitly (the latter eg. by selecting the last of the generated divs, identified by a class or their id prefix).
then try
var newdiv = null; // replace by div-generating code
$(newdiv).attr('id', 'answerdiv' + global_counter++);
$("#parent").append(newdiv); // or wherever
var newdivcount=0;
function insertDivs(){
newdivcount=newdivcount+1;
var id="answerdiv-"+(newdivcount);
var div=document.createElement("DIV");
div.setAttribute("ID",id);
var input=document.createElement("TEXTAREA");
div.appendChild(input);
document.getElementById('container').appendChild(input);
}
<button onclick="insertDivs">InsertDivs</button>
<br>
<div id="container">
<div id="answertextdiv">
<textarea id="answertext" name="answertext" placeholder="Type answer here" rows="2" cols="40" tabindex="6" onBlur="exchangeLabelsanswertxt(this);"></textarea>
</div>
</div>
Here is the another way you can try
// you can use dynamic Content
var dynamicContent = "Div NO ";
// no of div you want
var noOfdiv = 20;
for(var i = 1; i<=noOfdiv; i++){
$('.parent').append("<div class='newdiv"+i+"'>"+dynamicContent+i+"</div>" )
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
</div>

Livequery and each()

i have an .each() loop doing something on all matching elements. but i also have a way to add those elements.... i'm trying to get livequery to realize that a new element has been added and run it through the same each loop.
here's a general setup:
http://jsfiddle.net/CUURF/1/
basically, how do i use livequery and each together?
ultimately it is so that i can dynamically add tinymce editor textboxes in metaboxes, but i am fairly certain the problem is that my IDs aren't autoincremting on the add/clone, since the new element isn't in the DOM for the each loop.
edit- i think the biggest thing is that i need the index counter that comes standard w/ .each to work w/ livequery?
edit- here's the code from wpalchemy for looping/cloning
/* <![CDATA[ */
jQuery(function($)
{
$(document).click(function(e)
{
var elem = $(e.target);
if (elem.attr('class') && elem.filter('[class*=dodelete]').length)
{
e.preventDefault();
var p = elem.parents('.postbox'); /*wp*/
var the_name = elem.attr('class').match(/dodelete-([a-zA-Z0-9_-]*)/i);
the_name = (the_name && the_name[1]) ? the_name[1] : null ;
/* todo: expose and allow editing of this message */
if (confirm('This action can not be undone, are you sure?'))
{
if (the_name)
{
$('.wpa_group-'+ the_name, p).not('.tocopy').remove();
}
else
{
elem.parents('.wpa_group').remove();
}
the_name = elem.parents('.wpa_group').attr('class').match(/wpa_group-([a-zA-Z0-9_-]*)/i)[1];
checkLoopLimit(the_name);
$.wpalchemy.trigger('wpa_delete');
}
}
});
$('[class*=docopy-]').click(function(e)
{
e.preventDefault();
var p = $(this).parents('.postbox'); /*wp*/
var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1];
var the_group = $('.wpa_group-'+ the_name +':first.tocopy', p);
var the_clone = the_group.clone().removeClass('tocopy');
var the_props = ['name', 'id', 'for'];
the_group.find('input, textarea, select, button, label').each(function(i,elem)
{
for (var j = 0; j < the_props.length; j++)
{
var the_prop = $(elem).attr(the_props[j]);
if (the_prop)
{
var the_match = the_prop.match(/\[(\d+)\]/i);
if (the_match)
{
the_prop = the_prop.replace(the_match[0],'['+(+the_match[1]+1)+']');
$(elem).attr(the_props[j], the_prop);
}
}
}
});
if ($(this).hasClass('ontop'))
{
$('.wpa_group-'+ the_name +':first', p).before(the_clone);
}
else
{
the_group.before(the_clone);
}
checkLoopLimit(the_name);
$.wpalchemy.trigger('wpa_copy', [the_clone]);
});
function checkLoopLimit(name)
{
var elem = $('.docopy-' + name);
var the_match = $('.wpa_loop-' + name).attr('class').match(/wpa_loop_limit-([0-9]*)/i);
if (the_match)
{
var the_limit = the_match[1];
if ($('.wpa_group-' + name).not('.wpa_group.tocopy').length >= the_limit)
{
elem.hide();
}
else
{
elem.show();
}
}
}
/* do an initial limit check, show or hide buttons */
$('[class*=docopy-]').each(function()
{
var the_name = $(this).attr('class').match(/docopy-([a-zA-Z0-9_-]*)/i)[1];
checkLoopLimit(the_name);
});
});
/* ]]> */
</script>
and the markup for inside my metabox:
<div id="testimonials">
<h2>Testimonials</h2>
<a style="float:right; margin:0 10px;" href="#" class="dodelete-testimonials button"><span class="icon delete"></span>Remove All</a>
<div id="wpa_loop-testimonials" class="wpa_loop wpa_loop-testimonials"><div class="wpa_group wpa_group-testimonials first">
<span class="icon delete"></span>Remove
<div class="slide_preview">
<div class="preview_wrap">
<img class="preview" src="" alt="preview" />
</div>
<input type="hidden" name="_sidebar_meta[testimonials][0][testimonial_image]" value="" class="img_src" />
<input type="hidden" name="_sidebar_meta[testimonials][0][slide_image_alt]" value="" class="img_alt" />
<button class="upload_image_button button" type="button"><span class="icon upload"></span>Change Photo</button>
</div>
<div class="slide_text">
<label>About Testimonial</label>
<div class="customEditor minimal">
<textarea rows="5" cols="50" name="_sidebar_meta[testimonials][0][testimonial_desc]">I realized it was ME causing all the problems</textarea>
</div>
</div>
</div> <div class="wpa_group wpa_group-testimonials last tocopy">
<h3 class="slide">Testimonial Name:
<input type="text" name="_sidebar_meta[testimonials][1][testimonial_name]" value="" />
</h3>
<span class="icon delete"></span>Remove
<div class="slide_preview">
<div class="preview_wrap">
<img class="preview" src="http://localhost/multi/wp-content/themes/callingintheone/functions/WPAlchemy/images/default_preview.png" alt="_sidebar_meta[testimonials][1][testimonial_image] Preview" />
</div>
<input type="hidden" name="_sidebar_meta[testimonials][1][testimonial_image]" value="" class="img_src" />
<input type="hidden" name="_sidebar_meta[testimonials][1][slide_image_alt]" value="" class="img_alt" />
<button class="upload_image_button button" type="button"><span class="icon upload"></span>Upload Photo</button>
</div>
<div class="slide_text">
<label>About Testimonial</label>
<div class="customEditor minimal">
<textarea rows="5" cols="50" name="_sidebar_meta[testimonials][1][testimonial_desc]"></textarea>
</div>
</div>
</div></div>
<p style="margin-bottom:15px; padding-top:5px;"><span class="icon add"></span>Add Testimonial</p>
</div>
the .tocopy class gets shifted by the alchemy code to a new hidden (by CSS) and last element
Your problem was that each was not executing with the clik. And after that there was nothing to make it run.
fixed code
Answer: http://jsfiddle.net/morrison/CUURF/6/
Notes:
Does not use livequery. There's no need to in this instance.
Keeps track of existing editors in an array. This is faster than cycling through the DOM every time you want an editor. DOM stuff is slow, arrays are fast. This also gives you easy access to any or all of the editors for other things you might do.
Doesn't cycle when a new editor is created. It simply modifies the new editor to have an id of the last one plus 1. This is a huge performance boost.

Categories