How to hide results when the query is empty? (with Vue InstantSearch)

Went to create an issue but actually read the template :slight_smile: I’ve seen examples with the .js library and React libraries but can’t really work out how to do this with the scoped templates in the Vue library. Is it possible?

I’ve found one way and that is to create my own searchStore then use it like so:

      <ais-index :search-store="searchStore">
        <ais-search-box></ais-search-box>

        <ais-results v-show="searchStore._helper.state.query.length > 0">
          <template scope="{ result, stack }">
            <h2>
              <ais-highlight :result="result" attribute-name="name"></ais-highlight>
            </h2>
          </template>
        </ais-results>
      </ais-index>

Not sure if this is the best way to achieve it :slight_smile:

Hi @dan2,

Wow, you went quicker than I.
Here is my version:

<template>
  <ais-index :search-store="searchStore">
    <ais-input></ais-input>
    <results v-show="searchStore.query.length > 0"></results>
  </ais-index>
</template>

<script>
import { createFromAlgoliaCredentials } from 'vue-instantsearch';

const searchStore = createFromAlgoliaCredentials('<appId>', '<apiKey>');

export default {
  data() {
    return { searchStore };
  }
}
</script>

I recommend you do not access the _helper directly.
This is an internal implementation detail which might change in the near future.
All goodness from the helper should be available on the store itself.

Also in your example, stack in not a scoped attribute.

Does that help?

Hey @rayrutjes thanks for the quick reply :slight_smile:

Awesome! Just out of interest how do we know .query exists on searchStore it doesn’t appear in my Vue devtools.

I’ve gone with your method though as it is much cleaner, also the stack thing was a hangover from trying to see if i could get searchStore as a scoped variable instead of injecting it myself.

But yea this worked perfectly. Love what you’ve done with the Vue stuff!

The search store is not a Vue component, so that is why it does not appear as part of the Vue dev tools.
Maybe a should take a look at ways to have it appear there anyway. Good feedback!

Ideally, I would like to make it easy to access the search store without having to register it manually like in my example.

Please feel free to open issues on the Vue InstantSearch repository if you encounter more issues or if you have feature requests.

1 Like

Hey @rayrutjes,

This method seems to put my Vue into a wild infinite loop of sorts and it never properly loads. I have to force quit Chrome to load my app again.

Is there any other method to do this?

Cheers!

Hey,

Could you share with us your implementation?

@rayrutjes here it is:

<template>
    <ais-index
        :search-store="searchStore"
        index-name="resources"
        :query-parameters="{ 'page':  page }"
    >
        <ais-search-box class="navbar-search-input el-input" :autofocus="true">
            <ais-input placeholder="What are you looking for?" :class-names="{ 'ais-input': 'el-input__inner' }"></ais-input>
        </ais-search-box>

        <ais-powered-by v-if="open"></ais-powered-by>

        <ais-clear v-if="open">
            <template>
                <i class="fa fa-times" aria-hidden="true" @click="closeSearch"></i>
            </template>
        </ais-clear>

        <div class="search-results-container" v-if="open">
            <header>
                <h1>Search</h1>
            </header>

            <div class="refinement-list">
                <el-card>
                    <fieldset>
                        <legend>Type</legend>

                        <ais-refinement-list attribute-name="type.singular" :sort-by="['name:asc', 'isRefined:desc', 'count:desc']"></ais-refinement-list>
                    </fieldset>
                </el-card>

                <el-card>
                    <fieldset>
                        <legend>Site</legend>
                        
                        <ais-refinement-list attribute-name="site.data.name" :sort-by="['name:asc', 'isRefined:desc', 'count:desc']"></ais-refinement-list>
                    </fieldset>
                </el-card>

                <ais-stats></ais-stats>
            </div>

            <div class="loaded-search-results">
                <ais-results :stack="true">
                    <template scope="{ result }">
                        <el-card>
                            <ais-highlight :result="result" attribute-name="name" v-if="result.name"></ais-highlight>
                            <ais-highlight :result="result" attribute-name="description" v-if="result.description"></ais-highlight>
                        </el-card>
                    </template>
                </ais-results>

                <div v-observe-visibility="loadMore" class="loading-div"></div>
            </div>

            <ais-no-results>
                <template scope="props">
                    No results found for <em>{{ props.query }}</em>.
                </template>
            </ais-no-results>

        </div>
    </ais-index>
</template>

