Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Emokores's avatar

Cannot display data from MariaDB dynamically - Inertia/ReactJS

I have a datatable component to display some data from a table. However, when I try to display the data I get a JS error: TypeError: Cannot read properties of undefined (reading 'length'). This is what I had in my controller before and it was working very fine:


'patients' => Patient::query()->when($search, fn ($query) => $query->where( ... ))->with(['nok', 'insurance'])->orderByDesc('created_at')

And now, since I want to implement a frontend data filter, I resorted to using:


'patients' => Patient::with(['nok', 'insurance'])->get(['name', 'email']),

When I console.log(patients), I can view the data. However, my page just returns my error boundary with that JS error in the console. I can't figure out what is not right.

0 likes
14 replies
LaryAI's avatar
Level 58

The issue seems to be with the data format being returned from the backend. In the first example, you are returning a query builder instance, which can be further manipulated on the frontend. However, in the second example, you are returning a collection of patients with only the 'name' and 'email' fields, which cannot be further manipulated on the frontend.

To fix this, you can return the full patient data from the backend and use a frontend data filter to filter the data. Here's an example of how you can modify your controller code:

'patients' => Patient::query()
    ->when($search, fn ($query) => $query->where( ... ))
    ->with(['nok', 'insurance'])
    ->orderByDesc('created_at')
    ->get(),

Then, in your frontend code, you can use a data filter to filter the data based on the search query. Here's an example of how you can do this using the useMemo hook in React:

import { useMemo } from 'react';
import { usePage } from '@inertiajs/inertia-react';

const PatientsTable = () => {
  const { props } = usePage();
  const { patients } = props;

  const filteredPatients = useMemo(() => {
    // Replace this with your actual filter logic
    return patients.filter(patient => patient.name.includes(searchQuery));
  }, [patients, searchQuery]);

  return (
    // Render your table using the filteredPatients data
  );
};

Note that you'll need to replace the searchQuery variable with your actual search query value. Also, make sure to import the usePage hook from @inertiajs/inertia-react to access the data passed from the backend.

Emokores's avatar

@LaryAI Thank you. This is what I actually did in the beginning. The first code I used seems too much yet I am not using the query builder in the backend. I just need to return the collection and display it in the frontend, which is why I changed from using the query builder to just returning the collection.

tykus's avatar

@Emokores length of what? There should be no issue with the query being conditionally constrained (or not) based on the presence of $search. This is most probably an issue on the client side application/library rather than the backend.

Emokores's avatar

@tykus The query I'm trying to use is the one below:


// refer to the second code in the question
'patients' => Patient::with([relationships])->get([specific fields])

However, when I try to map through in my frontend, I get the JS error Type Error: Cannot read properties of undefined (reading 'length').

// This is in the <PatientsData /> component having the table
{array.data.length === 0 && (
      <EmptyState />
)}

// But I still cannot map through the data (patients) in the component
{array.data.map()}

// In the Index.jsx
<PatientsData array={patients} />

When I console.log(patients) I get the array from the database.

tykus's avatar

@Emokores okay... and how does the result differ whenever the conditional constraint is applied?

Emokores's avatar

@tykus When I use the conditional constraint, it is very okay. I felt that the code was a bit too much, yet I am not going to use filtering in the backend. I just want to return the array to the frontend and do the filtering from the frontend. But the code in the controller doesn't display the data

tykus's avatar

@Emokores I'm lost... what happens with the $search in that case; are you trying to filter the entire Collection on the frontend?

Emokores's avatar

@tykus It works fine since I am doing the filtering from the backend. However, I changed the code to the one below so that I can do the filtering on the frontend instead, and just return the collection on the backend.


// refer to the second code in the question
'patients' => Patient::with([relationships])->get([specific fields])

tykus's avatar

@Emokores still not 100% sure I get you, but anyway... did you include the relevant foreign key(s) in the specific fields?

Emokores's avatar

@tykus Everything else is working, except when I try to change the Eloquent query, just as I explained earlier.

tykus's avatar

@Emokores yes, but there is nothing in this query (id or foreign keys from patients) to associate the nok and insurance relations:

Patient::with(['nok', 'insurance'])->get(['name', 'email'])
tykus's avatar

@Emokores does the Datatable package expect a (Eloquent/Query) Builder instance and not a Collection?

'patients' => Patient::with(['nok', 'insurance'])->select(/* specific columns */) ,
Emokores's avatar
Emokores
OP
Best Answer
Level 2

@tykus I solved the issue. I changed the collection to the one below to maintain the backend search filter:


'patients' => Patient::query()->when($search, fn ($query) => 
    $query->where( ... )
	)->through(fn ($patient) => [
      // only pass specific fields
]),

'filters' => $request->only(['search'])

In my frontend, I used the useEffect() hook to send the request to the backend while watching for changes

const filters = usePage().props.filters
const [query, setQuery] = useState(filters.search)

useEffect (() => {
   router.get(route(route().current()), 
      {search: query},
      {
         preserveState: true,
         replace: true
      },
   ), 
}, [query])

With this, the result was a live search with data being sent over to the backend, instead of handling it via frontend only.

1 like

Please or to participate in this conversation.