Laravel + Vue.js - how to have a global variable? - laravel

I have a project using Laravel and Vue.js. I guess it wasn't the best idea not to separate them, but we learn from our mistakes ;)
Here is how it works:
I have been struggling trying to put global variables, such as "current user". Now, I am calling /currentuser through axios each time I need it, or I put it in props, but it drives my crazy... How can I make it global?
I am wondering if Vuex could work in my project, as everything is called from Laravel, the routes as well...
I have tried several things in app.js (here are 2 of them, mixed):
var curruser=null;
axios.get('/currmember').then(
response => {
curruser=response.data;
}
);
Vue.mixin({
methods: {
},
data: function() {
return {
myvaiable: '', //this doesn't work eather
get currentUser() {
if(curruser==null){
axios.get('/currmember').then(
response => {
curruser=response.data;
return curruser;
}
);
}
return curruser;
}
}
}
});}
in TestComponent.vue
<template>
<div>
{{currentUser}}
{{myvariable}} <!-- none of them display anything -->
</div>
</template>
Here is how things are working (simplify them very much):
app.js
import Vue from 'vue';
window.Vue = require('vue');
var App = Vue.component('app', require('./App.vue').default, {
name: 'app'
});
var shol = Vue.component('test', require('./components/TestComponent.vue').default);
let lang=localStorage.Lang!=null?localStorage.Lang:'fr';// = document.documentElement.lang.substr(0, 2);
init();
function init(){
const app = new Vue({
el: '#app',
i18n,
components:{test
}
});
var curruser=null;
axios.get('/currmember').then(
response => {
curruser=response.data;
}
);
Vue.mixin({
methods: {
},
data: function() {
return {
currentUser: 'blabla',
get currentUser2() {
if(curruser==null){
axios.get('/currmember').then(
response => {
curruser=response.data;
console.log(curruser);
return curruser;
}
);
}
return curruser;
}
}
}
});}
test.blade.php
#extends('template')
#section('pageTitle', 'test' )
#section('contenu')
<div >
<test></test>
</div>
#endsection
web.php
Route::get('/test', function () {
return view('test');
});

You may use vuex to access current authenticated user:
On app.js:
import Vue from 'vue';
import store from './store';
const app = new Vue({
el: '#app',
store,
i18n,
components:{ test },
created() {
store.dispatch('getUser');
}
});
The store.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {},
},
getters: {
user: state => state.user,
},
mutations: {
setUser(state, user) {
state.user = user;
},
},
actions: {
getUser({ commit }) {
return new Promise((resolve, reject) => {
axios.get('/currmember')
.then(result => {
commit('setUser', result.data);
resolve();
})
.catch(error => {
reject(error.response && error.response.data.message || 'Error.');
});
});
},
}
})
The test component:
<template>
<div>
{{ currentUser }}
</div>
</template>
<script>
export default {
computed: {
currentUser() {
return this.$store.state.user;
}
}
};
</script>

Related

Error in mounted hook (Promise/async): "TypeError: Cannot read properties of undefined (reading 'SET_POST')"

This is the store.js where am consuming the API. I wanted to get the data from the API and display it when loaded. but at the moment am getting two errors
Error in mounted hook (Promise/async): "TypeError: Cannot read properties of undefined (reading 'SET_POST')"
TypeError: Cannot read properties of undefined (reading 'SET_POST')
<template>
<div v-if="!isDataLoaded">
Loading ...Please wait
</div>
<div v-else="isDataLoaded">
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default{
data: () => ({
isDataLoaded: false,
}),
computed:{
...mapGetters([
"GET_POST",
]),
},
methods: {
post() {
return this.$store.getters.GET_POST;
}
},
async mounted() {
await this.$store.actions.SET_POST
this.isDataLoaded = true
}
}
</script>
store.js file
`
import Vue from "vue";
import Vuex from 'vuex';
import axios from "axios";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
form: [],
post: [],
twoChunkPost: []
},
getters: {
GET_POST: state => {
return state.post;
}
},
mutations: {
SET_POST(state, post) {
state.post = post;
},
}
actions: {
SET_POST: async ({ commit }) => {
const options = {
headers: {
"Content-Type": "application/json"
}
};
let { data } = await axios.get(
"/api/post",
options
);
if (data.meta.code === 200) {
let postArray = data.data.post;
let chunkSize = 2;
commit("SET_POST", postArray);
let chunkedArray = chunk(postArray, chunkSize);
commit("SET_CHUNKED_POST", chunkedArray);
}
},
}
});
`

