Has anyone tried instantsearch.js using controller...
# community-help
s
Has anyone tried instantsearch.js using controller or livewire in Laravel. I went through documentation in Typesense for Laravel and it uses inertia.js as example. It will be great if we have instantsearch.js implmentation given using controllers or livewire as well? Any pointers will help me.
j
CC: @Fanis Tharropoulos
f
I'm not sure I understand the question properly. If you are asking for guidance on building an instantsearch.js using Laravel controllers, it would be impossible, as Instantsearch is a frontend, JS library. If you're asking about building a Livewire version of the inertia app, using controller methods for searching, that is feasible
s
Hi @Fanis Tharropoulos... yes I am looking for building a Livewire version of the inertia app, uisng controller methods. In fact all i am looking for is having correct approach and setup for instantsearch.js using livewire or controller or may be combined usage of controller and livewire. I installed instantsearch.js and typesense adaptor but somewhere missing in using it in Livewire correctly. My tech stack is Tailwind, Alpinejs, Livewire and Laravel. Any pointer. I am even fine if i could get existing game streaming app example covered by you in livewire version.
f
I'll be sure to look into creating an equivalent Livewire version then!
s
Thanks @Fanis Tharropoulos.
❤️ 1
Hi @Fanis Tharropoulos... no matter what i do i am unable to make instantsearch.js work with livewire. After all its just UI component. So i added the instantsearch.js with typesense script in the view file of Livewire. like below. <!-- resources/views/livewire/search.blade.php --> <div> <div> <div id="searchbox"></div> <div id="hits"></div> </div> @push('scripts') <script type="module"> import instantsearch from "instantsearch.js"; import { searchBox, hits } from "instantsearch.js/es/widgets"; import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter"; const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({ server: { apiKey: "xyz", // Be sure to use an API key that only allows search operations nodes: [ { host: "localhost", path: "", // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense' port: "8108", protocol: "http", }, ], cacheSearchResultsForSeconds: 2 * 60, // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching. }, // The following parameters are directly passed to Typesense's search API endpoint. // So you can pass any parameters supported by the search endpoint below. // query_by is required. additionalSearchParameters: { query_by: "title,location,category.level0,category.level1", }, }); const searchClient = typesenseInstantsearchAdapter.searchClient; const search = instantsearch({ searchClient, indexName: "leads_index", }); search.addWidgets([ searchBox({ container: "#searchbox", }), hits({ container: "#hits", templates: { item:
Copy code
<div class="hit-name">
                    @{{ highlight.highlighted(item.title) }}
                </div>
, }, }), ]); search.start(); </script> @endpush </div> But i get empty front end page with only my layout header and footer with menu. I can inspect searchbox div and hit div but its not pulling or triggering any instantsearch.js code.
The only change i made was in below code
Copy code
<div class="hit-name">
          {{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}}
        </div>
to <div class="hit-name"> @{{ highlight.highlighted(item.title) }} </div> because i was repeately getting unexpected ';' syntax here. May be livewire expects blade syntax. I am not sure.
f
Is there any console logs?
I see you're using ES6 import syntax, I'm not sure if it's even possible to use ES6 syntax and node modules in a script tag like this one
Unless you're using a build step as well
Could you send me a reproducible example?
s
I have vite.config.js installed and it should build. I have Lead Model and a Livewire component ListLeads which is just rendering its view file for now. I have this mega project with 15-16 models all with dedicated model search using Laravel Scout and typesense. But search logic for each is manually written which I find not efficient. I found instantsearch.js way great and covers all possible filters and sort with great speed. So for one the models Lead I am just testing instantsearch.js UI on its livewire view.
f
just tested the games demo with this, and it works just fine:
Copy code
<div>
    <h1>Search Game</h1>
    <div class="container">
    <div class="search-panel">
        <div class="search-panel__results">
            <div id="searchbox"></div>
            <div id="hits"></div>
        </div>
    </div>

    <div id="pagination"></div>
</div>
</div>

@assets
    <script src="<https://cdn.jsdelivr.net/npm/typesense@1/dist/typesense.min.js>"></script>
    <script src="<https://cdn.jsdelivr.net/npm/algoliasearch@4.24.0/dist/algoliasearch-lite.umd.js>" integrity="sha256-b2n6oSgG4C1stMT/yc/ChGszs9EY/Mhs6oltEjQbFCQ=" crossorigin="anonymous"></script>
    <script src="<https://cdn.jsdelivr.net/npm/instantsearch.js@4.73.0/dist/instantsearch.production.min.js>" integrity="sha256-gBDtQ3AJfoB4Sd7Yb5UWcgH5l1E3m38O4iXDuGjORMQ=" crossorigin="anonymous"></script>
    <script src=" <https://cdn.jsdelivr.net/npm/typesense-instantsearch-adapter@2.8.0/dist/typesense-instantsearch-adapter.min.js> "></script>
    <link rel="stylesheet" href="<https://cdn.jsdelivr.net/npm/instantsearch.css@8.3.0/themes/reset-min.css>" integrity="sha256-D+cGTF0LVHjuEf+CDRkHeNw/KTHPg47t1AA/qmzxgtA=" crossorigin="anonymous">
@endassets
@script
<script>
    const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
        server: {
            apiKey: 'xyz', // Be sure to use an API key that only allows searches, in production
            nodes: [
                {
                    host: 'localhost',
                    port: '8108',
                    protocol: 'http',
                },
            ],
        },
        // The following parameters are directly passed to Typesense's search API endpoint.
        //  So you can pass any parameters supported by the search endpoint below.
        //  queryBy is required.
        //  filterBy is managed and overridden by InstantSearch.js. To set it, you want to use one of the filter widgets like refinementList or use the `configure` widget.
        additionalSearchParameters: {
            queryBy: 'name',
        },
    });
    const searchClient = typesenseInstantsearchAdapter.searchClient;

    const search = instantsearch({
        searchClient,
        indexName: 'games',
    });

    search.addWidgets([
        instantsearch.widgets.searchBox({
            container: '#searchbox',
        }),
        instantsearch.widgets.configure({
            hitsPerPage: 8,
        }),
        instantsearch.widgets.hits({
            container: '#hits',
            templates: {
                item(item) {
                    return `
                        <div>
                          <div class="hit-name">
                            ${item._highlightResult.name.value}
                          </div>
                        </div>
                      `;
                },
            },
        }),
        instantsearch.widgets.pagination({
            container: '#pagination',
        }),
    ]);

    search.start();
</script>
@endscript
s
I have below key files. And I installed instantsearch.js and typesense adaptor using npm. Currently i am using sail in local environment. My scout configuration has a corresponding collection.
you mean on a livewire.
f
Maybe try using the CDNs from jsdelivr and see if that makes any difference? Also use the
@assets
tag for importing using jsdelivr
s
Is this correct? hits({ container: "#hits", templates: { item:
Copy code
<div class="hit-name">
                    @{{ highlight.highlighted(item.title) }}
                </div>
, }, }),
<div class="hit-name"> {{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}} </div> this was repeatedly giving syntax error of unexpectd ';'
f
It errors for me as well. Try using this:
Copy code
<div>
                          <div class="hit-name">
                            ${item._highlightResult.name.value}
                          </div>
                      </div>
s
Cool. I used your code with my index and i see result with pagination. <!-- resources/views/livewire/search.blade.php --> <div> <div> <h1>Search Game</h1> <div class="container"> <div class="search-panel"> <div class="search-panel__results"> <div id="searchbox"></div> <div id="hits"></div> </div> </div> <div id="pagination"></div> </div> </div> @assets <script src="https://cdn.jsdelivr.net/npm/typesense@1/dist/typesense.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.24.0/dist/algoliasearch-lite.umd.js" integrity="sha256-b2n6oSgG4C1stMT/yc/ChGszs9EY/Mhs6oltEjQbFCQ=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.73.0/dist/instantsearch.production.min.js" integrity="sha256-gBDtQ3AJfoB4Sd7Yb5UWcgH5l1E3m38O4iXDuGjORMQ=" crossorigin="anonymous"></script> <script src=" https://cdn.jsdelivr.net/npm/typesense-instantsearch-adapter@2.8.0/dist/typesense-instantsearch-adapter.min.js "></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@8.3.0/themes/reset-min.css" integrity="sha256-D+cGTF0LVHjuEf+CDRkHeNw/KTHPg47t1AA/qmzxgtA=" crossorigin="anonymous"> @endassets @script <script> const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({ server: { apiKey: 'xyz', // Be sure to use an API key that only allows searches, in production nodes: [ { host: 'localhost', port: '8108', protocol: 'http', }, ], }, // The following parameters are directly passed to Typesense's search API endpoint. // So you can pass any parameters supported by the search endpoint below. // queryBy is required. // filterBy is managed and overridden by InstantSearch.js. To set it, you want to use one of the filter widgets like refinementList or use the
configure
widget. additionalSearchParameters: { queryBy: 'title', }, }); const searchClient = typesenseInstantsearchAdapter.searchClient; const search = instantsearch({ searchClient, indexName: 'leads_index', }); search.addWidgets([ instantsearch.widgets.searchBox({ container: '#searchbox', }), instantsearch.widgets.configure({ hitsPerPage: 8, }), instantsearch.widgets.hits({ container: '#hits', templates: { item(item) { return ` <div> <div class="hit-name"> ${item._highlightResult.title.value} </div> </div> `; }, }, }), instantsearch.widgets.pagination({ container: '#pagination', }), ]); search.start(); </script> @endscript </div>
1
f
So I take it we've got the problem sorted?
s
Let me try all widgets? But I feel we should have better ways especially for livewire and blade. Livewire genrally recommed using alpinejs. And I feel we should have blade components mapped to instantsearch.js
This link someone implement might help. https://github.com/InterNACHI/blade-alpine-instantsearch
But this i guess focuss on algolia and there is no documentation on how to use it.
f
Yeah, if this project picks up some traction, you should use the components in your own project. It has to provide the ability to pass the client itself on the component, much like how the adapter is used on Javascript
s
Thanks @Fanis Tharropoulos.
f
Glad to be of help 😁