Parnet Child Checkbox

Tags: #<Tag:0x00007f135fedd798> #<Tag:0x00007f135fedd590>

Hello all,

I would like some help to see what wrong i am doing.

I have table with Parnet and Child Rows and col 8 has checkbox.

Would you guide me or point me to the right direction to remove the checkbox from the parent and only children have the checkbox?

The reason I am trying to do that is user can only pick one child from each parent.
Also let me know if there might be better approach than the rabbit hole i am in


I will share the sample of my code as I am not sure how would i make it work within the jsfiddle since my code over 1500 lines :cry: and my cells data are coming from backend using fetch and they are not statically embedded on my frontend .js file.

Here is my incoming data code along with the Table Setting:

fetch('/api/RTPSheet/TradeProcess/Blu', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(requestBody),

})
.then(response => {
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
})
.then(data => {

  if (data.clients && data.clients.length > 0) {
    setSnackbarOpen(true);

  let  order_number  = 0 
console.log("data.RTPOrdersNameList[: " , data.RTPOrdersNameList)
const hotDataBluConst = [];
for (let i = 0; i < data.RTPOrdersNameList.length; i++) {
  order_number = data.RTPOrdersNumberList[i]
  const parentRow = {

    Client: data.RTPOrdersNameList[i],
    OrderNo: data.RTPOrdersNumberList[i],
    Gallons: data.RTPOrderGallonsList[i],
    DateRange: "" , // data.EuroContracstName[i],
    Remaining: "" , // data.EuroContractsRemainingGallons[i],
    Ava: "" , // data.EuroContractsAvaGallons[i],
    TradeID: "" , // data.RTPProductCodeList[i],
    TradePrice: "" , //data.EuroContractTradePriceList[i],
    __children: [], // Initialize the children array


  };

  
  const children = [];
 
  console.log("data.RTPOrdersNumberLis[: " , data.RTPOrdersNumberList)
  console.log("data.ChildEuroContractOrderNumber: " , data.ChildEuroContractOrderNumber)

  for (let j = 0; j < data.ChildEuroContractTradeIDList.length; j++) {

if (order_number === data.ChildEuroContractOrderNumber[j]) {
  const childRow = {
              // Checkbox: true, 

    Client: `Contract ID ${data.ChildEuroContractTradeIDList[j]}`, // data.RTPOrdersNameList[i], 
    OrderNo: data.ChildEuroContractOrderNumber[j], 
    Gallons: "", //data.RTPOrderGallonsList[j],  
    DateRange: data.ChildEuroContractMonthRange[j],
    Remaining: data.ChildEuroContractsRemainingGallons[j],
    Ava: data.ChildEuroContractsAvaGallons[j],
    TradeID: data.ChildEuroContractTradeIDList[j],
    TradePrice: data.ChildEuroContractTradePriceList[j],
    __isChild: true,  
  };

  children.push(childRow);
}
  }

  parentRow.__children = children;
  hotDataBluConst.push(parentRow);

}
sethotDataBlu(hotDataBluConst);
setNumberOfProceedRows(data.NumberOfProceedRows);
 


 
  if (YesOrNo == 'Yes')
  {setOpenDialogBlu(false); }
   
  if (YesOrNo == 'No')
  {setOpenDialogBlu(false); }

  if (YesOrNo == 'NotSure')
  {setOpenDialogBlu(true); }

  const MessageSocketGroupPleaseUpdate = {    
    content: 'PleaseFetchDataTracker',
    username: CurrentUserData.username,
    color: CurrentUserData.color,
    coordx: selectedStartRow,
    coordy: selectedStartCol,
    SheetName: "RTP",
    inputFieldOne: null,
  };
  sendWebSocketMessage(MessageSocketGroupPleaseUpdate);
  
   

})
.catch(error => {

  
  console.error('Error sending data:', error);
});
  };




  //  Handsontable settings

