Inquiry regarding array reactivity in Vue.js 2 - javascript

I have written a grid component that supports child rows, i.e a togglable row with a cell that spans the entire width of the table, under each normal row. In order to keep track of the child rows state I am using a data property called openChildRows which defaults to an empty array. When the user clicks on the toggle icon which is present on the first column of each row, the child row of that row opens. An additional click closes it. The openChildRows array contains the ids of the open rows.
The issue I am having is that when I use a component for the child row, all open rows that come after the one toggled will be remounted. This is clearly inefficient, especially if the child row component sends an ajax request when mounted. Ideally, what I would want is that only the new child row will be mounted.
I have written the grid using JSX for templates. Below is the relevant code:
Rows template:
module.exports = function(h, that) {
var rows = [];
var columns;
var rowKey = that.opts.uniqueKey;
var rowClass;
var data = that.source=='client'?that.filteredData:that.tableData;
var recordCount = (that.Page-1) * that.limit;
data.map(function(row, index) {
index = recordCount + index + 1;
columns = [];
if (that.hasChildRow) {
var childRowToggler = <td><span on-click={that.toggleChildRow.bind(that,row[rowKey])} class={`VueTables__child-row-toggler ` + that.childRowTogglerClass(row[rowKey])}></span></td>;
if (that.opts.childRowTogglerFirst) columns.push(childRowToggler);
}
that.allColumns.map(function(column) {
let rowTemplate = that.$scopedSlots && that.$scopedSlots[column];
columns.push(<td class={that.columnClass(column)}>
{rowTemplate ? rowTemplate({ row, column, index }) : that.render(row, column, index, h)}
</td>)
}.bind(that));
if (that.hasChildRow && !that.opts.childRowTogglerFirst) columns.push(childRowToggler);
rowClass = that.opts.rowClassCallback?that.opts.rowClassCallback(row):'';
rows.push(<tr class={rowClass} on-click={that.rowWasClicked.bind(that, row)} on-dblclick={that.rowWasClicked.bind(that, row)}>{columns} </tr>);
// Below is the code that renders open child rows
if (that.hasChildRow && this.openChildRows.includes(row[rowKey])) {
let template = this._getChildRowTemplate(h, row);
rows.push(<tr class='VueTables__child-row'><td colspan={that.allColumns.length+1}>{template}</td></tr>);
}
}.bind(that))
return rows;
}
Toggle method code:
module.exports = function (rowId, e) {
if (e) e.stopPropagation();
if (this.openChildRows.includes(rowId)) {
var index = this.openChildRows.indexOf(rowId);
this.openChildRows.splice(index,1);
} else {
this.openChildRows.push(rowId);
}
};
The _getChildRowTemplate method:
module.exports = function (h, row) {
// scoped slot
if (this.$scopedSlots.child_row) return this.$scopedSlots.child_row({ row: row });
var childRow = this.opts.childRow;
// render function
if (typeof childRow === 'function') return childRow.apply(this, [h, row]);
// component
return h(childRow, {
attrs: {
data: row
}
});
};

I changed:
if (that.hasChildRow && this.openChildRows.includes(row[rowKey])) {
let template = this._getChildRowTemplate(h, row);
rows.push(<tr class='VueTables__child-row'><td colspan={that.allColumns.length+1}>{template}</td></tr>);
}
to:
rows.push(that.hasChildRow && this.openChildRows.includes(row[rowKey])?
<tr class='VueTables__child-row'><td colspan={that.allColumns.length+1}>{this._getChildRowTemplate(h, row)}</td></tr>:h());
And voila!

Related

How to get checked rows' values from html table on a sidebar using GAS?

