How to reset recursive function in JS? - javascript

I have a function to follow the multistep form:
function multistep() {
function disableBtn() {
continueButton.attr('disabled', true);
}
let select = $('.cf7mls_current_fs select');
let continueButton = $('.cf7mls_current_fs .cf7mls_next');
$('.wpcf7-submit').attr('disabled', false);
$('.preloader-form-wrap').hide();
$('.select-choosen').each(function () {
$(this).removeClass("select-choosen");
});
let selectArr = [];
let currentArr = [];
select.each(function (i, obj) {
currentArr.push($(obj).attr("name"));
})
continueButton.attr('disabled', true);
select.on('change', function () {
if ($(this).prop('selectedIndex') !== 0) {
if ($(this).hasClass("select-choosen") === false) {
$(this).addClass("select-choosen");
selectArr.push($(this).attr("name"));
}
} else {
$(this).removeClass("select-choosen");
selectArr.shift();
disableBtn();
}
console.log(selectArr.length, currentArr.length);
if (selectArr.length === currentArr.length) {
continueButton.attr('disabled', false);
$(continueButton).on("click", function () {
selectArr = [];
$('.preloader-form-wrap').show();
setTimeout(() => {
// if is everything ok, runs function again!
// but array from above will not be reset
multistep();
}, 1000);
});
}
});
}
And the goal of the function is to enable button if every step is filled, and this works, but I have a problem with
let selectArr = [];
When a function calls itself, the inner, variable from (array) above will not be reset? And function will be called multiple times.
First time call function:
$('.btn-open-form').click(function (e) {
....
multistep();
}
And reset again:
function closeForm() {
$(document).click(function (e) {
if ((e.target.className === "overlay-mobile form-active") == true
) {
multistep();
}
}
Function from above will be called on document init.
Well, let selectArr = []; if an array of choosing select items in one tab, and important is to have the length of the array above be equal to a number of displayed selected items.
If the length is the same, the button will be enabled, to jump on another tab.

Related

How do I call the function I pull out from an array in JavaScript?

I'm stuck with a problem, and I can't seem to figure out where to go. The code linked shows an array of 3 different functions. When the button is clicked it randomly splices one item out of the array after each click until the array is empty.
The cut out function shows fine in the console log, but I cannot figure out how to call the function and execute it. Anyone able to help me figuring out the correct way? I figured I'd use the new_numb like this (it does not work):
my_array[new_numb]();
Any help would be greatly appreciated!
Code for reference:
function first_function() {
console.log("test1");
}
function second_function() {
console.log("test2");
}
function third_function() {
console.log("test3");
}
Array.prototype.randsplice = function () {
var randomnr = Math.floor(Math.random() * this.length);
return this.splice(randomnr, 1);//removed extra variable
};
var my_array = [
first_function,
second_function,
third_function,
];
var button = document.getElementById("clicker");
button.onclick = function () {
if (my_array.length > 0) {
var new_numb = my_array.randsplice();
console.log(new_numb);
} else {
console.log('array is empty');
}
};
<button id="clicker">Click</button>
The array prototype function you're using returns an array with 1 index. So you need to access it with [0], then you can use apply() to call it.
new_numb[0].apply(null)
function first_function() {
console.log("test1");
}
function second_function() {
console.log("test2");
}
function third_function() {
console.log("test3");
}
Array.prototype.randsplice = function() {
var randomnr = Math.floor(Math.random() * this.length);
return this.splice(randomnr, 1); //removed extra variable
};
var my_array = [
first_function,
second_function,
third_function,
];
var button = document.getElementById("clicker");
button.onclick = function() {
if (my_array.length > 0) {
var new_numb = my_array.randsplice();
new_numb[0].apply(null)
} else {
console.log('array is empty');
}
};
<button id="clicker">Click</button>

Accessing object property on form submit (vanilla javascript)

I've decided to go back and relearn vanilla js since I've always relied on jquery.
I wanted to make some simple food order form.
My issue is that on my submit method, the "this" will refer to the form being submitted, rather than my placeOrder object.
When the order is submitted, I wanted to push it to my orders array which is inside cacheDom. Obviously, it can't use a push method on a form object.
can someone offer advice on how to go about this?
(function () {
var placeOrder = {
init: function() {
this.cacheDom();
this.bindEvents();
},
cacheDom : function() {
this.orderForm = document.getElementById('place-order-form');
this.elements = this.orderForm.elements;
this.orders = [];
},
bindEvents: function() {
if(this.orderForm.addEventListener){
this.orderForm.addEventListener("submit", this.submitOrder, false);
} else if (this.orderForm.attachEvent){
this.orderForm.attachEvent('onsubmit', this.submitOrder);
}
},
submitOrder: function(e) {
// this refers to the form being submitted
e.preventDefault();
var elements = this.elements;
var order = {};
for (var i = 0; i < elements.length; i++) {
if (elements[i].tagName !== 'BUTTON') {
if (elements[i].name === 'name') {
order.name = elements[i].value;
} else if (elements[i].name === 'food') {
order.food = elements[i].value;
}
}
}
//this.orders.push(order);
console.log(this);
}
};
placeOrder.init();
}());

onchange event handler triggering twice

I have written the below jQuery functions to invoke filters on a datatable. But the "change" jQuery function seems to seems to invoke two times for a single click , hence, if i try to turn off one of the filter, it will immediately turn itself back on.
Function:
$(document).ready(function () {
var table = $('#example').DataTable({
rowReorder: {
selector: 'td:nth-child(2)'
},
responsive: true,
initComplete: function () {
var filters = $('div[id$=referalFilters]').find('input:checkbox');
filters.each(function () {
dict.push({
key: $(this).prop('name'),
value: $(this).prop('checked')
});
$(this).change(function () {
var currentName = $(this).prop('name');
for (var i = 0; i < dict.length; i++) {
if (dict[i].key == currentName) {
if (dict[i].value == true) {
dict[i].value = false;
} else {
dict[i].value = true;
}
}
}
for (var i = 0; i < dict.length; i++) {
if (dict[i].value == true) {
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
var currentStatus = data[3];
var found = false;
for (var i = 0; i < dict.length; i++) {
if (currentStatus == String(dict[i].key)) {
if (dict[i].value == true) {
found = true;
}
}
}
if (found) {
return true;
}
return false;
})
}
}
table.draw();
});
});
//this.api().columns().every( function () {
// var column = this;
//} );
}
});
});
I will appreciate, if someone could let me know what triggers the change function multiple times.
Here is the jsfiddle: https://jsfiddle.net/a81h11tc/ . In Js fiffle, the button seems to toggle but, the filtering does not happen.
As far as I can tell, your problem was an undefined variable, dict inside initComplete. After I added var dict = []; before var filters = ..., it worked like a charm. (My understanding is that you wanted the column Status to hide the rows that contain the value of the clicked filter. If you want the opposite, modify your code accordingly.) Here is a JSFiddle of the altered code, it should work the way you wanted.
TIP: By the way, remember to always check the browser's console as in most cases you can see the proper error messages for stuff like this (i.e. for your code it said RefereceError: dict is not defined, which was basically the only problem your code had).

how to filter on a JavaScript object based on its attributes

I have a JavaScript object
var items = { ids : [
{
label: "red",
complete: true
},
{
label: "green",
complete: false
},
{
label: "blue",
complete: true
}
]
}
I need to filter out based on the complete attribute when I click on the complete button or when I click on all button it show show me all the entries.
How can I do this in the same function
I have this function which takes the list DOM element and creates the entries accordingly. I am wondering how could I write this function such that it could filter on the complete status or print all the entries in the redraw function itself.
var redraw = function(items) {
list.innerHTML='';
for (var id in items) {
draw(model.todos[id], list);
}
};
var draw = function(Obj, container) {
var el = Template.cloneNode(true);
el.setAttribute('data-id', Obj.id);
container.appendChild(el);
update(Obj);
});
}
Add a new function called filterItems that accepts the items array and key and value parameters and returns a filtered array based on those parameters. Then, just call it from redraw with the correct arguments.
function filterItems(items, key, value) {
return items.ids.filter(function (el) {
return el[key] === value;
});
}
var redraw = function(items) {
list.innerHTML='';
items = filterItems(items, 'complete', true);
for (var id in items) {
draw(model.todos[id], list);
}
};
DEMO
If you're using Underscore, this is pretty simple
var completedItems = {
ids: _.filter(items.ids, function (id) { return id.complete; })
};
Otherwise you could write it by hand
var completedItems = {
ids: (function (ids) {
var arr = [];
ids.forEach(function (id) {
if (id.complete) arr.push(id);
});
return arr;
})(items.ids)
};
var result = [];
for(var item in items.ids){
if(items.ids[item].hasOwnProperty("complete") &&
items.ids[item].complete === true){
result.push(item);
}
}
you can use this to filter out the items based on the complete attribute.
demo

