mafortis
mafortis

Reputation: 7138

Laravel search results in second page

I'm working with vuejs in laravel 5.6 and I've made search form with 2 inputs, but i'm not sure how to show results in different page and my data return by json.

Logic

  1. User fill inputs/input -> click search button
  2. User redirects to other page -> see results

Code

controller

public function indexsearch(Request $request)
    {

        $area = request('area');
        $keywords = request('keywords');

        if($keywords){
          $projects = Project::where('title', 'LIKE', "%{$keywords}%")
          ->orWhere('body', 'LIKE', "%{$keywords}%")
          ->orWhere('area', 'LIKE', "%{$keywords}%")
          ->get();
        }else{
          $projects = Project::where('title', 'LIKE', "%{$keywords}%")
          ->orWhere('body', 'LIKE', "%{$keywords}%")
          ->orWhere('area', 'LIKE', "%{$keywords}%")
          ->get();
        }

        return response()->json($projects);
    }

route

Route::get('indexsearch', 'Api\SearchController@indexsearch');

component

<template>
    <div>
      <div class="form-row justify-content-center align-items-center mmt-5">
        <div class="col-md-4">
          <label class="sr-only" for="inlineFormInput">Query</label>
          <input v-model.lazy="keywords" type="text" class="customformdes form-control mb-2" id="inlineFormInput" placeholder="E.g. Larave, Vue, Design, Writer">
        </div>
        <div class="col-md-4">
          <label class="sr-only" for="inlineFormInputGroup">Area</label>
          <input v-model.lazy="area" type="text" class="customformdes form-control mb-2" id="inlineFormInputGroup" placeholder="E.g. Jabodetabek, Medan, Surabaya">
        </div>
        <div class="col-md-2">
          <button type="button" class="customformdes btn btn-block btn-primary mb-2"><i class="fab fa-searchengin"></i> Search</button>
        </div>
      </div>
         // currently this part shows the result as hidden drop-down
        <b-list-group v-if="results.length > 0">
          <b-list-group-item v-for="result in results" :key="result.id" :to="`/projects/${result.slug}`">{{result.title}}</b-list-group-item>
        </b-list-group>


    </div>
</template>

<script>
var _ = require('lodash');
import navbar from './navbar.vue';
export default {
    data() {
        return {
            keywords: null,
            area: null,
            results: []
        };
    },

    watch: {
        keywords(after, before) {
            this.fetch();
        }
    },

    methods: {
        fetch() {
            axios.get('/api/indexsearch', { params: { keywords: this.keywords, area: this.area } })
                .then(response => this.results = response.data)
                .catch(error => {});
        }
    }
}
</script>

Issues

  1. By my current control code I cannot get my second input (area) alone, meaning: If I don't fill first input and just fill second input i cannot get results.
  2. I don't know how to show results in other page and not as drop-down in the same page (part is commented in my component code)

Thanks in advance.

Upvotes: 0

Views: 1117

Answers (2)

Julian Paolo Dayag
Julian Paolo Dayag

Reputation: 3729

For your first issue, you can add more watcher for the area:

(Since you are just calling a single method from your watcher, you can just directly use the method's name as the value of your watcher as it is just the same.)

watch: {
  keywords: 'fetch',
  area: 'fetch'
},

you can also use $vm.watch to watch for multiple values at the same time.

Instead of:

watch: {
  keywords(after, before) {
    this.fetch();
  }
},

you can have it like this:

mounted() {

  this.$watch(
    function() {
      return this.keywords + this.area
    },
    (newVal, oldVal) => {
      this.fetch();
    }
  )

}


As for the second issue, you can pass props data to the target page.

See this example code below:

ResultsPage.vue:

<template>
  <div>
      <div v-for="result in results" :key="result.id">{{ result.title }}</div>
  </div>
</template>
<script>
  export default {
    props: ['results']
  }
</script>

router configuration:

import ResultsPage from 'ResultsPage.vue'

new Router({

  routes: [
    // ... some other routes in here
    {
        path: '/results',
        name: 'results',
        props: true,
        component: ResultsPage,
    }
]

})

then you can now navigate to the ResultsPage by using $router.push():

methods: {
  fetch() {
    axios.get('/api/indexsearch', {
        params: {
          keywords: this.keywords,
          area: this.area
        }
      })
      .then(response => {

        this.$router.push({
          name: 'results',
          params: {
            results: response.data
          }
        })

      })
      .catch(error => {});
  }
}

Upvotes: 1

CUGreen
CUGreen

Reputation: 3184

You will need to add $area as your search term to solve the first issue.

And to show the results on a separate page you will need to request a route that returns a view in your search method.

// Controller

public function indexsearch(Request $request)
{

    $area = request('area');
    $keywords = request('keywords');

    if($keywords){
      $projects = Project::where('title', 'LIKE', "%{$keywords}%")
      ->orWhere('body', 'LIKE', "%{$keywords}%")
      ->orWhere('area', 'LIKE', "%{$area}%")
      ->get();
    }else{
      $projects = Project::where('title', 'LIKE', "%{$keywords}%")
      ->orWhere('body', 'LIKE', "%{$keywords}%")
      ->orWhere('area', 'LIKE', "%{$area}%")
      ->get();
    }

    return view('search_results', compact('projects'));
}

If you want to show the results on a separate page then you don't really need vue here.

You can do something like this to submit a form in your view:

<form action="search"> <!-- or whatever your searchindex route is -->
  <div class="form-row justify-content-center align-items-center mmt-5">
    <div class="col-md-4">
      <label class="sr-only" for="inlineFormInput">Query</label>
      <input v-model.lazy="keywords" type="text" class="customformdes form-control mb-2" id="inlineFormInput" placeholder="E.g. Larave, Vue, Design, Writer">
    </div>
    <div class="col-md-4">
      <label class="sr-only" for="inlineFormInputGroup">Area</label>
      <input v-model.lazy="area" type="text" class="customformdes form-control mb-2" id="inlineFormInputGroup" placeholder="E.g. Jabodetabek, Medan, Surabaya">
    </div>
    <div class="col-md-2">
      <button type="button" class="customformdes btn btn-block btn-primary mb-2"><i class="fab fa-searchengin"></i> Search</button>
    </div>
  </div>
</form>

Then in your search results blade (search_results.blade.php) view:

<div>
    <b-list-group">
        @foreach($projects as $project)
        <b-list-group-item>{{ $project->title }}</b-list-group-item>
        @endforeach
    </b-list-group>
</div>

I hope this helps solve your issue.

Upvotes: 0

Related Questions