Vue CLI clickable dynamic url from a news API - api

I'm fetching data from newsapi.org and I want there to be a clickable link after the headlines so that you can read more about the article. But I can't make it work.
Maybe this is too advanced for me since I'm no good at coding. I thought maybe there was a simple way of making the dynamic urls work.
<template>
<div class="api">
<h1>Latest gossip</h1>
<br />
<div v-for="item of items" v-bind:key="item.id">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}</p>
<a v-bind:href="adress">
{{ item.url }}
</a>
</div>
</div>
</template>
I use axios.
<script>
import axios from "axios";
export default {
name: "Api",
props: ["articles"],
data() {
return {
items: [],
adress: "item.url"
};
},
mounted() {
this.getInfo();
},
methods: {
getInfo() {
axios({
method: "GET",
url:
"https://cors-anywhere.herokuapp.com/https://newsapi.org/v2/top-headlines?country=se&category=entertainment&apiKey=XXX",
dataType: "json",
headers: {
"X-Requested-With": "XMLHttpRequest",
"Access-Control-Allow-Origin": "*"
}
}).then(res => {
/* eslint-disable no-console */
console.log(res.data);
this.items = res.data.articles;
});
}
}
};
</script>

You can use vue-router in that case. You create a route with a parameter /news/:id in router/index.js eg.
const router = new VueRouter({
routes: [
{ path: '/news/:id', component: SingleNews }
]
})
then instead of
<a href=""/></a>
use
<router-link :to="{ name: 'news', params: { id: news.id }">{{news.headline}}</router-link>
And finally, retrieve parameter in a SingleNews.vue component using
this.$route.params.id
You can read more about vue-router and dynamic routes in the documentation https://router.vuejs.org/

So from what I understand, you're going to have a separate url for each different news article. It seems like there is a slight misunderstanding about how that information will be passed into the anchor tag, where it should be coming from, and how you're using data.
First, let's address your data method. If you look at the structure of your data you can see that you have an items property, which is an array and an adress property, which is set to a string.
data() {
return {
items: [],
adress: "item.url"
};
},
The problem here is that adress is not dynamic. It will always be the literal string "item.url", which is to say that it will always represent those characters ("item.url") in that order, but it doesn't actually represent any specific item's url property.
The good news is that you should already be seeing the correct url displayed on your page here:
<a v-bind:href="adress">
{{ item.url }}
</a>
Remember that an anchor tag in this case has two parts:
1. What we're displaying to the user.
2. Where we're telling the browser to redirect to.
The proper syntax here (without Vue) would be something like:
<a href="https://somelinktogoto.com">
Some text to display
</a>
What you're currently saying is: "I want an anchor tag to display the item's url to the user and redirect to whatever is stored in the data property called adress". Since adress is only storing the string "item.url", if you inspect your html that's been generated in your browser, I would suspect that all of your anchor tags look something like this:
<a href="item.url">
https://somenewsarticle.com
</a>
Luckily, the fix here is simple. Since you're already using v-bind, the href can use dynamic information, or information that's stored in your data somewhere, which can be referenced by its name. Then you can choose to display anything you'd like to your user. You can also delete your adress property from data, because it's not serving any purpose if all the urls are contained within items.
Try:
<a v-bind:href="item.url" target="_blank">
Read more...
</a>
data() {
return {
items: [],
}
}
Also, no one is good at coding at first, just keep trying to understand how data is flowing and you'll get there!

This line worked out great! Thank you!
<a v-bind:href="item.url" target="_blank">Read more here: </a>
I also deleted the adress data.

Related

How do I programmatically bind in video player URLs in Nuxt/Vue?