jQuery append issue without removing original elements

I just wrote some code for practicing my jQuery. When I wrote this code, I found out it works fine with only using append() and without removing any original tr elements in the table. How does it work — could someone explain it to me? here is the complete code. Thanks!
Here is my jQuery code:
$(document).ready(function () {
var list = a();
var last = $('#table').find("tr").length;
$('#table').find("tr").each(function (index, element) {
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
});
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};
Be aware, appending already existing element just move it. I guess maybe you want to clone it:
jsFiddle
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i].clone(true));
}
};
But then, reset function is misnamed...
$(document).ready(function () {
waits for the page and all elements to be loaded
var list = a();
var last = $('#table').find("tr").length;
sets up specific variables, in this case list is the function a() defined later in the page and last gets the length of the last tr in the table.
$('#table').find("tr").each(function (index, element) {
sets up a loop through each tr element on in the table with id #table
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
Because you are inside the loop, $(this) represents the tr that the loop is currently on. It then prepends a button and adds a click listener on this button. When the button is pressed, it will call the function up, which is defined later on, with the buttons parent as the first parameter and last (defined earlier) as the second
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
This adds another button, but calls down() instead of up()
});
End of the loop.
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
This adds a button before the table that when clicked calls the reset function with list as the only parameter, list is set to a().
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
This function is called when moving an item up, it first checks to see if the index is not 0 (so not the first element as this couldn't be moved up) if it is not then it puts the previous tr after the variable tr. Which in this case is the parent to the button (or the current tr)
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
Works exactly the same as the function above, but in the opposite direction.
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
This function is saved in the variable reset, it loops through each tr (defined in a()) and appends it to the table,
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};
This function creates and returns an array which loops through each tr and adds to that array. So we know the original state and can return to it.

Categories

Resources