returning article by id -- vue router, vuex - vue.js

I am trying to return article ID and go the detail page for that id. I did something like below. But in the end it's not working... in the console there is an error popping up and pointing that:
api/v1/article[object%20Object]:1 Failed to load resource: the server
responded with a status of 404 (Not Found)
I need some help because I am a bit lost here... What I am missing here? what I do wrong?
Vuex
export const articles = {
state: {
article: {},
},
mutations: {
setArticle(state, article){
state.article = article;
},
},
getters: {
loadArticle(state){
return state.article;
},
},
actions: {
getArticle(id){
axios.get("api/v1/article" + id)
.then(response => {
this.commit('setArticles', response.data);
})
.catch(error => {
console.log(error);
})
},
}
}
Routes
{
path: "detail/:id",
name: "detail",
component: Vue.component("Detail", require("./pages/Detail.vue").default),
meta: {
requiresAuth: true
}
},
Article Component
export default {
components: {
maps,
},
data(){
return {
};
},
created(){
this.$store.dispatch( 'getArticle', {
id: this.$route.params.id
});
},
computed: {
article(){
return this.$store.getters.loadArticle;
}
}
}
Link to the article id
<router-link :to="{ name: 'detail', params: { id: item.id } }">詳細を見る</router-link>

Update
First parameter to store action is the store properties itself. This is the reason you get the store object. You need to receive id or any payload as second parameter.
actions: {
getArticle({ commit }, id){
axios.get("api/v1/article" + id)
.then(response => {
commit('setArticles', response.data);
})
.catch(error => {
console.log(error);
})
},
}
Here you see this
created(){
this.$store.dispatch( 'getArticle', {
id: this.$route.params.id
});
},
You are passing an object as parameter-
{
id: this.$route.params.id
}
You should be doing this instead -
created(){
this.$store.dispatch( 'getArticle', this.$route.params.id);
},

Related

How can I update the comments without refreshing it?

First, I'm using vuex and axios.
store: commentService.js
components:
CommentBox.vue (Top components)
CommentEnter.vue (Sub components)
This is the logic of the code I wrote.
In the store called commentService.js, there are mutations called commentUpdate.
And There are actions called postComment and getComment.
At this time, In the component called CommentBox dispatches getComment with async created().
Then, in getComment, commentUpdate is commited and executed.
CommentUpdate creates an array of comments inquired by getComment and stores them in a state called commentList.
Then I'll get a commentList with "computed".
CommentEnter, a sub-component, uses the commentList registered as compounded in the CommentBox as a prop.
The code below is commentService.js.
import axios from 'axios'
export default {
namespaced: true,
state: () => ({
comment:'',
commentList: []
}),
mutations: {
commentUpdate(state, payload) {
Object.keys(payload).forEach(key => {
state[key] = payload[key]
})
}
},
actions: {
postComment(state, payload) {
const {id} = payload
axios.post(`http://??.???.???.???:????/api/books/${id}/comments`, {
comment: this.state.comment,
starRate: this.state.starRate
}, {
headers: {
Authorization: `Bearer ` + localStorage.getItem('user-token')
}
})
.then((res) => {
console.log(res)
this.state.comment = ''
this.state.starRate = ''
)
.catch((err) => {
alert('댓글은 한 책당 한 번만 작성할 수 있습니다.')
console.log(err)
this.state.comment = ''
this.state.starRate = ''
})
},
async getComment({commit}, payload) {
const {id} = payload
axios.get(`http://??.???.???.???:????/api/books/${id}/comments`)
.then((res) => {
console.log(res)
const { comment } = res.data.commentMap
commit('commentUpdate', {
commentList: comment
})
})
.catch((err) => {
console.log(err)
commit('commentUpdate', {
commentList: {}
})
})
}
}
}
The code below is CommentBox.vue
computed: {
commentList() {
return this.$store.state.commentService.commentList
}
},
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
}
},
async created() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
The code below is CommentEnter.vue
created() {
this.userComment = this.comment
},
props: {
comment: {
type: Object,
default: () => {}
}
},
I asked for a lot of advice.
There were many comments asking for an axios get request after the axios post request was successful.
In fact, I requested an axios get within .then() of the axios post, and the network tab confirmed that the get request occurred normally after the post request.
But it's still not seen immediately when I register a new comment.
I can only see new comments when I refresh it.
How can I make a new comment appear on the screen right away when I register it?
Can't you just call getComment when postComment is finished?
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
}).then(function() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
})
}
},
}
Or since you're using async:
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
await this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
},
}