I was looking for an idea of how to programmatically bind in video player urls. I understand the idea of using img and doing v-for and a :src, but the url for my videos get put in the data of the script. Is it possible to bind and make these programmatic as well? Here is an example of a working script now, but I just have to replace this as a component for every single video manually.
<template>
<div class="player">
<client-only>
<video-player
ref="videoPlayer"
:options="playerOptions"
/>
</client-only>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
playerOptions: {
sources: [{
type: 'application/x-mpegurl',
src: 'myvideo.m3u8'
}],
The above code is working, but I need to have a component for every single video. Then in each component put the same code, but change the name of the src for the m3u8 video. Ideally, I would want to just pass something from an api into the src of the m3u8 and create one dynamic component. The question is, how would I make this dynamic component?
I tried something like this, but couldnt do a :src in the script.
<template>
<div class="player">
<client-only>
<video-player
ref="videoPlayer"
:options="playerOptions"
/>
</client-only>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
playerOptions: {
sources: [{
type: 'application/x-mpegurl',
:src: video.url
}],
#tomdale I'm not sure if i'm understanding your question correctly, but if you want something dynamic you're probably best to remove playerOptions from your data() property and turn it into a computed property.
It could then look something like this,
computed: {
playerOptions() {
return {
sources: [{
type: 'application/x-mpegurl',
src: this.video.url
}]
}
},
}
Your question doesn't really show where you're getting the video and video.url data from, but if the component is working with a collection of video data, you could do something like,
playerOptions() {
let sources = []
let i = 0
while (i < this.videos.length) {
sources.push({
type: 'application/x-mpegurl',
src: this.videos[i].url
})
i++
}
return sources
},
You'll be be able to reference playerOptions the same way that you were in when it was in data(), ie this.playerOptions, however now it will be dynamic.

how to redirect to specific component in vue js

I want to redirect inside a URL without page refresh, without using a router link as below :
<router-link to="/about us " active-class="active">foo</router-link>
I want to print routes like below:
<li class="nav-item phone">
<a class="nav-link" href="contact-us.html">
اتصل بنا
</a>
</li>
My route:
const routes = [
{ path: '/aboutus/', component: AboutUs }
]
Try this
this.$router.push('about')
You may need a workaround for this.
This solution won't change the url either :)
Set an html in the data
data: () => {
return {
html: null
}
}
Get the content of your html file using any request and assign to the html in data section. You can fetch this from any life cycle hook. Here I'm using beforeMount.
beforeMount() {
this.fetchAllEmployees();
axios.get('contact-us.html')
.then(response => {
this.html = response.data;
})
}
Now you can show the html content in your component like this
<template>
<div>
<div v-html="html"></div>
</div>
</template>
To show only when clicking the a tag, you can add another variable in the data which can be used to toggle the value.

Where should route meta data be loaded in a Vue app?

I'm in the process of setting up a VueJs SPA. I'm using vue-router and I'm trying to find the best solution to the following problem. I have a series of routes. Each of which needs to call an API to get the meta data for the given ID.
/industry/:id/overview
/industry/:id/top-stories
/industry/:id/top-tweets
/brand/:id/overview
/brand/:id/top-stories
/brand/:id/top-tweets
I've been looking at using created or beforeRouteEnter/beforeRouteUpdate and I'm a bit lost. Ideally, I would only fetch new data when a new /industry/:id is reached, not when navigating between pages within the same ID. Also, I'd like to avoid having to define the fetch to grab data in every page component. Also don't want to over complicate this, so my question is, Is there a standard method for tackling this issue?
Clarification:
When I say meta here, I mean data returned from an API about the given industry or brand which I pull using the ID in the route. The api call includes the name of the industry/brand which I want to have on page as soon as the page is presented to the user.
I have something similar. I tackle this using the following approach:
I use the same component for all /industry/:id Vue likes to reuse components wherever it can so if two routes (for example /industry/:id/overview and /industry/:id/top-stories) are using the same component it will stay the same.
What does change, however, is the route meta. So if you add a page key to the meta object in the route objects, and probably add a computed property called page that return this.$route.meta.page, you can use v-if attributes to conditionally render any component. So you might have something like <div v-if="page === 'overview'"></div><div v-else-if="page==='top-stories'"></div>
What this allows you to do is fetch all the data from the API during created or mounted lifecycle and store it as the state. Since the route change doesn't reload the component the state stays the same.
Here is a code example
// router.js
const Project = () =>
import(/* webpackChunkName: "projects" */ "./views/projects/_id");
export default new Router({
mode: "history",
routes: [
{
path: "/projects/:project_id/views",
name: "ViewProject",
component: Project,
meta: {
page: "views",
}
},
{
path: "/projects/:project_id/export",
name: "ExportProject",
component: Project,
meta: {
page: "exports"
}
},
{
path: "/projects/:project_id/recommendations",
name: "ProjectRecommendations",
component: Project,
meta: {
page: "recommendations"
}
},
]
});
And here is the template
<template>
<div v-if="project">
<h1>{{ project.name }}</h1>
<router-link :to="/project/someid/views">Views</router-link>
<router-link :to="/project/someid/exports">Exports</router-link>
<router-link :to="/project/someid/recommendations">Recommendations</router-link>
<ul v-if="page==='views">
<li v-for="(view, i) in project.views" :key="i">{{ views }}</div>
</ul>
<ul v-else-if="page==='exports">
<li v-for="(export, i) in project.exports" :key="i">{{ export }}</div>
</ul>
<ul v-else-if="page==='recommendations">
<li v-for="(recommendation, i) in project.recommendations" :key="i">{{ recommendation }}</div>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
project: null
}
},
computed: {
page() {
return this.$route.meta.page;
}
},
mounted() {
this.getProject()
},
methods: {
getProject() {
axios
.get(`/projects/someid`)
.then(res => this.project = res.data)
}
}
}
</script>

