ArticleController
<?php
namespace App\Http\Controllers\Articles;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\ArticleCategory;
use App\Models\Article;
use App\Models\ArticleTranslation;
use Lang;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$locale = Lang::locale();
// $locale = Lang::getLocale();
$articles = Article::withTranslations($locale)->get();
return $articles;
}
Article.vue component
<template>
<div>
<div v-for="article in articles" :key="article.articles">
<div v-for="translation in article.translations">
<h4>{{ translation.title }}</h4>
{{ translation.subtitle }}
{{ translation.content }}
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { mapGetters } from 'vuex'
export default {
layout: 'basic',
computed: mapGetters({
locale: 'lang/locale'
}),
data: function () {
return {
articles: []
}
},
watch: {
locale: 'lang/locale'
},
mounted() {
console.log(this.locale)
this.getArticles ()
},
methods: {
getArticles() {
var app = this;
axios.get('/api/articles')
.then(response => {
// JSON responses are automatically parsed.
this.articles = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
api.php
Route::group(['middleware' => 'guest:api'], function () {
Route::post('login', 'Auth\LoginController#login');
Route::post('register', 'Auth\RegisterController#register');
Route::post('password/email', 'Auth\ForgotPasswordController#sendResetLinkEmail');
Route::post('password/reset', 'Auth\ResetPasswordController#reset');
Route::resource('articles', 'Articles\ArticleController');
});
I'm detecting the locale on the frontend and using it in the controller to fetch articles for that locale. This works only when i refresh the page everytime.
I'm using this template which has a navbar with language switcher
How to watch the locale and fetch the articles again in order to refresh the dom without refreshing the page.
<script>
import axios from 'axios'
import { mapGetters } from 'vuex'
export default {
layout: 'basic',
computed: mapGetters({
locale: 'lang/locale'
}),
data: function () {
return {
articles: []
}
},
watch: {
locale: function (newLocale, oldLocale) {
this.getArticles()
}
},
mounted() {
console.log(this.locale)
this.getArticles ()
},
methods: {
getArticles() {
var app = this;
axios.get('/api/articles')
.then(response => {
// JSON responses are automatically parsed.
this.articles = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
Tried this and it worked!
Related
I am new to Typescript with vuex. I simply want to fetch user list from the backend. Put in the store. I declared custom user type
export interface User {
id: number;
firstName: string;
lastName: string;
email: string;
}
in my vuex.d.ts file, I declare store module like:
import { Store } from "vuex";
import { User } from "./customTypes/user";
declare module "#vue/runtime-core" {
interface State {
loading: boolean;
users: Array<User>;
}
interface ComponentCustomProperties {
$store: Store<State>;
}
}
in my store I fetch the users successfully and commit the state:
import { createStore } from "vuex";
import axios from "axios";
import { User, Response } from "./customTypes/user";
export default createStore({
state: {
users: [] as User[], // Type Assertion
loading: false,
},
mutations: {
SET_LOADING(state, status) {
state.loading = status;
},
SET_USERS(state, users) {
state.users = users;
},
},
actions: {
async fetchUsers({ commit }) {
commit("SET_LOADING", true);
const users: Response = await axios.get(
"http://localhost:8000/api/get-friends"
);
commit("SET_LOADING", false);
commit("SET_USERS", users.data);
},
},
getters: {
userList: (state) => {
return state.users;
},
loadingStatus: (state) => {
return state.loading;
},
},
});
I set the getters, I sense that I don't need to set getter for just returning state however this is the only way I could reach the data in my component. Please advise if there is a better way to do it. In my component I accessed the data like:
<div class="friends">
<h1 class="header">Friends</h1>
<loading v-if="loadingStatus" />
<div v-else>
<user-card v-for="user in userList" :user="user" :key="user.id" />
<pagination />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { mapGetters } from "vuex";
import { User } from "../store/customTypes/user";
=import UserCard from "../components/UserCard.vue";
import Loading from "../components/Loading.vue";
import Pagination from "../components/Pagination.vue";
export default defineComponent({
name: "Friends",
components: {
UserCard,
Loading,
Pagination,
},
static: {
visibleUsersPerPageCount: 10,
},
data() {
return {
users: [] as User[],
currentPage: 1,
pageCount: 0,
};
},
computed: {
...mapGetters(["loadingStatus", "userList"]),
},
mounted() {
this.$store.dispatch("fetchUsers");
this.paginate()
},
methods: {
paginate () {
// this.users = this.$store.state.users
console.log(this.$store.state.users)
console.log(this.userList)
}
}
});
</script>
Now when I get userList with getters, I successfully get the data and display in the template. However When I want to use it in the method, I can't access it when component is mounted. I need to paginate it in the methods. So I guess I need to wait until promise is resolved however I couldn't figure out how. I tried
this.$store.dispatch("fetchUsers").then((res) => console.log(res)) didn't work.
What I am doing wrong here?
An action is supposed to return a promise of undefined, it's incorrectly to use it like this.$store.dispatch("fetchUsers").then(res => ...).
The store needs to be accessed after dispatching an action:
this.$store.dispatch("fetchUsers").then(() => {
this.paginate();
});
So I have added a second bus to my code that runs on create, but no matter in which order I call the Busses the second bus (eventBus2) is never called and then returns no data. By printing some console logs I get the feeling that that eventBus2.$on is never executed. Is there some Vue rule that I'm not aware of, any suggestions?
Item.vue
<template>
<div>
<table>
<tr
v-for="item in info"
:key="item.id"
#click="editThisItem(item.id)"
>
<td>{{ item.name}}</td>
<td>{{ item.number}}</td>
<td>{{ item.size}}</td>
</tr>
</table>
</div>
</template>
<script>
import Something from "./Something.vue";
import axios from "axios";
import { eventBus } from "../main";
import { eventBus2 } from "../main";
export default {
components: { Something },
name: "Item",
data() {
return {
selected_item_id: 0,
info: null,
};
},
methods: {
editThisItem(bolt) {
this.selected_item_id = bolt;
eventBus2.$emit("itemWasSelected", this.selected_item_id);
eventBus.$emit("newTabWasAdded", "edit-item");
},
},
mounted() {
axios
.get("http://localhost:8080/items")
.then((response) => (this.info = response.data._embedded.artikli));
},
};
</script>
EditItem.vue
<script>
import Something from "./Something.vue";
import axios from "axios";
import { eventBus2 } from "../main";
export default {
components: { Something},
name: "Edit-item",
data() {
return {
info: null,
select_number: 0,
select_name: "",
selected_item_id: -1,
priv_item: {
id: 0,
size: "big"
},
};
},
mounted() {
if (this.selected_item_id != -1) {
axios
.get("http://localhost:8080/items/" + this.selected_item_id)
.then((response) => (this.priv_item = response.data));
}
},
created() {
eventBus2.$on("itemWasSelected", (data) => {
this.selected_item_id = data;
console.log(" + " + data);
//this console log does not even print the "+", the data is empty
});
console.log(this.selected_item_id);
},
};
</script>
main.js
export const eventBus = new Vue();
export const eventBus2 = new Vue();
you're expecting itemWasSelected and emitting WasSelected they should be the same.
PD: that can be done in one line.
import { eventBus } from "../main";
import { eventBus2 } from "../main";
import { eventBus, eventBus2 } from "../main";
Variable named jso disappears when the page is refreshed. Also, is there any other way to send store information than method?
It will work when the page is refreshed and reopened without using a button.
view/userProfile.vue
<template>
<div>
<v-list>
<v-list-item>
{{userdata['username']}}</v-list-item>
<v-list-item> {{userdata['id']}}</v-list-item>
<v-list-item> {{userdata['email']}}</v-list-item>
<v-list-item> {{userdata['phone_number']}}</v-list-item>
<v-list-item> {{userdata['first_name']}} {{userdata['last_name']}}</v-list-item>
<v-list-item > {{userdata['gender']}}</v-list-item>
{{userdata['educational_status']}}
</v-list>
<hr>
{{this.profileData.gender}}
{{jso}} --> variable that disappears on page refresh
</div>
</template>
<script>
Only jso disappears on refresh page:
import Vuetify from "vuetify"
import {UserData} from "../../store/userModule";
import {JsonChoiceData} from "../../store/choiceStore";
import jsonDict from "../../jsonFiles/data.json"
import JsonFile from "../../jsonFiles/jsonfile"
export default {
name: "userProfile",
data(){
return {
profileData:{
username:'',
first_name:'',
last_name: '',
email:'',
phone_number:'',
birthday:'',
gender:'',
educational_status:'',
martial_status:'',
},
}
},
created(){
this.$store.dispatch('initUserData')
this.$store.dispatch('inijson')
},
computed:{
jso(){
return this.$store.getters.user
},
userdata (){
for(var i in this.$store.getters.getUser){
return this.$store.getters.getUser[i]
}
return this.$store.getters.getUser},
},
methods:{
getjsondata(){
console.log(this.userdata['gender'] + "methods")
this.$store.dispatch('getJsonData',this.userdata['gender'])
console.log(this.userdata['gender'])
}
},
mounted(){
this.getjsondata()
}
}
</script>
<style scoped>
</style>
store
import JsonFiles from '../jsonFiles/jsonfile'
import Jsondict from '../jsonFiles/data.json'
import jsonfile from "../jsonFiles/jsonfile";
export const JsonChoiceData = {
state: {
user: [],
},
getters: {
user(state) {
return state.user
},
},
mutations: {
inijson(state, user) {
state.user = user
},
getsonData: function (state, userinput) {
var getJsoncleandata = jsonfile.JsonData(userinput, Jsondict.Gender)
state.user = getJsoncleandata
return getJsoncleandata
}
},
actions: {
inijson(context){
context.commit('inijson', this.getsonData)
},
getJsonData(context,userinput){
context.commit('getsonData',userinput)
}
}
}
getsonData is a mutation and shouldn't be used as payload of another mutation. You are also trying to dispatch initUserData action which is not inside your store. I think that you can try to commit getsonData mutation inside your inijson action.
mutations: {
...,
getsonData: function(state, userinput) {
const getJsoncleandata = jsonfile.JsonData(userinput, Jsondict.Gender);
state.user = getJsoncleandata;
}
...
},
actions: {
inijson(context) {
context.commit('getsonData', null)
},
...
}
Then inside created hook of your component dispach only inijson action:
...
created() {
this.$store.dispatch('inijson')
},
...
If you see strange date make sure that jsonfile.JsonData(userinput, Jsondict.Gender) doesn't return a Promise.
Instead of using global $store you can also consider to use vuex store mappers. component binding helpers
I try to create a custom plugin to store data to use it as global. this is my custom plugin
import {remove} from 'lodash'
export const notifications = {
install(Vue, options = {}) {
Vue.prototype.$notifs = {
count: 0,
notifications: []
}
Vue.prototype.$pushNotifs = ({content, type, timeout}) => {
Vue.prototype.$notifs.count++
Vue.prototype.$notifs.notifications.push({content, type, timeout, id: Vue.prototype.$notifs.count})
}
Vue.prototype.$removeNotifs = ({id}) => {
Vue.prototype.$notifs.notifications = remove(Vue.prototype.$notifs.notifications, (item) => item.id !== id)
}
Vue.mixin({
computed: {
$notifications() {
return this.$notifs.notifications
}
}
})
}
}
when i try to run $pushNotifs methods from my vue template to push some data to $notif.notifications, the template won't updated (but the value its there)
...
methods: {
pushNotifs() {
this.$pushNotifs({content: 'contoh content', type: 'success', timeout: 500})
console.log(this.$notifs.notifications); // has the value
}
}
....
how to make it reactive to the template?
I followed this answer.
Basically, you create a class and use a new Vue instance to provide reactivity.
plugin.js:
import Vue from 'vue';
class Notif {
constructor() {
this.VM = new Vue({
data: () => ({
notifs: [],
count: 0,
}),
});
}
get state() {
return this.VM.$data;
}
get count() {
return this.VM.$data.count;
}
}
const notif = {
Store: Notif,
install (Vue, options) {
Vue.mixin({
beforeCreate() {
this.$notif = options.store;
}
});
},
};
export default waiter;
then to use it (in main.js):
import notif from './plugins/plugin.js';
Vue.use(notif, {
store: new notif.Store()
});
and access it:
this.$notif.state.notifs.push('some notif');
in the template:
<span>{{$notif.count}}</span>
so here state gives you access to all the data, or you can expose individual items as i've shown here.
I'm trying to use vue-async-data to fetch data asynchronously before rendering my Vue component, but I'm having no success. I'm not getting any erros, but it simply doesn't work.
Here's my main.js code:
import Vue from 'vue'
import VueAsyncData from 'vue-async-data'
import router from './router'
import App from './App.vue'
Vue.use(VueAsyncData)
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
And here's my App.vue code:
<template>
<div>
{{ msg }}
<navigation wait-for="async-data"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
msg: 'not loaded yet...'
}
},
asyncData: function (resolve, reject) {
// load data and call resolve(data)
// or call reject(reason) if something goes wrong
setTimeout(function () {
// this will call `vm.$set('msg', 'hi')` for you
resolve({
msg: 'hi'
})
}, 1000)
}
}
</script>
The msg value doesn't change at any moment, but the component is still rendered.
Am I missing somenthing?
As Bert Evans stated, vue-async-data doesn't work with Vue 2.0.
I used vue-router and the created function to achieve what I needed (as suggested in: https://router.vuejs.org/en/advanced/data-fetching.html.
<template>
<div>
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<navigation v-if="currentUser"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
loading: true,
error: false,
currentUser: null
}
},
created: function() {
this.fetchUserData()
},
methods: {
fetchUserData: function() {
this.$http.get('/Account/CurrentUserInfo').then(data => {
this.currentUser = data
this.loading = false
}, response => {
this.loading = false
this.error = true
});
}
}
}
</script>