I have a table whose rows consist of 3 columns. 1º is a checkbox, 2º contains the colors and the 3º contains the hex.
As the user selects the colors desired by ticking the checkboxes, i imagine the colors being pushed into an arrat, that will be written to a cell as the user clicks on the save button.
I've borrowed this snippet from Mark, but it doesn't seem to run in my context:
var checkboxes = document.getElementsByTagName("input");
var selectedRows = [];
for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i];
checkbox.onclick = function() {
var currentRow = this.parentNode.parentNode;
var secondColumn = currentRow.getElementsByTagName("td")[1];
selectedRows.push(secondColumn);
};
console.log(selectedRows)
}
This is the javascript part running to load and populate the table and I'm not sure where the above snippet woud go into:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
/**
* Run initializations on sidebar load.
*/
$(function() {
// Assign handler functions to sidebar elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
google.script.run
.withSuccessHandler(function (record) { //<-- with this
showRecord(record);
})
.withFailureHandler(
function(msg, element) {
showStatus(msg, $('#button-bar'));
element.disabled = false;
})
.getRecord();
});
/**
* Callback function to display a "record", or row of the spreadsheet.
*
* #param {object[]} Array of field headings & cell values
*/
function showRecord(record) {
if (record.length) {
for (var i = 0; i < record.length-1; i++) {
// Adds a header to the table
if(i==0){
$('#sidebar-record-block').append($($.parseHTML('<div class="div-table-row"><div class="div-table-header">Sel</div><div class="div-table-header">Color</div><div class="div-table-header">Hex</div></div>')));
}
// build field name on the fly, formatted field-1234
var str = '' + i;
var fieldId = 'field-' + ('0000' + str).substring(str.length)
// If this field # doesn't already exist on the page, create it
if (!$('#'+fieldId).length) {
var newField = $($.parseHTML('<div id="'+fieldId+'"></div>'));
$('#sidebar-record-block').append(newField);
}
// Replace content of the field div with new record
$('#'+fieldId).replaceWith('<div id="'+fieldId+'" class="div-table-row"></div>');
$('#'+fieldId).append('<input type="checkbox" class="div-table-td" id=CB"'+fieldId+'"name="checkBox" </input>')
.append($('<div class="div-table-td">' + record[i].heading + '</div>'))
.append('<div class="div-table-td">' + record[i].cellval + '</div>')
}
}
}
</script>
Sample of how to get the checked tickboxes an button click
Assuming all your checkboxes are tied to a row, you can loop through all checkboxes with a query selector,
access their checked status
and save the indices of those checkboxes.
Those indices will be the same as when looping through the corresponding table rows.
Sample implementing a button click event:
var saveButton = document.getElementById("myButtonId");
saveButton.onclick = function(){
var checkedRowIndices = [];
$('input[type=checkbox]').each(function( index ) {
if($(this)[0].checked{
checkedRowIndices.push(index);
}
});
};
//now get the rows with those indeices and do something with them

Saving state of expanded child rows in datatable after reload div

My application is working with database and when data in DB changes, my page is reloading. To show data I used bootstrap datatable. My datatable always has one child, hidden column and I want to save expanded state before refreshing page. I did it but I have 2 problems:
When I am expanding rows after reload, child rows has also expanded icon like parent-rows
expanded-row icon doesn't change
Here is a example what I want and what I get.
I was trying dynamically change tr class but it didn't work or just I was making it wrong.
My js code:
<script type="text/javascript">
function refreshtable() {
var openRows = [];
var table = $('#table').DataTable();
table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
var tr = rowIdx;
var row = table.row(tr);
if (row.child.isShown()) {
openRows.push(rowIdx);
}
})
$('#tablediv').hide();
$('#load').show();
$("#tablediv").load("mainrf.jsp");
setTimeout(function(){
var table = $('#table').DataTable();
var arrayLength = openRows.length;
var roww;
for (var i = 0; i < arrayLength; i++) {
roww = table.row(openRows[i]);
roww.child(format(roww.data())).show();
}
}, 500);
}
function format(value) {
var temprow = value.toString();
var pieces = temprow.split(/[\s,]+/);
var piece = pieces[pieces.length-1];
return '<table><tbody><tr><td>Comments: ' + piece + '</td></tr><tbody></table>';
}
</script>
I did it, by changing for loop. Now I am just triggering expand button click.
for (var i = 0; i < arrayLength; i++) {
$( 'td:first-child', table.row( openRows[i]).node() ).trigger( 'click' );
}

Disable table-hover on certain row in Angular Bootstrap

I have a table that displays selectable information. Sometimes there are child rows that are selectable.
I want the parent rows to be selectable if they have no children, otherwise only the child rows should be selectable. This is a select-only-one type of table.
This table works as expected. However, I want to disable the hover on the non-selectable parent row.
Here is a working plunker: http://plnkr.co/edit/Z0cgHKx2qxpekEE36O1K?p=preview
Here is an example of some of the code in the controller:
scope.parentSelected = [];
$scope.childSelected = [];
$scope.getParentDetails = function(parentObj) {
if(!parentObj.jobs || parentObj.jobs.length === 0) {
nonSelectOtherRows();
var index = $scope.pro.indexOf(parentObj);
$scope.parentSelected[index] = !$scope.parentSelected[index];
// get details for parent row using parentObj
console.log(parentObj);
}
};
$scope.getChildDetails = function(parentObj, childObj) {
nonSelectOtherRows();
var parentIndex = $scope.pro.indexOf(parentObj);
var childIndex = parentObj.jobs.indexOf(childObj);
$scope.childSelected[parentIndex] = [];
$scope.childSelected[parentIndex][childIndex] = !$scope.childSelected[parentIndex][childIndex];
// get details for parent and child rows using parentObj and childObj.
// childObj is the childRow selected
console.log(parentObj);
console.log(childObj);
}
Remove table-hover attribute.
Implement your ng-mouseover and ng-mouseleave functions.
$scope.hoverIn = function(row){
row.hoverEdit = true;//check selectable or not
};
$scope.hoverOut = function(row){
row.hoverEdit = false;
};
Define css class for hover.
.custom-hover {
background-color: red;
}
Finally add class to your tr
`'custom-hover': x.hoverEdit`
here is: http://plnkr.co/edit/CJxi86GyM8jMbtehPQgU?p=preview
Add your selectable control inside hoverIn and it will be work.
try to use ng-class. it will help you.

Hide row in Extjs grid view not work

I need to hide duplicate rows in master/detail grid. I found this fiddle http://jsfiddle.net/tPB8Z/1465/ that hides some cells based user choice, but when I applied this in my code http://jsfiddle.net/alebotello/axvhtrcL/21/ method addRowCls() from view grid, it did not work for rows. Master and detail grids shared same store, and I only want to change rows visibility in master grid, without modify store or create a new one.
In master grid listeners:
afterrender: function (comp) {
var st = comp.getStore();
var arr = [];
var i = 0;
var view = comp.getView();
st.each(function (record) {
// console.log(record);
if (arr.indexOf(record.data['idOrden']) === -1) {
arr.push(record.data['idOrden']);
} else {
view.removeRowCls(record, 'x-grid-view');
view.addRowCls(record, 'oculto');
// console.log(view);
}
i++;
});
css
.oculto{
display: none;
}
Fix is very simple, change the master grid listener from 'afterrender' to 'viewready'.
For most of the Ext.view.View based Components like Grid, List developers should use viewready events instead of afterrender to perform post render DOM manipulations.
This is documented in their API Doc and Guides.
viewready: function (comp) {
var st = comp.getStore();
var arr = [];
var i = 0;
var view = comp.getView();
st.each(function (record) {
debugger;
if (arr.indexOf(record.data['idOrden']) === -1) {
arr.push(record.data['idOrden']);
} else {
view.removeRowCls(record, 'x-grid-view');
view.addRowCls(record, 'oculto');
console.log(view);
}
i++;
});
}
Working example forked from above jsfiddle:- http://jsfiddle.net/chetanbh/rpbdq4ex/

slickgrid - How to loop through rows which are outside canvas?

I am having some markers on map and same number of rows in slickgrid?
What I want is when a marker is clicked the id of marker is matched with all rows and corresponding row should get selected.
Here is my code:
var $canvas = $(grid.getCanvasNode());
var $allRows = $canvas.find('.slick-row');
$($allRows).each(function() {
if ($(this).rowID == selectedMarker) {
$(this).addClass("active-row");
grid.scrollRowIntoView($(this).index());
}
});
It works fine only when the row which I want is present in the grid but the grid DOM contains only 8 rows at a time (The grid has 30 rows).
How can I loop through all data?
You shouldn't be modifying SlickGrid's DOM at all. SlickGrid will overwrite any changes as it's only rendering the rows in view (with some buffer). When you scroll past that buffer any changes you made to the DOM are lost.
You have to change the row's data and allow SlickGrid to add the appropriate classes to the DOM when it's rendering.
Edit:
SlickGrid setup:
dataView.getItemMetadata = metadata(dataView.getItemMetadata);
function metadata(metadataProvider) {
return function(row) {
var item = this.getItem(row),
ret = metadataProvider(row);
if (item && item.isActive) {
ret = ret || {};
ret.cssClasses = (ret.cssClasses || '') + ' active-row';
}
return ret;
};
}
Then when you click on a marker:
var item = dataView.getItemById(selectedMarker);
var row = dataView.getRowById(selectedMarker);
item.isActive = true;
dataView.updateItem(item.id, item);
grid.scrollRowIntoView(row);

Categories

Resources