Introduction

You can create a custom Table Type dedicated to AJAX-sourced data. This approach has the advantage of being totally reuasble, while the AJAX via data function may be less reuasble across multiple table instances.

The example bellow reuses 2 times the same logic, changing only the data parameter to a different endpoint.

If you want to customize the behavior of your table for a single use, you may want to check the use of the data function.

Demo

Upcoming launches

Past launches

Code

Javascript

import { makeQueryStringFromObj, formatUtcDate } from '../utils.js';

/* globals VuejsDatatable, axios, Vue */

VuejsDatatable.registerTableType( 'ajaxtable', tableType => {
	tableType
		.setFilterHandler( ( source, filter, columns ) => ( {
			// See https://documenter.getpostman.com/view/2025350/RWaEzAiG#json-field-masking
			filter: columns.map( col => col.field.replace( /\./g, '/' ) ).join( ',' ),
		} ) )
		.setSortHandler( ( endpointDesc, sortColumn, sortDir ) => 
			Object.assign( {}, endpointDesc, sortColumn && sortDir ? {
				sort:  sortColumn.field.replace( /\./g, '/' ),
				order: sortDir, 
			} : {} ) )
		.setPaginateHandler( ( endpointDesc, perPage, pageIndex ) => 
			Object.assign( {}, endpointDesc, {
				offset: ( ( pageIndex - 1 ) * perPage ) || 0,
				limit:  perPage || 10, 
			} ) )
		// Alias our process steps, because the source, here, is our API url, and paged is the complete query string
		.setDisplayHandler( async ( { source: baseEndPoint, paged: endpointDesc } ) => {
			const url = `${ baseEndPoint }?${ makeQueryStringFromObj( endpointDesc ) }`;

			const {
				// Data to display
				data,
				// Get the total number of matched items
				headers: {'spacex-api-count': totalCount}, 
			} = await axios.get( url );
			
			return {
				rows:          data,
				totalRowCount: totalCount,
			};
		} );
} );

new Vue( {
	el:   '#demo-app',
	data: {
		columns: [
			{ label: 'Flight number', field: 'flight_number' },
			{ label: 'Mission name', field: 'mission_name' },
			{ label: 'Launch date', field: 'launch_date_utc', representedAs: row => formatUtcDate( new Date( row.launch_date_utc ) ) },
			{ label: 'Rocket type', field: 'rocket.rocket_name', sortable: false },
			{ label: 'Launch site', field: 'launch_site.site_name_long', sortable: false },
			{
				label:         'Mission patch',
				field:         'links.mission_patch_small',
				representedAs: row => row.links.mission_patch_small ?
					`<img src="${ row.links.mission_patch_small }" alt="${ row.mission_name } patch" style="height: 6em;"/>` :
					`<img src="https://www.gvmc.gov.in/wss/images/noimageavailable.png" alt="No patch for mission &quot;${ row.mission_name }&quot; available" style="height: 6em;"/>`,
				interpolate: true,
				sortable:    false,
			},
			{
				label:         'Reddit link',
				field:         'links.reddit_campaign',
				representedAs: row => `<a href="${ row.links.reddit_campaign }">${ row.mission_name } Reddit thread</a>`,
				interpolate:   true,
				sortable:      false,
			},
		],
		page:           1,
		apiUrlUpcoming: 'https://api.spacexdata.com/v3/launches/upcoming',
		apiUrlPast:     'https://api.spacexdata.com/v3/launches/past',
	},
} );

HTML

<div id="demo-app">
		<h3>Upcoming launches</h3>
		<div class="row">
			<div class="col-xs-12 table-responsive">
				<ajaxtable name="upcoming" :columns="columns" :data="apiUrlUpcoming"></ajaxtable>
				<ajaxtable-pager table="upcoming" v-model="page"></ajaxtable-pager>
			</div>
		</div>
		<h3>Past launches</h3>
		<div class="row">
			<div class="col-xs-12 table-responsive">
				<ajaxtable name="past" :columns="columns" :data="apiUrlPast"></ajaxtable>
				<ajaxtable-pager table="past" v-model="page"></ajaxtable-pager>
			</div>
		</div>
	</div>