Can QuaggaJS and Livewire 3 work together?

30 Views Asked by At

How can I access a public property from Livewire 3 to the corresponding blade if I am using QuaggaJS. I can't use it like this : {{ $barcode }}. I believe that I can't use QuaggaJS and Livewire 3 together. What do you think?

I have a route that display me the blade of TicketScannerComponent.

Route::get('/scan-the-ticket', TicketScannerComponent::class)->name('scan.ticket');

I will show you the blade: ticket-scanner-component.blade.php

{{-- to be moved in app.css --}}


<style>
  #barcode-scanner video {
    width: 100% !important;
  }
</style>

<div>

  <div class="fixed top-0 left-0 w-screen h-screen bg-gray-100 flex items-center justify-center">

    <div id="barcode-scanner" class="h-full w-full relative">
      <!-- Overlay text -->
      <div id="overlay-text" class="absolute inset-0 flex justify-center items-center bg-opacity-50 text-white text-lg font-bold">
        Scan barcode here {{ $barcode }}
      </div>
    </div>

  <!-- Include the library -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js"></script>


</div>

</div>




<script>


    {{--https://serratus.github.io/quaggaJS/--}}

  // Initialize Quagga
  Quagga.init({
    inputStream: {
      name: "Live",
      type: "LiveStream",
      target: document.querySelector("#barcode-scanner")
    },
    decoder: {
      readers: ["upc_reader"] // Use the UPC-A reader
    }
  }, function(err) {
    if (err) {
      console.error("Error initializing Quagga:", err);
      return;
    }
    console.log("Initialization finished. Ready to start");
    Quagga.start();
  });

  // Listen for barcode detection
  Quagga.onDetected(function(result) {
    console.log("Barcode detected and read successfully:", result);
    // Handle the detected barcode here
    alert("UPC-A Barcode detected: " + result.codeResult.code);
    sendBarcodeData(result.codeResult.code);

    Quagga.stop(); // Stop scanning after a barcode is detected



  });

    // Function to send barcode data to the backend
    function sendBarcodeData(barcode) {

      var csrfToken = document.head.querySelector('meta[name="csrf-token"]').content;
      // Make an AJAX request to the Laravel route
      var xhr = new XMLHttpRequest();
      xhr.open("POST", "/validate-ticket", true);
      xhr.setRequestHeader("Accept", "application/json");
      xhr.setRequestHeader("Content-Type", "application/json");

      xhr.setRequestHeader("X-CSRF-TOKEN", csrfToken);

      // Define the data to be sent in JSON format
      var data = JSON.stringify({ barcode: barcode });

      // Handle response from the server
      xhr.onreadystatechange = function() {
        if (xhr.readyState === XMLHttpRequest.DONE) {
          if (xhr.status === 200) {
            console.log("Response from server:", xhr.responseText);
            // Handle successful response if needed
          } else {
            console.error("Error:", xhr.status);
            // Handle error response if needed
          }
        }
      };

      // Send the request with the data
      console.log("CSRF Token:", csrfToken);
      console.log("XHR object:", xhr);
      xhr.send(data);
    }

</script>

I send an ajax request to DashboardController where the validate ticket happen:

Route::controller(DashboardController::class)->group(function (): void {
//    Route::get('/', 'index')->name('index');
    Route::post('/validate-ticket', 'validateTicket')->name('validate');
});

DashboardController:

class DashboardController extends Controller
{
    public function validateTicket(Request $request): RedirectResponse
    {
        $barcode = $request->input('barcode');
        $ticket = Ticket::query()->where('code', $barcode)->first();
        if ($ticket !== null) {
//            Session::put('barcode', $barcode);

            return redirect()->route('generate.ticket', ['barcode' => $barcode]);
        }

        return redirect()->route('generate.ticket');
    }
}

And than it redirect me to Livewire Component:

`Route::get('/generate-ticket/{barcode}', TicketScannerComponent::class)->name('generate.ticket');

In LivewireComponent I have:

  public null|string $barcode;
    public string $orderId;
    public string $ticketTypeId;
    public BigInteger $usage;
    public bool $isUsed;




    public array|string $ticketData;
    public function mount(?string $barcode = null): void
    {



        if ($barcode !== null) {
            $ticket = Ticket::query()->where('code', $barcode)->first();
            $this->barcode = $barcode;

//            dd($this->barcode);
            $this->orderId = $ticket['order_id'];
            $this->ticketTypeId = $ticket['ticket_type_id'];
            $this->isUsed = $ticket['is_used'];
        }

    }

And I can't access the $barcode variable

1

There are 1 best solutions below

0
kduma On

If you want to use that barcode in the same instance of Livewire component, you need to communicate with it using Livewire JavaScript API.

In the code you have pasted, when you scan a new barcode, your sendBarcodeData method makes an POST AJAX call to /validate-ticket, which validates your barcode and redirects that call to your Livewire component - creating second instance of your component. That redirection is than immediately discarded, as you don't do anything with the response from xhr.send(data).

Generally, when creating Livewire components, you should contain whole flow inside of the component (as it makes life easier). Instead of using AJAX calls, you should create another method on your component which you will call when the barcode is scanned. In following example, I have prepared sendBarcodeData method in livewire component (where you should put your validation and processing of a ticket):

class TicketScannerComponent extends Component
{
    #[Locked]
    public null|string $barcode = null;

    public function sendBarcodeData(string $barcode): void
    {
        //perform your validation

        $this->barcode = $barcode;
    }
}

Which can be called as $wire.sendBarcodeData([...]) from the component Javascript.

<div>
    <div class="fixed top-0 left-0 w-screen h-screen bg-gray-100 flex items-center justify-center">
        <div id="barcode-scanner" class="h-full w-full relative">
            <!-- Overlay text -->
            <div id="overlay-text" class="absolute inset-0 flex justify-center items-center bg-opacity-50 text-white text-lg font-bold">
                Scan barcode here: {{ $barcode }}
            </div>
        </div>
    </div>
</div>

@script
<script>
    Quagga.init({
        inputStream: {
            name: "Live",
            type: "LiveStream",
            target: document.querySelector("#barcode-scanner")
        },
        decoder: {
            readers: ["ean_reader"]
        }
    }, function(err) {
        if (err) {
            console.error("Error initializing Quagga:", err);
            return;
        }
        console.log("Initialization finished. Ready to start");

        Quagga.start();
    });

    // Listen for barcode detection
    Quagga.onDetected(function(result) {
        console.log("Barcode detected and read successfully:", result);

        // Handle the detected barcode here
        $wire.sendBarcodeData(result.codeResult.code);

        Quagga.stop(); // Stop scanning after a barcode is detected
    });

</script>
@endscript

@assets
<style>
    #barcode-scanner video {
        width: 100% !important;
    }
</style>

<!-- Include the library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js"></script>
@endassets

Please notice that the script is contained between @script and @endscript tags, as it is required by documentation.