简体   繁体   中英

on-click method on a button that directs to another component

I have a main app page component with a search bar. The Search results that come back is in cards And I am looking to set up a "Click here to view more detail" that would be placed in each card. And it would link to the Details page of the one result clicked. How do I link these components on Vue and if the id could be passed? I am hoping that upon click of the button the component renders on the same page and not a new tab.

Thank you!

App.vue

 <template>
  <div id="app">
    <Header/>
    <SearchForm v-on:search="search"/>
    <SearchResults
      v-if="results.length > 0"
      v-bind:results="results"
      v-bind:reformattedSearchString="reformattedSearchString"/>

    <Pagination
      v-if="results.length > 0"
      v-bind:prevPageToken="api.prevPageToken"
      v-bind:next_page="api.scrollId"
      v-on:prev-page="prevPage"
      v-on:next-page="nextPage"
    />
  </div>
</template>

<script>
import Header from './components/layout/Header';
import SearchForm from './components/SearchForm';
import SearchResults from './components/SearchResults';
import Pagination from './components/Pagination';
import Details from './components/Details'
import axios from 'axios';

export default {
  name: 'app',
  components: {
    Header,
    SearchForm,
    SearchResults,
    Pagination,
    Details
  },

   data() {
    return {
      results: [],
      reformattedSearchString: '',
      api: {
        baseUrl: 'https://test.org/api/v1/articles?',
        max: 25,
        q: '',
        prevPageToken: '',
        scrollId: ''
      }
    };
  },


   methods: {
    search(searchParams) {
      this.reformattedSearchString = searchParams.join(' ');
      this.api.q = searchParams.join('+');
      const { baseUrl, q, max} = this.api;
      const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&recent&max=${max}&full_results`;
      this.getData(apiUrl);

    },

    prevPage() {
      const { baseUrl, q, max, prevPageToken } = this.api;
      const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&pageToken=${prevPageToken}`;
      this.getData(apiUrl);
    },

    nextPage() {
      const { baseUrl, q, max,scrollId } = this.api;
      const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&recent&full_results&scroll_id=${scrollId}`;
      this.getData(apiUrl);
    },

    getData(apiUrl) {
      axios
        .get(apiUrl)

        .then(res => {
          this.results = res.data.success.data;
          this.api.prevPageToken = res.data.success.data.prevPageToken;
          this.api.next_page = res.data.scrollId;

        })
        .catch(error => console.log(error))
    }
  }
};
</script>

Searchresults.vue

<template>
  <div class="container mb-3">
    <div class="d-flex mb-3">
      <div class="mr-auto">
        <h3>Search Results for "{{ reformattedSearchString }}"</h3>
      </div>
      <div class="btn-group ml-auto" role="group">
        <button
          @click="changeDisplayMode('grid')"
          type="button"
          class="btn btn-outline-secondary"
          v-bind:class="{ active: displayMode === 'grid' }"
        >
          <i class="fas fa-th"></i>
        </button>
        <button
          @click="changeDisplayMode('list')"
          type="button"
          class="btn btn-outline-secondary"
          v-bind:class="{ active: displayMode === 'list' }"
        >
          <i class="fas fa-list"></i>
        </button>
      </div>
    </div>

    <div class="card-columns" v-if="displayMode === 'grid'">
      <div class="card" v-bind:key="result._gddid" v-for="result in results">
        <ArticleGridItem v-bind:result="result"/>
      </div>
    </div>
    <div v-else>
      <div class="card mb-2" v-bind:key="result._gddid" v-for="result in results">
        <ArticleListItem v-bind:result="result"/>
      </div>
    </div>
  </div>
</template>

<script>
import ArticleListItem from './ArticleListItem';
import ArticleGridItem from './ArticleGridItem';
import Details from './Details';

export default {
  name: 'SearchResults',
  components: {
    ArticleListItem,
    ArticleGridItem,
    Details,
  },
  data() {
    return {
      title: 'Search Results',
      displayMode: 'grid'
    };
  },
  methods: {
    changeDisplayMode(displayMode) {
      this.displayMode = displayMode;
    }
  },
  props: ['results', 'reformattedSearchString']
};
</script>

ArticleListItem.vue

<template>
  <div>
    <div class="card-body"> 
    <h6 class="card-text">{{ result.title }}</h6>

      <p
        class="card-subtitle mb-2 text-muted"
      >{{ result.publisher }} | {{ result.journal }} | {{ result.year }}</p>
      <a :href="'https://test.org/api/articles?docid=' + result._gddid" target="_blank">
        <i class="fa fa-download"  alt="Download"> </i>
      </a>
     <router-link>
    <v-btn dark to="{name:'Details', params: {id: article._gddid}}">
    Click here for more Details
    </v-btn>
  </router-link>
  <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ArticleListItem',
  props: ['result'],   
}

</script>

index.js

  import Vue from 'vue';
import Router from 'vue-router';
import Details from '@/components/Details';


Vue.use(Router)

export default new Router({
  routes: [
    {
     path: '/Details/:id',
     name: 'Details',
     component: Details
   }
 ]
});

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router/index.js'
import moment from 'moment'


Vue.config.productionTip = false

Vue.filter('formatDate', function (value) {
  if (!value) return ''
  return moment(value.toString()).format('MM/DD/YYYY hh:mm')
})

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

use <router-link> tag for it to work

When using Vue Router, instead of using <a> tags, you can use <router-link> tags.

Here's a basic example similar tothe Vue Router documentation for dynamic route matching .

If you have this...

const router = new VueRouter({
  routes: [
    { path: '/Details/:id', component: DetailsPage, name: 'Details' }
  ]
})

You can have router-links declared in, say, your ArticleListItem.vue file like:

<v-btn dark to="{name:'Details', params: {id: article.id}}">
  Click here for more Details
</v-btn>

You can't just go to a generic details page. There needs to be some dynamic part of the route (which I've called id in my example) to specify which article's page to go to.

Edit

An additional problem is in your Router setup:

From the Vue Router docs :

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

...needs to be in your main.js file. The declaration of Vue.use in your index.js file isn't doing anything. Just for conciseness. Make it one file:

WhateverYourOneTrueFileIsGoingToBeCalled.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import Details from '@/components/Details';
import moment from 'moment'


Vue.config.productionTip = false

Vue.filter('formatDate', function (value) {
  if (!value) return ''
  return moment(value.toString()).format('MM/DD/YYYY hh:mm')
})

Vue.use(VueRouter)

router = new VueRouter({
  routes: [
    {
     path: '/Details/:id',
     name: 'Details',
     component: Details
   }
 ]
})

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM