Help with Opening itemDetailScreen After Scanning Barcode (Match by ID)

Hi all,

I’m building a Retool mobile app with a barcode scanner to make looking up products faster. I have a scanner1 component set up, and I want it to work like this:

After scanning a barcode, the app should navigate to itemDetailScreen and show the product whose id matches the scanned value.

The barcode values correspond to the id field in my productos table.

What I’ve tried so far:

  • I can get the scanned value using scanner1.data.
  • I thought of using a JS query or transformer to filter the product list and find the matching item.
  • But I’m not sure how to pass that selected item to itemDetailScreen, or how to set itemCollection.selectedItem correctly before navigating.

Has anyone done something similar? What’s the best way to:

  1. Match the scanned barcode to an item by id,
  2. Set that item as the selected one,
  3. Navigate to itemDetailScreen with the right data?

Thanks a lot for any advice or examples!

Inventario Farmasi.json (71.6 KB)

1 Like

Hello @max.lopezzz,

Please update the event handler for scanner1 by changing the Navigation event type from Open to Capture, as shown in the attached screenshot.

Also, please update the transformer code in the filterItems query with the following:

// Get raw columnar data from query
const rawData = {{ getItems.data }};
// Handle case where data might be null or empty
if (!rawData || !rawData.nombre || !Array.isArray(rawData.nombre)) {
  return [];
}
// Convert columnar format to array of objects
const data = rawData.nombre.map((_, index) => {
  return {
    id: rawData.id?.[index] ?? null,
    nombre: rawData.nombre?.[index] ?? null,
    cantidad: rawData.cantidad?.[index] ?? null,
    costo: rawData.costo?.[index] ?? null,
    precio: rawData.precio?.[index] ?? null,
    categoria: rawData.categoria?.[index] ?? null,
    subcategoria: rawData.subcategoria?.[index] ?? null,
    descripcion: rawData.descripcion?.[index] ?? null,
    foto: rawData.foto?.[index] ?? null
  };
});
// Filtering function
function filterItems(searchString, categoria, subcategoria, id) {
  let filteredData = [...data];
  // Filter by search string in 'nombre'
  if (searchString) {
    const lowerCaseSearch = searchString.toLowerCase();
    filteredData = filteredData.filter(item =>
      item.nombre && item.nombre.toLowerCase().includes(lowerCaseSearch)
    );
  }
  // Filter by categoria
  if (categoria !== null && categoria !== undefined && categoria !== "") {
    filteredData = filteredData.filter(item =>
      item.categoria !== null &&
      item.categoria !== undefined &&
      item.categoria.toString() === categoria.toString()
    );
  }
  // Filter by subcategoria
  if (subcategoria !== null && subcategoria !== undefined && subcategoria !== "") {
    filteredData = filteredData.filter(item =>
      item.subcategoria !== null &&
      item.subcategoria !== undefined &&
      item.subcategoria.toString() === subcategoria.toString()
    );
  }
  // Filter by exact id
  if (id !== null && id !== undefined && id !== "") {
    filteredData = filteredData.filter(item =>
      item.id !== null &&
      item.id !== undefined &&
      item.id.toString() === id.toString()
    );
  }
  return filteredData;
}
// Execute filtering and return result
return filterItems(
  {{ busqueda.value || "" }},
  {{ select1.value ?? null }},
  {{ select2.value ?? null }},
  {{ scanValue.value ?? null }}
);