How to get route params to work with vue-router and vuex

I'm trying to pass data from a component to $route.params.post but somewhere along the line it's failing and I'm not sure how to get it to work.
In my component I'm using router-link to go to a specific path in my routes file but it's not routing to the specified component.
// Component.vue
<router-link :to="{ path: 'replies', params: { post: postId }}">
<div class="button is-light is-small has-replies" #click=" postId = thread.no ">Replies</div>
//clicking replies will push the thread number to data and load it into the params
</router-link>
export default {
data () {
return {
postId: null
}
}
}
// ./routes/index.js
import Replies from '../components/Replies'
routes: [
{ path: '/', component: Frontpage },
{ path: '/replies/:post', component: Replies }
]
Clicking the button should open the Replies component with the route looking like /replies/# but it's just loading a blank page and ignoring the component entirely. I'm importing vuex-router-sync on my main.js, but I can't tell if that's the issue, but I'm aware it very well may be since I'm not entirely sure I'm using vuex-router-sync correctly.
You can try it like following, as postId is not a URL parameter, but part of the URL itself:
<router-link :to="'replies/'+ postId'">
<div class="button is-light is-small has-replies" #click=" postId = thread.no ">Replies</div>
//clicking replies will push the thread number to data and load it into the params
</router-link>

vue-router route with params not working on page reload

I am using vue-router on my project.
I am able to navigate to my named routes perfectly fine. My only problem is when I use a named route which expects a parameter, it does not load when I refresh the page.
here is my route:
'/example/:username': {
name: 'example-profile',
title: 'Example Profile',
component: ExampleComponent
}
this is how I am using the vue-router route:
<a v-link="{ name: 'example-profile', params: { username: raaaaf } }">
Example Link
</a>
When I select Example Link I get mydomain.com/example/raaaaf.
On first load, it renders the correct template, but when I refresh or manually entered the link on the address bar, I am redirected to my Page Not Found page and the method called when the page is created is not triggered.
This is what I have on my ExampleComponent:
<template>
<div class="small-12 left">
<side-bar></side-bar>
<div class="store-right">
<store-details></store-details>
<store-menu></store-menu>
<store-listings></store-listings>
</div>
</div>
</template>
<script>
export default {
data() {
return {
username: null,
user: null,
}
},
created() {
this.getUser()
},
methods: {
getUser() {
console.log(this.$route.params);
}
}
}
</script>
I don't know if anyone else if facing the same issue, but I was having a problem getting route params on refresh. The route parameter I was trying to get was an ID number and I use that ID to fetch data and populate the page. I found (through many console logs) when I refreshed, the number was turning into a string and thats why the page was not working. I sorted it out but casting the ID to number before using it:
Number($route.params.id)
You need to configure your server properly. Your server is essetially looking for an index file in a /example/raaaaf directory. I'd read through this page carefully: http://router.vuejs.org/en/essentials/history-mode.html