vue.js accessing this.$route.params in mounted functions

I'm trying to filter table of movies by director ID. The structure of a movie is:
{
id: 1,
title: "They All Lie",
releaseYear: 1989,
director: {
id: 18,
firstName: "Darci",
lastName: "Overill",
nationality: "China",
birthdate: "07/13/1973",
},
},
I want to filter the table using the $route.params.id. I have the following code:
<script>
import axios from "axios";
export default {
data: function () {
return {
directorId: this.$route.params.id,
director: {},
movies: [],
};
},
mounted: function () {
this.getDirector();
this.getMovies();
},
methods: {
getMovies: function () {
let url = "http://localhost:8080/movies/movies";
axios.get(url).then((response) => {
this.movies = response.data;
});
},
getDirector: function () {
let url = "http://localhost:8080/movies/directors/" + this.directorId;
axios.get(url).then((response) => {
this.director = response.data;
});
},
},
computed: {
filteredMovies: function () {
var v = this.$route.params.id;
alert(v);
return this.movies.filter(movie => movie.director.id === v);
},
}
};
</script>
I'm trying to access this.$route.params.id in the filteredMovies function. It works in the .alert function but I can't get the return this.movies.filter(movie => movie.director.id === v); to work. The filtering doesn't work. Any ideas please?
If you want a more elegant solution for parsing the router param id check tis out:
index.js(router file)
{
path: '/directors/:id',
name: 'Directors',
component: myComponentName,
props: (route) => {
const id = Number.parseInt(route.params.id);
return { id }
}
}
Component.vue
props: {
id: {
required: true,
type: Number,
}
With the above implementation you can remove the parsing in the component and also instead of doing this:
this.$route.params.id;
Now you can do:
this.id
And you have the parsed id with best practises ;)
Cheers

How can I make the vue-router change when changing parameters? (vuex)

I'm making an app that has advanced search api.
You can choose what to look for and how to sort the results. The problem is that the page (vue-router) is updated only when the request changes, but it also should be updated when you change the search terms
How i can do this? I don't even have any ideas.
There is my code that is responsible for requesting the API and updating the router when the request is updated
export default {
name: "Search",
data: function () {
return {
selectedTag: 'story',
selectedBy: '',
};
},
components: {
'Item': Item
},
mounted() {
this.items = this.getItems(this.id)
},
beforeRouteUpdate(to, from, next) {
this.items = this.getItems(to.params.id);
next();
},
methods: {
getItems(id) {
this.items = this.$store.dispatch('FETCH_SEARCH_RESULTS', {id, tag: this.selectedTag, by: this.selectedBy});
return this.items;
},
},
created: function () {
this.getItems(this.$route.params.id);
},
computed: {
items: {
get() {
return this.$store.state.searchResults;
},
set(value) {
this.$store.commit("APPEND_SEARCH_RESULTS", value);
}
}
}
}

Making pagination with laravel paginate() and vuex,