const hotSettingsBlu = {
  data: hotDataBlu,
  cells: function (row, col, prop) {
const cellProperties = {};
 const checkboxColumnIndex = hotSettingsBlu.columns.findIndex(column => column.type === 'checkbox');
const ChildColumnIndex = hotSettingsBlu.columns.findIndex(column => column.data === 'Client');

 cellProperties.renderer = function (instance, td, row, col, prop, value, cellProperties) {
   if (col === checkboxColumnIndex) {
     Handsontable.renderers.CheckboxRenderer.apply(this, arguments);
  } else {
     Handsontable.renderers.TextRenderer.apply(this, arguments);
  }

  if (col === ChildColumnIndex && value.includes('Contract')) {
       td.classList.add('child-row'); 
    if (td.parentNode) {
       const cellsInRow = td.parentNode.childNodes;
      console.log('td.forEach:', td.innerText);  


     cellsInRow.forEach(cell => {
      console.log('cellsInRow.forEach:', cell.innerText); 
      cell.classList.add('child-row'); 
  

    });
  }
}


 
    console.log(' td.innerText:', td.innerText);  
     console.log(' td.className:', td.className); 
  
 
};
  
return cellProperties;
  },

  colHeaders: ['Client', 'OrderNo', 'Deliv. Gallons', 'DateRange', 'Remaining', 'Ava', 'TradeID', 'TradePrice', 'Check'],
  columns: [
{ data: 'Client' },
{ data: 'OrderNo' },
{ data: 'Gallons' },
{ data: 'DateRange' },
{ data: 'Remaining' },
{ data: 'Ava' },
{ data: 'TradeID' },
{ data: 'TradePrice' },
{ 
  type: 'checkbox' 
}
  ],
  stretchH: 'all',
  width: '100%',
  height: '300',
  rowHeaders: true,
  columnSorting: true,
  contextMenu: true,
  nestedRows: {
initialCollapse: true, // Collapse all nested rows by default Not Working
  },
  licenseKey: 'non-commercial-and-evaluation',
  afterInit: function () {

      // Collapse all nested rows by default
if (hotTableComponentBlu.current) {
  const hotInstance = hotTableComponentBlu.current.hotInstance;

  if (hotInstance) {
    const nestedRowsPlugin = hotInstance.getPlugin('nestedRows');

    if (nestedRowsPlugin && nestedRowsPlugin.collapsingUI && typeof nestedRowsPlugin.collapsingUI.collapseAll === 'function') {
      nestedRowsPlugin.collapsingUI.collapseAll();
    }
  }
}
  },

 
  afterChange: function (changes, source) {
if (source === 'edit') {
  changes.forEach(([row, col, oldValue, newValue]) => {
    console.log('Changes:', changes);
    console.log('Row:', row);
    console.log('Column:', col);
    console.log('Old Value:', oldValue);
    console.log('New Value:', newValue);
    console.log('col:', col);
    console.log('hotSettingsBlu.columns.length:', hotSettingsBlu.columns.length -1);
 
  });
}
  }
  
  
  
  
};

Here is a screenshot of the current output if that would help:

Thank you so much again!

Hi @noajm

Do I understand correctly that the last column should have a checkbox per child, not a parent? If so then you can use a custom renderer.

Now, the nestedRows doesn’t have a method to gather parents, but I created a function that runs and checks that (you should use it within afterCreateRow if you allow to add children rows).

Here’s the demo https://stackblitz.com/edit/33qu8p?file=index.js

Awesome and thank you!

That did work, and I liked the parent index trick.

I do have a follow-up question: when a user checks one of the parent checkboxes, then the corresponding checkboxes of its siblings get disabled.

However, I will create a new question for that, and this one can be closed.

Thanks again! :blush:

I hate to be picky, but it’s not a big deal if it had to be like this way like on the picture.

I could see that when I collapsed it, I got a picture like the following:

Here is was my adopted code from yours:

  // Define your Handsontable settings
 
  function getParentIndexes() {
    const parentIndexes = [];
    let parentIndex = 0;
  
    for (let i = 0; i < hotDataBlu.length; i++) {
      if (hotDataBlu[i].hasOwnProperty('__children')) {
        parentIndexes.push(parentIndex);
        parentIndex += hotDataBlu[i].__children.length + 1;
      }
    }
  
    console.log('gg Parent Indexes:', parentIndexes);  
    return parentIndexes;
  }
  const parentIndexes = getParentIndexes();

const hotSettingsBlu = {
  data: hotDataBlu,
  cells: function (row, col, prop) {
    const cellProperties = {};
     const checkboxColumnIndex = hotSettingsBlu.columns.findIndex(column => column.type === 'checkbox');
    const ChildColumnIndex = hotSettingsBlu.columns.findIndex(column => column.data === 'Client');
    const ChildColumnIndexOrderNo = hotSettingsBlu.columns.findIndex(column => column.data === 'OrderNo');

     cellProperties.renderer = function (instance, td, row, col, prop, value, cellProperties) {
     
         console.log('arentIndexes.includes:', parentIndexes); 

        if (parentIndexes.includes(row)) {
           Handsontable.renderers.TextRenderer.apply(this, arguments);
        } else {
           if (col === checkboxColumnIndex) {
             Handsontable.renderers.CheckboxRenderer.apply(this, arguments);
          } else {
             Handsontable.renderers.TextRenderer.apply(this, arguments);
          }
        }

Hi @noajm

Can you share a demo with the latest progress? That will help to replicate the issues.

I read it again, and I think that you were referring to the error when we double-clicked the empty parent where the checkbox was.

Here https://stackblitz.com/edit/33qu8p?file=index.js is an updated version that doesn’t force the checkbox to be empty.

It also looks well when we collapse/expand the parents.

That made it work perfectly :slight_smile:

Thanks!

I’m glad to hear that. Well done!

If you’ll need my help in the future, please feel free to open a new thread.