vue-moment issue in laravel-inertia

I tried importing vue-moment and initializing it by using .use(VueMoment) as shown below. But after i do that the whole app shows error. Anyone facing the same problem?
require('./bootstrap');
// Import modules...
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import VueMoment from 'vue-moment' ////////imported vue-moment
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
})
.mixin({
methods: {
route,
validationError(field){
if(this.$page.props.errors && this.$page.props.errors[field]){
return this.$page.props.errors[field];
}
else{
return null;
}
}
} })
.use(InertiaPlugin)
.use(VueMoment) /////use vue-moment
.mount(el);
InertiaProgress.init({ color: '#4B5563' });
This is the error i am getting
first install moment by
npm install moment
<template>
{{today}}
</template>
<script>
import moment from 'moment'
export default {
name:'Home',
data(){
return{
today:moment().startOf('day').toDate(), moment().endOf('day').toDate()
}
}
</script>
there is a working example of how to import 'vue-moment' from my Laravel + inertia project
const vm = new Vue({
metaInfo: {
titleTemplate: title => (title ? `${title} - Ping CRM` : 'Ping CRM'),
},
store,
render: h =>
h(App, {
props: {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => import(`#/Pages/${name}`).then(module => module.default),
},
}),
}).$mount(el)
Vue.use(require('vue-moment'))
Might help someone who is using InertiaJs with Vue and want to declare globally.
In app.js
createInertiaApp({
id: 'app',
setup({ el, App, props}) {
let app = createApp({
render: () => {
return h(App, props);
},
});
//you can declare any other variable you want like this
app.config.globalProperties.$moment = moment;
app.use(
store,
.....
).mount(el);
},
});
Now in the vue file you can call moment by
this.$moment(this.time,'H:m').format('hh:mm a');

How to redirect another router in Vue3 ? (used next.router in Laravel 8 with vue3)

It does not redirect after successfully logged in.
getting a console error TypeError: Cannot read property 'push' of undefine
Here my code.
I'm creating SPA in vue3 with Laravel 8.
import { ref } from "vue";
import { useRoute } from "vue-router";
export default {
setup() {
const form = ref(
{
email: "hudson.vilma#example.net",
password: "password",
isLoading: false,
},
);
const user = ref("");
function login() {
axios.get('/sanctum/csrf-cookie').then(response => {
axios.post('/login', this.form).then(response => {
this.$router.push('/dashboard')
// useRoute.push('/dashboard');
// this.$router.push({ name: "Dashboard" });
}).catch(error => console.log(error)); // credentials didn't match
});
}
return { form, login, user , useRoute};
},
};
</script>
in app.js instant of vue &
require('./bootstrap');
import { createApp } from "vue";
import App from "./view/App.vue";
import router from "./router";
const app = createApp(App);
app.use(router);
app.mount("#app");
Try to use useRouter instead of useRoute and instantiate it like const router =useRouter() in setup function:
import { ref } from "vue";
import { useRouter } from "vue-router";
export default {
setup() {
const router =useRouter()
const form = ref(
{
email: "hudson.vilma#example.net",
password: "password",
isLoading: false,
},
);
const user = ref("");
function login() {
axios.get('/sanctum/csrf-cookie').then(response => {
axios.post('/login', this.form).then(response => {
router.push('/dashboard')
}).catch(error => console.log(error)); // credentials didn't match
});
}
return { form, login, user ,};
},
};
</script>
Note that this couldn't be used in composition API.
You are using this.$router.push('/dashboard') in setup(). This cannot be used in setup(). Instead you can use...
router.push('/dashboard')

Fetch request in React: How do I Map through JSON array of objects, setState() & append?

This API returns a JSON array of objects, but I'm having trouble with setState and appending. Most documentation covers JSON objects with keys. The error I get from my renderItems() func is:
ItemsList.js:76 Uncaught TypeError: Cannot read property 'map' of undefined
in ItemsList.js
import React, { Component } from "react";
import NewSingleItem from './NewSingleItem';
import { findDOMNode } from 'react-dom';
const title_URL = "https://www.healthcare.gov/api/index.json";
class ItemsList extends Component {
constructor(props) {
super(props);
this.state = {
// error: null,
// isLoaded: false,
title: [],
url: [],
descrip: []
};
}
componentDidMount() {
fetch(title_URL)
.then(response => {
return response.json();
})
.then((data) => {
for (let i = 0; i < data.length; i++) {
this.setState({
title: data[i].title,
url: data[i].url,
descrip: data[i].bite,
});
console.log(data[i])
}
})
.catch(error => console.log(error));
}
renderItems() {
return this.state.title.map(item => {
<NewSingleItem key={item.title} item={item.title} />;
});
}
render() {
return <ul>{this.renderItems()}</ul>;
}
}
export default ItemsList;
Above, I'm trying to map through the items, but I'm not quite sure why I cant map through the objects I set in setState(). Note: even if in my setState() I use title: data.title, it doesnt work. Can someone explain where I'm erroring out? Thanks.
in App.js
import React, { Component } from "react";
import { hot } from "react-hot-loader";
import "./App.css";
import ItemsList from './ItemsList';
class App extends Component {
render() {
return (
<div className="App">
<h1> Hello Healthcare </h1>
<ItemsList />
<article className="main"></article>
</div>
);
}
}
export default App;
in NewSingleItem.js
import React, { Component } from "react";
const NewSingleItem = ({item}) => {
<li>
<p>{item.title}</p>
</li>
};
export default NewSingleItem;
The problem is this line:
this.setState({
title: data[i].title,
url: data[i].url,
descrip: data[i].bite,
});
When you state this.state.title to data[i].title, it's no longer an array. You need to ensure it stays an array. You probably don't want to split them up anyway, just keep them all in a self contained array:
this.state = {
// error: null,
// isLoaded: false,
items: [],
};
...
componentDidMount() {
fetch(title_URL)
.then(response => {
return response.json();
})
.then((data) => {
this.setState({
items: data.map(item => ({
title: item.title,
url: item.url,
descrip: item.bite,
})
});
console.log(data[i])
}
})
...
renderItems() {
return this.state.items.map(item => {
<NewSingleItem key={item.title} item={item.title} />;
});
}

unable to see vue component on logged in profile

I have a vue component which can be seen on other users's profile but not on logged in user.
when I visit other user's id i can see that component but when I come back to my id it disappears
profile url is /myplace/{username}
vue component :
<template>
<img src="https://cdn0.iconfinder.com/data/icons/basic-ui-elements-colored/700/09_bell-3-512.png" style="height:50px;margin-top: 30px; margin-left:0px!important;">
</template>
<script>
import $ from 'jquery'
import axios from 'axios'
import Notification from './Notification.vue'
export default {
components: { Notification },
props:['username'],
data: () => ({
total: 0,
notifications: []
}),
mounted () {
this.fetch()
if (window.Echo) {
this.listen()
}
this.initDropdown()
},
computed: {
hasUnread () {
return this.total > 0
}
},
methods: {
/**
* Fetch notifications.
*
* #param {Number} limit
*/
fetch (limit = 5) {
axios.get('/notifications', { params: { limit }})
.then(({ data: { total, notifications }}) => {
this.total = total
this.notifications = notifications.map(({ id, data, created }) => {
return {
id: id,
title: data.title,
body: data.body,
created: created,
action_url: data.action_url
}
})
})
},
in blade view:
<notifications-dropdown :username="{{json_encode($user)}}">
</notifications-dropdown></a>
app.js:
import './bootstrap'
import Vue from 'vue'
import NotificationsDemo from './components/NotificationsDemo.vue'
import NotificationsDropdown from './components/NotificationsDropdown.vue'
new Vue({
el: '#app',
components: {
NotificationsDemo,
NotificationsDropdown
}
})

Resources