Deleting dynamically created rows in Knockout.js - javascript

I'm using knockout.js 2.3.0 and I have a table with dynamically added rows and select lists in each of these rows. Upon changing a date input, the select lists populate with different content. Because different dates will populate the lists with different content, I want to remove any previously added rows because the content may not be accurate.
The issue I'm having is that not all of the rows are being removed. Ex: If I have more than 4 rows, there will always be 2 remaining. The only time all rows are cleared is when there is only 1 row to start with.
Here's the subscribed function for deleting the rows
self.date.subscribe(function() {
//I also tried setting the loop length to a very long number but the same results happened each time
for (i = 0; i < self.customers().length; i++){
self.customers.remove(self.customers()[i]);
}
//now populate the select list and add an empty row - commented out for testing to make sure rows are being deleted
//setCustomerList(self.date());
//self.customers.push(new AddCustomer(self.customerList[0]));
});
I was just testing to see what would happen, and the only way I've gotten all of the rows to remove is by adding multiple for loops which obviously isn't desirable.
Is there a simpler way to remove all dynamically added rows?

If you want to remove all the items in an observable array, use the removeAll method:
self.customers.removeAll();
If you really want to use a loop, you could do so by continuously removing the last (or first) item until there are none left:
while (self.customers().length) {
self.customers.pop();
}

I think you need to reverse the for loop and remove the items from the bottom up. the problem with your code is that the each time an item is removed the length of the array changes.
self.date.subscribe(function() {
var customerLength = self.customers().length
for (i = customerLength ; i >= 0; i = i - 1){
self.customers.remove(self.customers()[i]);
}
});

Related

Dynamically added rows to table after filtering are not hiding

I'm using DataTable API and jquery to construct a table after getting its rows from the server. Then I press the btn to load other rows and add the to the end of the table. The trouble is when I hide certain columns: the initial rows get rid of triggered columns but those which are loaded later aren't affected by filters. How to fix this? After research I found out that when filtering the function gets all the rows not the initial ones.
var data = $(this).dataTable().toArray();
if ($this.prop("checked") === false) {
data.forEach(function (element) {
$(element).DataTable().columns().column(column).visible(false);
});
} else {
data.forEach(function (element) {
$(element).DataTable().columns().column(column).visible(true);
});
}
Loading the remaining rows
var tbody = $("#tbody-" + $this.attr("data-parent-id"));
var dt = tbody.parents(".bizon-datatable").DataTable();
$(result).filter("tr").each(function (i, v) {
dt.row.add($(v));
});
tbody.append(result);
The key is understanding that each executes against the set of items that are found at the moment that selector runs. So if you have 10 rows initially and each executes, it will apply to 10 rows, and any added later will not have the conditions applied by each.
The same goes for filter. It applies to the elements that are returned by the selector at the time the selector executes--not to anything added later. The selector only selects DOM elements that match at the moment it runs and doesn't apply to any future DOM elements that are added. So you have to re-select DOM elements after you've added elements if you want to apply filters or other conditions to all current DOM elements.
To fix this, you would need to re-apply the filter after adding rows or re-run the each if you have added rows.

How to edit the ID of each button in a class if a condition is true in JavaScript?

I'm using ChartJS to generate a pie chart in that elements are added every time the user clicks a specific button (I have 14 buttons that trigger the adding of a specific element in the pie chart, each one triggers a function that adds info to 3 arrays as needed in order for the chart to work.
Every time the user clicks a button a new one is created in a div that contains all the elements that are present in the chart because I want them to be able edit or delete the elements as needed.
To know what which elements from my arrays is edited by which edit button I'm using a variable named btnctr that I initialized with 0 at the beginning of my JS file. That variable gives every new ”edit button” an ID and then then increments, like this:
function CreateEditButton() {
var buttonnode= document.createElement('input');
buttonnode.setAttribute('type','button');
buttonnode.setAttribute('id',btnctr);
...
$("#rotationelements").append(buttonnode);
$("#rotationelements").append(' ');
btnctr++;
};
My problem is that I also have to make deleting elements possible. I'm using splice for deleting elements from the arrays, but that also messes up the position of other elements and my edit buttons become useless.
I want to also edit the IDs of my buttons when I delete elements, because I need them to be in sync.
Here's what I've come with so far:
// Get editbuttons
var editbuttons = document.getElementsByClassName('editbtn');
// Delete element
function deleteElement (x) {
names.splice(x,1);
dataset.splice(x,1);
colors.splice(x,1);
chart1.update();
time=time-length[x];
length.splice(x,1);
UpdateTime();
var delbtn=$("#"+x);
$(delbtn).remove();
var newid=x;
for (var i=0; i<editbuttons.length;i++) {
if (editbuttons[i].id>x) {
editbuttons[i].id=newid;
newid++;
btnctr=newid++;
}
}
}
Thanks!
Lulian, inside of your for loop it looks like you are only changing the id's of editbtns after the one that was deleted above. You may want to try taking out the if statement and replacing "newid" with "i":
for (var i=0; i<editbuttons.length;i++) {
// if (editbuttons[i].id>x) {
editbuttons[i].id=i;
//newid++;
btnctr=i;
// }
}
This way you can re-initialize all of you editbtn's and btnctr to match from beginning to end.

Assigning Row_Ids to dynamically added rows in Datatables

I am working on making an editable Datatable using Jeditable. I need to be able to dynamically add rows, which I have successfully done. By default, it appears that Datatables will add everything with a row_id of 0, which makes it impossible to differentiate added rows from each other.
So I am working on a function that assigns the row_id. There are no errors, but it also does not seem to work as it still returns a row_id of 0 for all added rows.
$('#addRow').on( 'click', function () {
var rowIndex = $('#example').dataTable().fnAddData([ "column1Data", "column2Data"]);
var row = $('#example').dataTable().fnGetNodes(rowIndex);
$(row).attr('id', row_id_counter);
row_id_counter ++;
Entire code:
http://jsfiddle.net/j2frzerj/
I tested your code in the fiddle provided, and it is adding new table rows with sequential id's, starting with index 0. I am not seeing any duplicate id's of 0?
http://prntscr.com/ew3tg9
http://prntscr.com/ew3tlr

Odd behavior when removing action buttons from a table in JavaScript

I have a page that builds a table using DataTables, and each row has an Action Button that adds some data (an ID, just an int) from that row to a list. To keep users from clicking each action button multiple times, I made it so a row's button is removed the first time you click it. This worked great until I realized the buttons come back if you switch to the next page of the table and then switch back to the first page.
To fix this, I wrote some JS to compare each row to my list of data, and if that row's data is already in the list, it removes that row's action button. This happens each time the table is reloaded (for example, when you switch to a different page of the table and back again) using DataTable's draw.dt function.
The problem is, when I switch pages and the JavaScript goes to work removing buttons, for some reason it skips every other row. For example, if I click (thus removing) the first three rows' action buttons, switch pages and switch back, my JS removes the action buttons on row 1, 3, and 5 instead of rows 1, 2, and 3. It's so consistent that it has to be some kind of simple looping error due to my sloppy JS skills, but I can't find it.
Here is the code:
$(document).on('draw.dt', function () {
var $allSerialNumbers = $('.box-electrode'); // This is a list of all the rows' action buttons / ID's
$('#electrodes li').each(function (i, li) { // This is the list of ID's I'm comparing to
var $id = $(li).data('id');
for(var index = 0; index < $allSerialNumbers.length; index++){
if($id == $allSerialNumbers.eq(index).attr('data-id')){ // For each item in my ID list, run through all the rows and see if any Action Button ID's match any on the list
$('.box-electrode').eq(index).remove(); // If they do match, remove that Action Button
}
}
})
});
I'm not an expert on JQuery, but could remove() in your last line be re-sizing the list so that the element which used to be at index 1 is now at index 0, causing you to skip it when you increment the index?

Access rendered items

Playing around with Slickgrid. But got some questions that I'm not figurate out.
I have made an Regex filter on two X cells, and it works surprisingly well.
But for every time you filter or make other actions i want to flash all incorrect fields with cellFlash or highlighter.
Atm i have made a formatter with same regex as filter uses but it seems not 100% correct.
The problem when i'm using cellFlash is that it trigger the animation on ALL rows not only the rows thats rendered.
I'm not sure that i'm triggering the flashcell on correct callback/stage, I did it on my filter function i saved all incorrect rows in an array then i loop them throught and trigger flash.
So is it possible to get all items thats rendered in Viewport? Haven't find any information about this. Only data i can get out from getRenderedViewport.. is pxls. getRenderedRange() or getViewport()..
If you need to do processing on each data item in the current slick grid viewport, you can use getRenderedRange() to get the range of data item indexes that are rendered. You could then use that to get each visible data item
function forEachItemInViewport(fn) {
var range = slickGrid.getRenderedRange();
var bottom = range.bottom;
while(bottom--) {
var dataItem = slickGrid.getDataItem(bottom);
fn(dataItem);
}
}
forEachItemInViewport(function (item) {
// do your work on each item in viewport
});

Categories

Resources