How do I make my counter work correctly? - javascript

I have a function that adds div when I press a button.
I have a counter re-setting logic written in the removal which should re-count all my names.
my problem is that when I add say 3 items, and remove the 2nd Item, my 3rd item does not rename itself.
what am I doing wrong with this?
$(function () {
var rowItem = $(".row", $(".formitems")); //select all rows from class formitems
$(".formitems").on("click", ".addRow", function () {
var newItem = rowItem.clone(),
rowIndex = $(".row", $(".formitems")).length;
$(":input", newItem).each(function (c, obj) {
$(obj).attr("name", $(obj).attr("crap") + rowIndex);
});
$(".formitems").append(newItem); // adds At the end of the container
}).on("click", ".removeRow", function () {
if ($(".row", $(".formitems")).length > 1) {
var target = $(this).parent().parent().parent().parent(".row");
target.slideUp(function () {
target.remove();
});
}
for (i = 0; i < $(".row", $(".formitems")).length; i++) //select our div called //formitems and then count rows in it
{
rowobj = $(".row", $(".formitems"))[i];
$(":input", rowobj).each(function (c, obj) {
$(obj).attr("name", $(obj).attr("crap") + i);
})
}
});
});
EDIT : Ok, So I put up alerts just before and after using remove(). Does jquery takes time to re-calulate all the properties? If yes, are they cached? If yes, can I force refresh them.?

Consider simplifying your life.
<input type="text" name="blah[]" />
You can have as many of these elements as you want. The server will receive an array of values, meaning you don't have to manually count them.

As far as i understand, you want to update the 'name's after the removal. But the code does the remove() asynchronously when slideUp() completed, while the renaming is invoked immediately after invoking the slideUp(), before remove() is called.
You can solve this by placing the renaming code after the call to remove(), inside the slideUp() handler:
}).on("click", ".removeRow", function () {
if ($(".row", $(".formitems")).length > 1) {
var target = $(this).parent().parent().parent().parent(".row");
target.slideUp(function () {
target.remove();
// rename now!
for (i = 0; i < $(".row", $(".formitems")).length; i++) {
rowobj = $(".row", $(".formitems"))[i];
$(":input", rowobj).each(function (c, obj) {
$(obj).attr("name", $(obj).attr("crap") + i);
})
}
});
}
});

Related

How to not lose my event listener in Javascript each time I use .insertBefore?

I am attempting to move a div (which contains text and other elements) each time the user clicks the up or down arrow. The goal is to simply allow users to rearrange divs to their liking, based on clicking the appropriate arrows.
The issue I'm running into is -- when I use .insertBefore to rearrange these elements? It only allows me to click the arrow and perform that action once. After that, nothing happens. It appears that I'm losing my event listener each time I do this. Is there a way for me to somehow say: "Keep that old event listener after it gets moved?"
Here is the code:
for (let i = 0; i < NumberOfSavedIdeas; i++) {
document.getElementById('DeleteIdeaButton' + [i]).addEventListener('click', () => {
var DivToDelete = document.getElementById("SavedIdeaDiv" + [i]);
DivToDelete.remove();
let ArrayContentMatch = FullSavedIdeasArray.indexOf(FullSavedIdeasArray[i])
FullSavedIdeasArray.splice(ArrayContentMatch, 1);
chrome.storage.local.set({SavedIdeas: FullSavedIdeasArray});
});
document.getElementById('MoveIdeaUp' + [i]).addEventListener('click', () => {
var DivToMove1 = document.getElementById("SavedIdeaDiv" + [i]);
var ParentDiv1 = document.getElementById("DivTesting");
ParentDiv1.insertBefore(DivToMove1, ParentDiv1.children[i-1]);
});
document.getElementById('MoveIdeaDown' + [i]).addEventListener('click', () => {
alert('move down')
});
}
Thanks!
This is because new element doesn't exist in DOM when all event listeners are set. Add an event listener on document instead of an element.
It should be wrapped like:
for (let i = 0; i < NumberOfSavedIdeas; i++) {
document.body.addEventListener( 'click', function (e) {
if (e.target.id == 'YourId' + [i]) {
yourFunction();
}
} );
}

Changing text inside of a dynamically created element

I want to change the text inside of an element for dynamically created elements. i = 2 because that's Why is it not working?
var loanName = function() {
for(var t=1; t < i; t++) {
$('body').on('keyup', '.loanNameV'+t, function () {
var loanN = $('.loanNameV'+t).val();
$('.nameLoan'+t).text(loanN);
});
}
};
$('body').on('keyup', '[class^="loanNameV"]', function () {
var numbesideclass = ($(this).attr('class').split('loanNameV'))[1];
var loanN = $(this).val();
$('.nameLoan'+numbesideclass).text(loanN);
});
Note: this code will work if you don't have another class for loanNameV elements like class="loanNameV1 anotherclass anotherclass" in this case this code will not work as expected

how to make the jquery function load before one ajax function finish