I am really having a hard time to solve this problem. Trying to make pagination by using vuex. But I can't update actions when I change the argument value.
For example to go to the next page, I tried a simple way
in component: home
<button #click="nextPage()">{{currentPage}}</button>
I send the argument to actions.
mounted(){
this.$store.dispatch('bridalApi', {currentPage})
},
data(){
return {
currentPage: 1,
};
},
methods: {
nextPage(){
this.currentPage++
}
},
in store.js
I take the argument that I commited.
actions: {
bridalApi({commit}, currentPage){
axios.get("api/bridal?page=" + currentPage)
.then(response => {
commit("setBridals", response.data);
})
.catch(e => {
console.log(e);
})
},
}
it's clearly I can't update the argument inside actions. Because when I click the button, it doesn't go to next page. I mean currentPage inside actions doesn't updated. This was the first way. So, I tried different approach to solve this problem which is like below.
in component: home
<button #click="nextPage()">{{pager}}</button>
I set/get the currentPage, and change the state.
methods: {
nextPage(){
this.pager++
}
},
computed: {
...mapGetters([
"getBridals",
]),
pager: {
set(val){
this.$store.commit("setPagination", val);
},
get(){
return this.$store.state.bridal.pagination.currentPage;
}
},
bridals() {
return this.getBridals;
},
},
in Store.js
state: {
bridals: [],
pagination: {
currentPage: 1,
},
},
mutations: {
setBridals(state, bridal){
state.bridals = bridal;
},
setPagination(state, pager){
state.pagination.currentPage = pager;
},
},
getters: {
getBridals(state){
return state.bridals
},
},
actions: {
bridalApi({commit,state}){
console.log(state.pagination.currentPage)
axios.get("api/bridal?page=" + state.pagination.currentPage)
.then(response => {
commit("setBridals", response.data);
})
.catch(e => {
console.log(e);
})
},
}
But this way is not working either. And I am very much out of ideas. How can I update the actions? What is the right way to use vuex for pagination?...
I am not sure is it's the right way to this. But solved it. Used the first way I mentioned in the question and update home component like below.
data(){
return {
currentPage: 1,
};
},
watch: {
currentPage() {
this.$store.dispatch("bridalApi", this.currentPage);
console.log("ok")
}
},
You can use a mutation for this like
state:{
data:[]
}
mutations:{
SET_DATA:(state , data) => {
return state.data = data
}
}
actions: {
dataApi({commit}, currentPage){
console.log(currentPage)
axios.get("http://website.com/api/endpoint?page="+currentPage)
.then(response => {
commit('SET_DATA' , response.data)
})
.catch(e => {
console.log(e);
})
}
}
I would recommend using LaravelVuePagination package for this.
That way you can have something like:
<pagination :data="bridals" #pagination-change-page="getBridals"></pagination>
export default {
name: 'BridlaList',
mounted() {
this.getBridals();
},
methods: {
getBridals(page = 1){
this.$store.dispatch('getBridals',{
page: page
});
},
}

Nuxt asyncData result is undefined if using global mixin head() method

I'm would like to get titles for my pages dynamically in Nuxt.js in one place.
For that I've created a plugin, which creates global mixin which requests title from server for every page. I'm using asyncData for that and put the response into storage, because SSR is important here.
To show the title on the page I'm using Nuxt head() method and store getter, but it always returns undefined.
If I place this getter on every page it works well, but I would like to define it only once in the plugin.
Is that a Nuxt bug or I'm doing something wrong?
Here's the plugin I wrote:
import Vue from 'vue'
import { mapGetters } from "vuex";
Vue.mixin({
async asyncData({ context, route, store, error }) {
const meta = await store.dispatch('pageMeta/setMetaFromServer', { path: route.path })
return {
pageMetaTitle: meta
}
},
...mapGetters('pageMeta', ['getTitle']),
head() {
return {
title: this.getTitle, // undefined
// title: this.pageMetaTitle - still undefined
};
},
})
I would like to set title in plugin correctly, now it's undefined
Update:
Kinda solved it by using getter and head() in global layout:
computed: {
...mapGetters('pageMeta', ['getTitle']),
}
head() {
return {
title: this.getTitle,
};
},
But still is there an option to use it only in the plugin?
Update 2
Here's the code of setMetaFromServer action
import SeoPagesConnector from '../../connectors/seoPages/v1/seoPagesConnector';
const routesMeta = [
{
path: '/private/kredity',
dynamic: true,
data: {
title: 'TEST 1',
}
},
{
path: '/private/kreditnye-karty',
dynamic: false,
data: {
title: 'TEST'
}
}
];
const initialState = () => ({
title: 'Юником 24',
description: '',
h1: '',
h2: '',
h3: '',
h4: '',
h5: '',
h6: '',
content: '',
meta_robots_content: '',
og_description: '',
og_image: '',
og_title: '',
url: '',
url_canonical: '',
});
export default {
state: initialState,
namespaced: true,
getters: {
getTitle: state => state.title,
getDescription: state => state.description,
getH1: state => state.h1,
},
mutations: {
SET_META_FIELDS(state, { data }) {
if (data) {
Object.entries(data).forEach(([key, value]) => {
state[key] = value;
})
}
},
},
actions: {
async setMetaFromServer(info, { path }) {
const routeMeta = routesMeta.find(route => route.path === path);
let dynamicMeta;
if (routeMeta) {
if (!routeMeta.dynamic) {
info.commit('SET_META_FIELDS', routeMeta);
} else {
try {
dynamicMeta = await new SeoPagesConnector(this.$axios).getSeoPage({ path })
info.commit('SET_META_FIELDS', dynamicMeta);
return dynamicMeta && dynamicMeta.data;
} catch (e) {
info.commit('SET_META_FIELDS', routeMeta);
return routeMeta && routeMeta.data;
}
}
} else {
info.commit('SET_META_FIELDS', { data: initialState() });
return { data: initialState() };
}
return false;
},
}
}