DataTables format (d) is undefined going in and I don't know why.

DataTables format (d) is undefined going in and I don't know why.

pborreggpborregg Posts: 59Questions: 2Answers: 0

This is the test case that I used to develop what Allan has already been helping me with: https://datatables.net/examples/server_side/row_details

Debug console produces the following:

DEFAULT: TypeError: Cannot read property show of undefined. This happens when I click on the row.

Here's the image of my form: Note: There are no green plus signs.

I'm using Angular 6 and Typescript.

So, KUDO's to ALLAN for helping me privately but overstayed my welcome and don't want to take up all of his time.

Here's my issue:

I have an unusual situation. The details are going to show the document for fields that have them.

The case is there are TWO required fields in my form: SSN and Country of Issuance. If there are docs I display them. There can be 1 - "n" number. So, that's in an array and I simply pull them. Therein lies the problem.

Here's my HTML

<table id="dataTable1" #dataTable class="table table-striped table-bordered table-hover table-vcenter" 
       [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" datatable>
  <thead>
    <tr>
      <th></th>
      <th>Document</th>
      <th>Section/Subform</th>
      <th>Status</th>
      <th>Attachment</th>
    </tr>
  </thead>

</table>

My Typescript, reduced for brevity which is inclosed in the ngOnInti(): It works fine but I'll break out into mini functions later on.

      const detailRows: any[] = [];

      const dt = $('#dataTable1 tbody').on('click', 'td.details-control', () => {
        const tr = $('#dataTable1').closest('tr');
        const row = thistable.row(tr);
        const idx = detailRows.includes(tr.attr('id'));

        console.log('IDX: ' + idx);
        console.log('Selected Row: ', thistable.rows({selected: true}).data());

        if (row.child.isShown()) {
          // This row is already open, close it
          row.child.hide();
          tr.removeClass('shown');
        } else {
          // Open this row
          console.log('Row Data: ', row.data());
          console.log('What Row: ', this.format(row.data()));
          row.child(this.format(row.data())).show(); **<-- THIS IS WHERE IT FAILS**
          tr.addClass('shown');
        }
      });

      // On each draw, loop over the `detailRows` array and show any child rows
      dt.on('draw', function () {
        dt.forEach(detailRows, function (ndx: any, id: string) {
          console.log('NDX is: ' + ndx);
          console.log('ID is: ' + id);
          $('#' + id + ' td.details-control').trigger('click');
        });
      });
      return '';

      dt.on('myRedraw', () => {
        dt.fnDraw();
      });

      this.dtTrigger.next();

Here's my format() function with UNDEFINED TRAP

  private format(d: any) {

    if (d === undefined) {
      this.formatNoDocs('the field');
    } else {

      console.log('DETAILS', d);

      return `<table class='childDatatableMain'>` +
        `<thead>` +
        `<tr>` +
        `<th>Document Version ID</th>` +
        `<th>Document Description</th>` +
        `<th>Document Name</th>` +
        `<th>UserID</th>` +
        `<th>Sensitive</th>` +
        `<th>Date Created</strong></th>` +
        `<th></th>` +
        `</tr>` +
        `</thead>` +

        `<tr>` +
        `<td>` + d.documentversionid + `</td>` +
        `</tr>` +
        `<tr>` +
        `<td>` + d.description + `</td>` +
        `</tr>` +
        `<tr>` +
        `<td>` + d.documentname + `</td>` +
        `</tr>` +
        `<tr>` +
        `<td>` + d.userid + `</td>` +
        `</tr>` +
        `<tr>` +
        `<td>` + d.issensitive + `</td>` +
        `</tr>` +
        `<tr>` +
        `<td>` + d.createddate + `</td>` +
        `</tr>` +

        `</table>`;
    }
  }

  private formatNoDocs(d: string) {
    return `<table class='childDatatableMain'>` +
      `<tr>` +
      `<td>There are no documents for ` + d + ` at this time.</td>` +
      `</tr>` +
      `</table>`;
  }

OK, now that, that's out of the way, the way my JSON looks like is this.

data: Array(2)
0:
completed: 1
docsattached: Array(3)

0:
createddate: "2020-08-28T21:55:22.000+0000"
currentverid: 491
deleteddate: null
description: "Social Security"
dmsid: "433bc863-7dfb-45ee-8ec3-05e22153cef3"
doctypecode: "Social Security number"
doctypelabel: "afp.pdf"
documentname: "test text file.txt"
documenttitle: "test text file.txt"
documentversionid: 491
fromlibrary: undefined
id: 491
issensitive: false
isvisible: true
location: "social_documents/zaWnaEYt"
resourceid: "f37a82d0-c0c3-47ce-9a76-4c1ff3db8a5a_ea83fca9-7ccc-40f4-8dc6-e7a8a269ded1"
userid: "zaWnaEYt"

1:
createddate: "2020-08-28T21:54:40.000+0000"
currentverid: 490
deleteddate: null
description: "Social Security"
dmsid: "af20c5b2-dfe7-46e0-b7f4-7cf79d602163"
doctypecode: "Social Security number"
doctypelabel: "afp.pdf"
documentname: "This is a test PDF Doc.pdf"
documenttitle: "This is a test PDF Doc.pdf"
documentversionid: 490
fromlibrary: undefined
id: 490
issensitive: false
isvisible: false
location: "social_documents/zaWnaEYt"
resourceid: "f37a82d0-c0c3-47ce-9a76-4c1ff3db8a5a_ea83fca9-7ccc-40f4-8dc6-e7a8a269ded1"
userid: "zaWnaEYt"

2:
createddate: "2020-08-26T22:48:25.000+0000"
currentverid: 374
deleteddate: null
description: "test text file v.1.0.txt"
dmsid: "cec36556-e023-44b9-98b9-aac95cb854c3"
doctypecode: "Social Security number"
doctypelabel: "afp.pdf"
documentname: "test text file v.1.0.txt"
documenttitle: "test text file v.1.0.txt"
documentversionid: 374
fromlibrary: undefined
id: 374
issensitive: true
isvisible: true
location: "social_documents/zaWnaEYt"
resourceid: "f37a82d0-c0c3-47ce-9a76-4c1ff3db8a5a_ea83fca9-7ccc-40f4-8dc6-e7a8a269ded1"
userid: "zaWnaEYt"
field: "Social Security number"
required: 1
section: "Employee Information"
stats: true
subform: "Personal Information"

1:
completed: 0
docsattached: Array(1)
0: "There are no documents for: Country of issuance"
length: 1
field: "Country of issuance"
required: 1
section: "Eligibility Information"
stats: false
subform: "Employment Eligibility"

KEY OBJECTIVE:
First, Display rows under the parent ROW where I either show all attached documents (info) or "No Documents for Country of Issuance" for this example.

Secondly, the ATTACHMENT column for the parent needs to be "EMPTY" as I only display the EDIT, Download, Upload, or Delete icon per attachment not the for the parent row.

So, I want it to look like the image with the following:

PARENT ROW SSN:
- Document 1
- Document 2
- Document 3

PARENT ROW COUNTRY OF ISSUANCE:
- NO documents for Country of Issuance <-- I'm passing that into the FORMAT noDocs method.

That's all folks.

This question has an accepted answers - jump to answer

«1

Answers

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    OH, by the way:

    My goal is to eventually get to this example: https://datatables.net/blog/2019-01-11

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    TypeError: Cannot read property show of undefined. This happens when I click on the row.

    row.child(this.format(row.data())).show(); <-- THIS IS WHERE IT FAILS

    Its hard to say just by looking at the code but you will need to find out what is undefined.

    What do these lines show?

        console.log('Row Data: ', row.data());
        console.log('What Row: ', this.format(row.data()));
    

    And this in the format() function?

    console.log('DETAILS', d);
    

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Row Data: UNDEFINED
    DETAILS: UNDEFINED
    What Row: UNDEFINED

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    DETAILS: UNDEFINED

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Kevin, any thoughts?

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Kevin, HA! I put this code in and look what I found even though the table "DOES" have records.

    console.log('The table has ' + thistable.length + ' records');

    The table has 0 records.

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    This is the data going into the Table:

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    So, here's what's in this:

          thistable = $('#dataTable1').DataTable({
            'lengthMenu': [[5, 10, 25, -1], [5, 10, 25, 'All']],
            'paging': true,
            'ordering': true,
            'info': true,
            'data': **dataTablesReqFieldsFinal.data**,
            'columnDefs': [
              {'className': 'align-items-center', 'targets': 'status'}
            ],
            responsive: {
              details: {
                type: 'column',
                target: 'tr'
              }
            },
            'columns': [
              {
                'className': 'details-control',
                'orderable': false,
                'data': null,
                'defaultContent': ''
              },
              {'data': 'document'},
              {'data': 'subformsection'},
              {
                'data': function (row: Object, type: any, val: string, meta: any) {
                  // Get the values to show the Status ICON
                  // <span *ngIf="!row?.stats || (row?.stats?.attachments?.required !== row?.stats?.attachments?.completed)" class="fas fa-exclamation-circle text-danger"></span>
                  // <span *ngIf="row?.stats && (row?.stats?.attachments?.required === row?.stats?.attachments?.completed)" class="fas fa-check-circle text-success"></span>
                  console.log('row: ', row);
                  console.log('type: ', type);
                  console.log('val: ', val);
                  console.log('meta: ', meta);
    
                  const len = meta.row;
                  if (!self.obj.data[len].stats ||
                    (self.obj.data[len].required !==
                      self.obj.data[len].completed)) {
                    return '<span class="fas fa-exclamation-circle text-danger"></span>';
                  } else if (self.obj.data[len].stats &&
                    (self.obj.data[len].required ===
                      self.obj.data[len].completed)) {
                    return '<span class="fas fa-check-circle text-success"></span>';
                  }
    
                },
                'class': 'centerColumns'
              },
              {
                'data': null,
                'orderable': false
              }
            ],
            'order': [[2, 'asc']]
          });
    

    Row 0

    and Row 1

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    oh, BTW, self is defined way up top as: const self = this;

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Kevin, also, look at this... it's going into the format(d) method twice and the second time, DETAILS "IS" populated

    and here's what "_Api(2) looks like which contains the data...

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    Looks like your problem is with this code:

    const dt = $('#dataTable1 tbody').on('click', 'td.details-control', () => {
      const tr = $('#dataTable1').closest('tr');
      const row = thistable.row(tr);
    

    If you look at the example you have linked it uses this:

        $('#example tbody').on( 'click', 'tr td.details-control', function () {
            var tr = $(this).closest('tr');
    

    In this case this is the td.details-control cell that is clicked. The $('#dataTable1').closest('tr') is not going to work properly and is likely why you have undefined. This thread will show how to get the clicked cell using an arrow function.

    Kevin

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    it's going into the format(d) method twice and the second time, DETAILS "IS" populated

    You are calling it twice, once here:
    console.log('What Row: ', this.format(row.data()));

    and once here:
    row.child(this.format(row.data())).show();

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    D'oh! Let me make the changes... the var can't be used in Typescript, hence the Const. LET is not allowed as tr is never redefined with jsLint. Stand by Kevin.

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Still is undefined

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    Still is undefined

    What did you change. Please post a link to your page or a test case replicating the issue so we can help debug.
    https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    OK, I'll pull out the parts for codepen. Give me a bit, meetings all day

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Here: I've dropped in with hard code and still "d" is undefined!!!!!!!!

    http://live.datatables.net/fimonime/1/edit

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    OMG! Playing in Codepen, I think I got it to work!!! Kevin, please verify.

  • pborreggpborregg Posts: 59Questions: 2Answers: 0
    edited September 2020

    OK, just one minor issue left, Kevin.

    I'm getting [object Object] and [object Object] before the two JSON objects. I'm trying to find out,.... it's probably really simple. Can you review my code please? This was a great idea!

    [object Object] {
      attachment: "yes",
      docsattached: [[object Object] { 
    ....
      }
     ]
    ....
    }
    
  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736
    Answer ✓

    The data structure is easier to see if you use the Browser's console instead of the console tab in the JS BIN. For example:

    You have this in the format function:

            '<tr>'+
                '<td>Created Date:</td>'+
                '<td>'+d.createddate+'</td>'+
            '</tr>'+
    

    The createddate object is contained in an array assigned to the docsattached property. You can access the first one using d.docsattached[0].createddate. Or you can loop through all the docsattached property to build multiple rows. of output. ITs all Javascript at this point. Nothing specific to Datatables.

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Kevin, my goal is to display the documents UNDER the parent row. In my example there are three.

    So I just need to do that

    Doc 1
    Doc 2
    Doc 3

    But eventually I want to get to this https://datatables.net/blog/2019-01-11 but one step at a time.

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    Oh, I just saw your comment.. Let me work it. Thank you so much. This has been a great help.

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    I GOT IT! YOU ROCK! Thank you sir!

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    It's all working, Kevin, but the green plus sign doesn't appear even though it's in the CSS as specified. What am I missing?

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    I guess you need t o make sure the path to the PNG files is good and the files are there. Not sure what you specified as the path.

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0
    edited September 2020

    A quick Question Kevin.

    Styling my child data table is not working.

          for (let i = 0; i < this.childObj.data.length; i++) {
    
            docsTableReturned += '<table class=\'docstable\' style=\'width: 100%\'>' +
              '<thead>' +
              '<tr>' +
              '<th>Name</th>' +
              '<th>Date Created</th>' +
              '<th>User Created</th>' +
              '<th>Controls</th>' +
              '</tr>' +
              '</thead>' +
              '<tbody>' +
              '<tr>' +
              '<td class="documentname">' + d.documents.docsattached[i].documentname + '</td>' +
              '<td class="datecreated">' + d.documents.docsattached[i].createddate + '</td>' +
              '<td class="userid">' + d.documents.docsattached[i].userid + '</td>' +
              '<td class="attachcontrol">' +
              '<button (click)="editDocument(' + d.documents.docsattached[i] + ')" ' +
              'class="btn-link" ' +
              'ngbTooltip="Edit current ' + d.documents.docsattached[i].documenttitle + ' document" ' +
              'type="button">' +
              '<i class="fas fa-pencil-alt"></i>' +
              '</button>' +
              '&nbsp;' +
              '<button (click)="downloadDocument(' + d.documents.docsattached[i] + ')" ' +
              'class="btn-link" ' +
              'ngbTooltip = "Download ' + d.documents.docsattached[i].documenttitle + ' document from library" ' +
              'type="button">' +
              '<i class="fas fa-cloud-download-alt"></i>' +
              '</button>' +
              '&nbsp;' +
              '<button (click)="attachDocument(' + d.documents.docsattached[i] + ')" ' +
              'class="btn-link" ' +
              'ngbTooltip = "Attach ' + d.documents.docsattached[i].documenttitle + ' document to library" ' +
              'type="button">' +
              '<i class="fas fa-plus-square"></i>' +
              '</button>' +
              '&nbsp;' +
              '<button (click)="uploadDocument(' + d.documents.docsattached[i] + ')" ' +
              'class="btn-link" ' +
              'ngbTooltip = "Upload ' + d.documents.docsattached[i].documenttitle + ' document from library" ' +
              'type="button">' +
              '<i class="fas fa-cloud-upload-alt"></i>' +
              '</button>' +
              '</td>' +
              '</tr>' +
              '<tbody>' +
              '</table>';
          }
          return docsTableReturned;
    

    Here are the classes that "aren't" working

    .btn-link {
      border: 0px !important;
      background-color: transparent !important;
      text-align: left !important;
      cursor: pointer !important;
    }
    .documentname {
      width: 25% !important;
    }
    .datecreated {
      width: auto !important;
    }
    .userid {
      width: 10% !important;  
    }
    .attachcontrol {
      width: 15% !important;
    }
    

    And the btn-link does not work. No hyperlink appears. I don't want to do inline styles

  • kthorngrenkthorngren Posts: 20,142Questions: 26Answers: 4,736

    Styling my child data table is not working.

    Solving styling issues is near impossible without being able to work with a running example. Please provide a link to your page or a test case showing the styling issues so we can help debug.
    https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case

    Otherwise right click on the element in question and click Inspect. This will allow you to see the styles applied and whether they are overwritten.

    Kevin

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    I fixed it. D'oh!

  • pborreggpborregg Posts: 59Questions: 2Answers: 0

    But this, still won't work,

    .btn-link {
      border: 0px !important;
      background-color: transparent !important;
      text-align: left !important;
      cursor: pointer !important;
    }
    .documentname {
      width: 25% !important;
    }
    .datecreated {
      width: auto !important;
    }
    .userid {
      width: 10% !important; 
    }
    .attachcontrol {
      width: 15% !important;
    }
    

    It shows i the element tab of chromes debug console but it's not in the Styles tab, anywhere

This discussion has been closed.