How do I fire one event before the previous function completed its function?
I have the following AJAX code :
var BrainyFilter = {
//...
init: function (opts) {},
changeTotalNumbers: function (data) {
jQuery(BrainyFilter.filterFormId).find('.bf-count').remove();
jQuery(BrainyFilter.filterFormId).find('option span').remove();
jQuery(BrainyFilter.filterFormId).find('select').removeAttr('disabled');
jQuery('.bf-attr-filter').not('#bf-price-container').find('input, option')
.attr('disabled', 'disabled')
.parents('.bf-attr-filter')
.addClass('bf-disabled');
if (data && data.length) {
for (var i = 0; i < data.length; i++) {
jQuery('.bf-attr-' + data[i].id + ' .bf-attr-val').each(function (ii, v) {
if (jQuery(v).text() == data[i].val) {
var parent = jQuery(v).parents('.bf-attr-filter').eq(0);
var isOption = jQuery(v).prop('tagName') == 'OPTION';
var selected = false;
if (isOption) {
jQuery(v).removeAttr('disabled');
selected = jQuery(v)[0].selected;
} else {
parent.find('input').removeAttr('disabled');
selected = parent.find('input')[0].checked;
}
parent.removeClass('bf-disabled');
if (!selected) {
if (!isOption) {
parent.find('.bf-cell').last().append('<span class="bf-count">' + data[i].c + '</span>');
} else {
jQuery(v).append('<span> (' + data[i].c + ')</span>');
}
}
}
});
}
jQuery('.bf-attr-filter input[type=checkbox]').filter(':checked')
.parents('.bf-attr-block').find('.bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text();
jQuery(v).text(t);
});
// since opencart standard filters use logical OR, all the filter groups
// should have '+' if any filter was selected
if (jQuery('.bf-opencart-filters input[type=checkbox]:checked').size()) {
jQuery('.bf-opencart-filters .bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text().replace('+', '');
jQuery(v).text(t);
});
}
}
// disable select box if it hasn't any active option
jQuery(BrainyFilter.filterFormId).find('select').each(function (i, v) {
if (jQuery(v).find('option').not('.bf-default,[disabled]').size() == 0) {
jQuery(v).attr('disabled', 'true');
}
});
},
//...
} // close the BrainyFilter
I also have another jQuery file running to get the bf-count value using $('.bf-count').text().
When the page load, the bf-count value is empty. Since the code above inject the bf-count, I will need to wait until it finishes the for loop in order to get the bf-count value.
What is the best way to approach this?
without knowing how the second js file is loaded, I can only give you a guesstimate suggestion.
If you want to run the second js file code after the page is fully loaded, you can wrap the code in:
jQuery(window).load(function(){
//your code here. runs after the page is fully loaded
});
jQuery documentation: http://api.jquery.com/load-event/
"The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object."

How to do queue of messages that shows in one div after delay?

How to implement queue which elements after shown with delay fadeOut and split out from array? This funcionallity should be provide message shows one after another in the same div even when showAlertBarMessages() is invoked many diffrent times like in FIFO. For now I can't clean shown elements. I spend one day and I don't know.
My current solution and working example: http://jsfiddle.net/ZtY38/:
var msgQueue = [];
var i = 1;
$('#add-msg').click(function () {
msgQueue.push("Message number " + i);
showAlertBarMessages();
i++;
});
function showAlertBarMessages() {
msgQueue.map(function (msg, idx) {
return function () {
var el = $('<div />').html(msg).addClass('msg').insertBefore('#msg-sequentially');
$(el).click(function () {
console.log("fadeOut and remove from queue");
});
if (idx > 0) {
return el.delay(2000).fadeIn(500).promise()
} else {
return el.fadeIn(500).promise()
}
};
}).reduce(function (cur, next) {
console.log("alredy shown fadeOut and remove from queue");
return cur.then(next);
}, $().promise());
}
HTML:
<div id="msg-sequentially"></div>
<button id="add-msg">Add next message</button>
Instead insertBefore should be append to #msg-sequentially but this doesn't work.
Or is there any completely other approach for this solution?
You could try that and see if it's fitting your needs:
DEMO
function showAlertBarMessages() {
var msg = msgQueue[0];
if (!$('#msg-sequentially').find(':visible').length) {
var el = $('<div />').html(msg).addClass('msg').appendTo('#msg-sequentially');
el.fadeIn(500).promise().done(function () {
$(this).delay(2000).fadeOut().promise().done(function () {
$(this).remove();
msgQueue.splice(0,1);
if(msgQueue.length) showAlertBarMessages();
});
});
}
}

Use Javascript string as selector in jQuery?

I have in Javascript:
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
}
How can I continue in jQuery like:
$(function() {
$(vst).'click': function() {
....
}
}
NO, like this instead
$(function() {
$(vst).click(function() {
....
});
});
There are other ways depending on your version of jquery library
regarding to this, your vst must need to be an object which allow you to click on it, and you assign a class or id to the object in order to trigger the function and runs the for...loop
correct me if I am wrong, cause this is what I get from your question.
$(function() {
$(vst).click(function() {
....
}
})
You can use any string as element selector param for jQuery.
Read the docs for more information.
http://api.jquery.com/click/
http://api.jquery.com/
You can pass a String in a variable to the $() just the way you want to do it.
For example you can do:
var id = 'banner';
var sel = '#'+id;
$(sel).doSomething(); //will select '#banner'
What's wrong is the syntax you are using when binding the click handler. This would usually work like:
$(sel).click(function(){
//here goes what you want to do in the handler
});
See the docs for .click()
Your syntax is wrong, but other than that you will have no problem with that. To specify a click:
$(function() {
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
$(vst).click(function (evt) {
...
});
}
})
Note that since vst is changing in the loop, your event code should also be placed in the loop.
EDIT: Assuming you want the same thing to happen for each image and each div, you could also do something like this:
$(function () {
function imgEventSpec($evt) {
// image clicked.
}
function divEventSpec($evt) {
// div clicked.
}
for (var idx = 0; idx < img_arr.length && idx < div_arr.length; idx ++) {
$("#" + img_arr[idx]).click(imgEventSpec);
$("#" + div_arr[idx]).click(divEventSpec);
}
});

Categories

Resources