Table doesn't render on ajax command I have a function that returns a render array for a table;

  private function _files_table($job_id){
    $files = $this-&gt;_query("
      select *
      from JC_Documents_Recent_Revisions
      where Job_ID=".$this-&gt;sqs($job_id).";
    ");

    $rows = array_map(function($row){
      return [
        (string)$row['Job_ID'],
        $row['Document_Name'],
        $row['Document_Type'],
        $row['File_Name'],
        ($row['Uploaded_Date'] != NULL ? $row['Uploaded_Date']-&gt;format("Y-m-d H:i") : 'Unknown Date'),
        $row['Uploaded_By'],
        new FormattableMarkup('&lt;a href=":link"&gt;show&lt;/a&gt;', [':link' =&gt; (Url::fromRoute('JobFileUpload.Serve', ['file_id' =&gt; (int)$row['FileID']]))-&gt;toString()]),
        new FormattableMarkup('&lt;a href=":link"&gt;revise&lt;/a&gt;', [':link' =&gt; (Url::fromRoute('JobFileUpload.Revise', ['file_id' =&gt; (int)$row['FileID']]))-&gt;toString()]),
        new FormattableMarkup('&lt;a href=":link"&gt;delete&lt;/a&gt;', [':link' =&gt; (Url::fromRoute('JobFileUpload.Delete', ['document_id' =&gt; (int)$row['DocumentID']]))-&gt;toString()])
      ];
    }, $files);

    $header = [
      t('Job ID'),
      t('Document Name'),
      t('Document Type'),
      t('File Name'),
      t('Uploaded Date'),
      t('Uploaded By'),
      t('Download'),
      t('Revise'),
      t('Delete')
    ];

    return [
      '#theme' =&gt; 'table',
      '#header' =&gt; $header,
      '#rows' =&gt; $rows
    ];
  }


and two occasions where I wish to render the table. The first is in buildForm:

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $job_id=NULL) {
    $jobs = $this-&gt;_query("
      select *
      from Active_Job_List;
    ");

    $formatted_jobs = [];
    $len = count($jobs);
    for($i=0; $i&lt;$len; $i++){
      $formatted_jobs[$jobs[$i]['Job_ID']] = $jobs[$i]['Job_Name'];
    }
    natsort($formatted_jobs);

    $form['job_id'] = [
      '#weight' =&gt; 1,
      '#title' =&gt; t('Job'),
      '#type' =&gt; 'select',
      '#options' =&gt; $formatted_jobs,
      '#ajax' =&gt; [
        'callback' =&gt; '::showFiles',
        'wrapper' =&gt; 'ajax-wrapper'
      ],
      '#required' =&gt; TRUE,
      '#default_value' =&gt; $job_id
    ];

    $form['jobfiles'] = $this-&gt;_files_table($job_id);
    $form['jobfiles']['#weight'] = 2;

    if($job_id != null){
      $form['newfile'] =  [
        '#weight' =&gt; 3,
        '#title' =&gt; t('Upload new file'),
        '#type' =&gt; 'link',
        '#url' =&gt; Url::fromRoute('JobFileUpload.UploadForm', ['job_id' =&gt; $job_id])
      ];
    }

    return $form;
  }


The second is in showFiles:  

  public function showFiles(array &amp;$form, FormStateInterface $form_state) {
    $job_id = $form_state-&gt;getValue('job_id');

    $output = $this-&gt;_files_table((int)$job_id);
    // $output['link'] = new FormattableMarkup('&lt;a href=":link"&gt;Upload a new file...&lt;/a&gt;', [':link' =&gt; (Url::fromRoute('JobFileUpload.UploadForm', ['job_id' =&gt; $job_id]))-&gt;toString()]);

    $renderer = \Drupal::service('renderer');

    $response = new AjaxResponse();
    $response-&gt;addCommand(new HtmlCommand('#ajax-wrapper', $renderer-&gt;render($output)));

    return $response;
  }


The buildForm method works just fine, and I get a table with the files in it. But when I call the same render array function on an output for the AjaxResponse (in ::showFiles), I don't even get an error, and the table does not show up. Anyone got an idea of what I'm doing wrong here?
I think the problem was not specifying an id attribute for my table when I first render it, so there was nothing to replace. 

This seems to work:

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $job_id=NULL) {
    $jobs = $this-&gt;_query("
      select *
      from Active_Job_List;
    ");

    $formatted_jobs = [];
    $len = count($jobs);
    for($i=0; $i&lt;$len; $i++){
      $formatted_jobs[$jobs[$i]['Job_ID']] = $jobs[$i]['Job_Name'];
    }
    natsort($formatted_jobs);

    $form['job_id'] = [
      '#weight' =&gt; 1,
      '#title' =&gt; t('Job'),
      '#type' =&gt; 'select',
      '#options' =&gt; $formatted_jobs,
      '#ajax' =&gt; [
        'callback' =&gt; '::showFiles',
        'wrapper' =&gt; 'ajax-wrapper'
      ],
      '#required' =&gt; TRUE,
      '#default_value' =&gt; $job_id
    ];

    $form['jobfiles'] = $this-&gt;_files_table($job_id);
    $form['jobfiles']['#weight'] = 2;

    if($job_id != null){
      $form['newfile'] =  [
        '#weight' =&gt; 3,
        '#title' =&gt; t('Upload new file'),
        '#type' =&gt; 'link',
        '#url' =&gt; Url::fromRoute('JobFileUpload.UploadForm', ['job_id' =&gt; $job_id]),
        '#attributes' =&gt; [
          'id' =&gt; ['new-file']
        ]
      ];
    }

    return $form;
  }

  public function showFiles(array &amp;$form, FormStateInterface $form_state) {
    $job_id = $form_state-&gt;getValue('job_id');
    // $form_state-&gt;setRedirectUrl(Url::fromRoute('JobFileUpload.OverviewWithJobId', ['job_id' =&gt; $job_id]));

    $table = $this-&gt;_files_table((int)$job_id);
    $link = [
      '#type' =&gt; 'markup',
      '#markup' =&gt; new FormattableMarkup('&lt;a href=":link"&gt;Upload a new file...&lt;/a&gt;', [':link' =&gt; (Url::fromRoute('JobFileUpload.UploadForm', ['job_id' =&gt; $job_id]))-&gt;toString()
      ])
    ];
    $renderer = \Drupal::service('renderer');

    $response = new AjaxResponse();
    $response-&gt;addCommand(new HtmlCommand('#ajax-wrapper', $renderer-&gt;render($table)));
    $response-&gt;addCommand(new HtmlCommand('#new-file', $renderer-&gt;render($link)));

    return $response;  
  }