skip to Main Content

I have been working on a news app, using Vue 3 and the News API.

I am currently working on a search functionality.

In App.vue I have:

<template>
  <TopBar @search="doSearch" />
  <div class="container">
     <HomeView searchString="searchTerm" v-if="!searchTerm.length" />
     <SearchResultsView searchString="searchTerm" v-if="searchTerm.length" />
  </div>
  <AppFooter />
</template>

<script>
import TopBar from '@/components/TopBar.vue';
import AppFooter from '@/components/AppFooter.vue';
import HomeView from '@/views/HomeView.vue';
import SearchResultsView from '@/views/SearchResultsView.vue';

export default {
  name: 'App',
  components: {
    TopBar,
    AppFooter,
    HomeView,
    SearchResultsView
  },

  data: () => ({
    searchTerm: ''
  }),

  methods: {
    doSearch: function(searchTerm) {
      this.searchTerm = searchTerm;
      console.log(this.searchTerm);
    }
  }
}
</script>

I emit the search event form the TopBar.vue component, where the search form is:

<template>
  <nav class="navbar py-1 sticky-top navbar-expand-md">
    <div class="container-fluid">
      <form ref="searchForm" class="search_form w-100 mx-auto mt-2 mt-md-0">
          <div class="input-group">
            <input
              @change="handleChange"
              v-model="searchTerm"
              class="form-control search-box"
              type="text"
              placeholder="Search..."
            />
            <div class="input-group-append">
              <button class="btn" type="button">
                <font-awesome-icon :icon="['fas', 'search']" />
              </button>
            </div>
          </div>
        </form>
    </div>
  </nav>
</template>

<script>
export default {
  name: "TopBar",

  methods: {
    handleChange(event){
      this.$emit('search', event.target.value)
    }
  }
};
</script>

The search string is correctly "captured" by the root App.vue component. I try to pass it to the ArticleList.vue component, so that it becomes a part of the endpoint used by the component:

<template>
  <div v-if="articles.length" class="row">
    <div
      v-for="article in articles"
      :key="article._id"
      class="col-xs-12 col-sm-6 col-lg-4 col-xl-3"
    >
      <ArticleCard :article="article" />
    </div>
  </div>
  <p v-else class="text-center">
    No articles to display
  </p>
</template>

<script>

import ArticleCard from './ArticleCard.vue';

export default {
  name: "NewsList",
  components: {ArticleCard},

  props: {
    whatToShow: {
      type: String,
      required: true,
    },

    searchString: {
      type: String,
      required: true,
      default: ''
    }
  },

  data: () => ({
    language: 'en',
    page_size: 24,
    current_page: 1,
    articles: [],
  }),

  mounted() {
    this.getArticles();
  },

  methods: {
    getArticles() {
      let endpoint = `${process.env.VUE_APP_API_URL}/${this.$props.whatToShow}?q=${this.$props.searchString}&language=${this.language}&page_size=${this.page_size}&page=${this.current_page}&apiKey=${process.env.VUE_APP_API_KEY}`;

      console.log(endpoint);

      this.$axios
        .get(endpoint)
        .then((response) => {
          this.articles = response.data.articles;
          console.log(this.articles);
        })
        .catch((err) => console.log(err));
    },
  }
};

The problem

The searchString prop in the endpoint variable above does not update upon doing a search (with "money" for example) and console.log(endpoint) outputs

https://newsapi.org/v2/everything?q=&language=en&page_size=24&page=1&apiKey=myappykey123secret

instead of

https://newsapi.org/v2/top-headlines?q=money&language=en&page_size=24&page=1&apiKey=myappykey123secret

Questions

  1. What am I doing wrong?
  2. What is the most reliable way to fix this issue?

3

Answers


  1. Yes you are correct, searchString updated in App.vue but you are not watching this change in ArticleList component.

    The request method getArticles only trigger on mounted. You have to watch searchString prop and trigger getArticles() method again

    Login or Signup to reply.
  2. The code has too many errors:

    1. as @BoussadjraBrahim pointed out you don’t bind prop in App.vue
    2. in TopBar.vue you have ref='searchForm' and v-model='searchTerm' but the refs searchFormandsearchTerm` are not defined at all.
    3. in TopBar.vue you didn’t declare for emits so custom event search will never be caught by doSearch function
    4. in ArticleList.vue you don’t even listen for changes so only when this component is mounted does it send a request to endpoint and it doesn’t react at all
    Login or Signup to reply.
  3. Where do you try to send the results to NewsList component from ArticleList.vue? You did not post where do you do the binding.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search