<script>
    import { EventBus } from 'app/utilities/event-bus';
    import { createFromAlgoliaCredentials } from 'vue-instantsearch';

    const searchStore = createFromAlgoliaCredentials('<appId>', '<apiKey>');

    export default {
        props: ['open'],

        data() {
            return {
                page: 1,
                searchStore,
            }
        },

        methods: { 
            closeSearch() {
                EventBus.$emit('closeSearch');
            },

            loadMore(isVisible) {
                if (isVisible) {
                    this.page++;
                }
            },
        }
    }
</script>

I thought perhaps it was because I was defining the index name but then I tried that as well and it made no difference.

I think this is related to the infinite loading implementation which keeps adding 1 to the page.
You should make sure to debounce the loadMore or find a way to throttle the loading of new elements.

Hi all,

I’m trying to implement this behaviour but can’t get it to work.

I must say I’m new with Algolia and also with Vue :sweat_smile:

My console starts to throw red errors like this one: Error in render: "RangeError: Maximum call stack size exceeded."

This is what I have so far:

resources/views/layouts/app.blade.php

...
<script>
    window.algolia = {
        app_id: "{{ config('scout.algolia.id') }}",
        search_key: "{{ config('scout.algolia.secret') }}"
    }
</script>
<script src="{{ asset('js/app.js') }}"></script>
...

navbar.blade.php

...
<algolia-instantsearch></algolia-instantsearch>
...

resources/assets/js/app.js

require('./bootstrap');

window.Vue = require('vue');

import InstantSearch from 'vue-instantsearch';
Vue.use(InstantSearch);

Vue.component('algolia-instantsearch', require('./components/InstantSearch.vue'));

const app = new Vue({
    el: '#app'
});

resources/assets/js/components/InstantSearch.vue

<template>
    <ais-index :search-store="searchStore">
        <ais-input></ais-input>
        <results v-show="searchStore.query.length > 0">
            <template slot-scope="{ result }">
                <h2>
                    <ais-highlight :result="result" attribute-name="name"></ais-highlight>
                </h2>
            </template>
        </results>
    </ais-index>
</template>

<script>
    import { createFromAlgoliaCredentials } from 'vue-instantsearch';

    const searchStore = createFromAlgoliaCredentials(window.algolia.app_id, window.algolia.search_key);

    export default {
        data() {
            return { searchStore };
        }
    }
</script>

Thank you in advance for any kind of help :smile:

Humm, at first sight this looks correct to me :confused:

Any chance you could share a live implementation or try to re-produce the issue on CodePen or JSFiddle?

Sure!
I’m out on a trip this weekend but I’ll try to provide a live implementation on monday.

Thanks :slightly_smiling_face:

EDIT:

Hi Raymond, I’m back from the trip.

I tried to put it in production but my server’s NPM installation does not work as expected. I have the public repository link of the project anyway I hope it’s useful to solve this :slight_smile:

1 Like

@d.lloople thanks for sharing the repo,

Do you mind pointing me to the files where the implementation resides?
I’ll try to submit a quick PR if I see anything,

Thanks!

@rayrutjes Yes of course!

The work is in the develop branch

The template which loads the JS file is in app.blade.php line 45

The main JS file is in app.js

The Vue component file is in InstantSearch.vue

The use of the component is in navbar.blade.php line 17

Tell me if you need anything more. I’ll try to put it in production as soon as possible to see the error, but I’m getting problems with npm on the server :sweat_smile:

Thank you very much!

Maybe @julienbourdeau has some time to take a look :wink:

It could be because you’re using results instead of ais-results here :smiley:

Thank you @julienbourdeau, that solves the problem.

Now appeared another one, I’m getting the error IndexName is not valid and a 400 Bad Request response.

I searched but with no luck. Sorry for the noob questions.

I finally get it live in my website, you can see the error on the console here:

Thanks for all your time.

Hi,

This error occurs because your didn’t set the searchstore.indexName property here.
You can find the doc at the very bottom of this page: https://community.algolia.com/vue-instantsearch/getting-started/search-store.html#understanding-how-the-search-store-synchronizes-with-algolia

Let me know if it worked :slight_smile:

@rayrutjes, I am trying your code from github on a fresh laravel app. When I add your code in, my browser loads a blank page. If I remove your code, my autocomplete search works no problem. I’m probably doing something wrong. Is there a tutorial I could follow that shows how to implement this feature (hiding results when there is no query)?

Thanks!

your code: