The global variable is not working with VueJS & Laravel - laravel

I have a global variable in app.blade.php like this>
<script>
window.App = {!! json_encode([
'apiToken' => Auth::user()->api_token,
]) !!};
</script>
I have in app.blade.php layouts a
and it has:
<script>
export default {
created() {
this.getRol();
},
methods: {
getRol() {
console.log(App.apiToken);
axios.get('/api/user?api_token='+App.apiToken)
.then(response => {
console.log(response);
this.rol_id = response.data.data.rol_id;
});
}
}
}
</script>
But I wonder why does it say this error?
[Vue warn]: Error in created hook: "ReferenceError: App is not defined"
And it's created globally.
Thanks

To create a "global variable" to be used in Vue, see LinusBorg's answer on the Vue forums here: https://forum.vuejs.org/t/global-variable-for-vue-project/32510/4
Contents of the post:
It’s not a good idea to use tru global variables in projects, to keep the global namespace clean.
Instead, create a small file, from where you can export any variable that you need to use in many places:
// variables.js
export const myVar = 'This is my variable'
export const settings = {
some: 'Settings'
}
// in your Vue
import { myVar, Settings } from './variables.js'

Related

Laravel vue.js 2 response view won't output parameters

I am new to vue.js and recently been assigned a project to learn it and refactor old code to vue.js like some of the existing pages already have been and I am having some issues. vue2
My question:
I have a get request with a controller that has a response something like this:
return Response::view('somebladefile', ['title' => 'some_title']);
Within the blade file I include a js file which will be responsible for vue
<script src="{{ cdnMix('somefile.js') }}"></script>
somefile.js contents:
const IndexPage = Vue.component('indexpage',require('./somepath/IndexPage.vue').default);
window.indexPageInstance = new IndexPage().$mount('#vuecontainerid');
So now within IndexPage.vue i would like to access variable 'title' that I passed with the response to my blade file originally. What would be the best way one would go about it? Tried few ways I found on YT/Google but without success, this is my code currently, any pointers would be appreciated, thanks!
<template>
<HeaderComponent></HeaderComponent>
</template>
<script>
const HeaderComponent = require('./somepath/HeaderComponent.vue').default;
export default {
name: 'indexpage',
props: ['data'],
components: {
'HeaderComponent': HeaderComponent,
},
data: function() {
return {
// why doesn't it work!!: '',
}
},
mounted: function() {
console.log(this.data);
}
}
</script>
Vue works, but I can't seem to be able to access 'title' variable.
Also I would like to be able to access 'title' within other components like the HeaderComponent I have within indexpage

Create global method vue on app.js laravel

I want create global method to translate message using Laravel-JS-Localization
But when i call the method using vue mustache got an error like this:
Property or method "trans" is not defined on the instance but referenced during render.
Make sure that this property is reactive.
Here my laravel app.js code:
require('./bootstrap');
window.Vue = require('vue');
Vue.component('dashboard', require('./components/Dashboard').default);
const app = new Vue({
el: '#vue',
methods: {
trans: function (key) {
return Lang.get(key);
},
},
});
Dashboard.vue code :
<template>
<p>{{ trans('common.welcome') }}</p>
</template>
<script>
data () {
return {
name: '',
}
},
</script>
dashboard.blade.php code :
..........
<div class="col-9" id="vue">
<dashboard></dashboard>
</div> <!--c end col-8 -->
..........
I would probably go with creating a Plugin. For example
Vue.use({
install (Vue) {
Vue.prototype.$trans = Lang.get
}
})
Adding this to your app.js code before creating any components or new Vue({...}) will mean all your components will have access to the $trans method.
Alternatively, you can create a Global Mixin but these aren't strongly recommended.
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components
Vue.mixin({
methods: {
trans (key) {
return Lang.get(key)
}
}
})

Laravel & Vuejs mixins : how to attribute a new value to shared variable?

I can use the mixin variables test and the method changeTest, when when I attribute a new value to the variable test, it's only applied in one component. How to have it changed globally, on all components using it ?
My mixins are set in the file resources/js/mixins.js:
export default {
data() {
return {
test: 'foo',
};
},
methods: {
changeTest(v) {
this.test = v;
}
}
}
Then, I have my two components comp1.vue and comp2.vue in resources/js/components/, both looking like this:
<template>
<div>
{{ test }}
</div>
</template>
<script>
import myMixins from '../mixins'
export default {
mixins: [ myMixins ],
}
</script>
Both components are in my home.blade.php like this:
#extends('layouts.app')
#section('content')
<comp1></comp1>
<comp2></comp2>
#ensection
for making a common variable (state) between all instances in vue.js you can use vuex. it's so simple, just add vuex to your packages and make an instance like this:
import Vuex from 'vuex'
const store = new Vuex.Store({
state: {
test: 'foo',
},
mutations: {
setTest(state, payload) {
state.test = payload
}
},
});
now you need to add this store to your main vue instance:
import Vue from 'vue'
Vue.use(Vuex);
let vm = new Vue({
el: '#app',
store,
// ...
});
all done. now in every component you can access the states by this.$store.state. for making life easier, you can define a computed variable like this:
computed: {
test() {
return this.$store.state.test
}
}
to change the state you just need to commit the setTest mutation. you have to add this mutation to methods and simply call it like this:
methods: {
...Vuex.mapMutations(['setTest']),
myMethod() {
// do this
this.setTest('some value');
// do that
}
}
you can also make a global mixin like i told you before to add this computed and mutation to every instance like this: (add this before make the main vue instance)
Vue.mixin({
computed: {
test() {
return this.$store.state.test
}
},
methods: {
...Vuex.mapMutations(['setTest']),
}
});
but i don't recommend to do this because when the project grow big, it gets so hard to avoid name confusion. it's better to make them separately for each component to chose proper names.
you can use mixin method on main Vue instance like this:
import Vue from 'vue'
import MyMixin from './mixins.js'
Vue.mixin(MyMixin);
It will apply this mixin for all instance no matter how deep they are.

Laravel compact in vue

I want to know how can I pass variables to vue component in laravel?
When we work with blade we can pass variables like:
$now = Carbon::now();
return view('xxxxxxxx', compact('now');
That way I can use $now in xxxxxxxx blade file. But what about vue components? we usually return data by json for components and with axios route we get that info no way to specify such data for exact component of us?
What if I want to use $now = Carbon::now(); in single.vue component?
How can I make that happen?
Update
Here is what I want to do with timing as carbon cannot be used (based on comments) I want to use moment.js
Logic
Let users bid if project deadline hasn't arrived
Don't let users bid if project deadline has arrived
template
<template v-if="`${project.deadline | timeAgo}`">
pssed (will be replaced by button is just for test)
</template>
<template v-else>
still have time (will be replaced by button is just for test)
</template>
script
var moment = require('moment');
export default {
data(){
return {
project : '',
}
},
mounted: function() {
// I found this code by google not sure if is currect!
Vue.filter('timeAgo', function(value){
return moment(value) >= fromNow()
});
},
}
Based on my code above here is the results
Try this:
This is my routes, simply I just render a view with some pre-defined variables
Route::get('/', function () {
return view('welcome', [
'now' => Carbon::now(),
'deadline' => Carbon::now()->addHours(2)
]);
});
And this is my view file. Here I have custom element named: example-component. And this is how I passed PHP variables to Vue component using props.
And pass your data to window like so:
<script>window.data = #json(compact('now', 'deadline'))</script>
And this is my Vue component file:
<template>
<h1>
<span v-if="isPassed">This job is passed</span>
<span v-else>You have to finish this job</span>
{{ parsedDeadline | timeFromX(parsedNow) }}
</h1>
</template>
<script>
const moment = require('moment');
export default {
props: {
now: {
type: String,
default: () => window.data.now.date // since `now` is an object, you need to access the `date` property to get plain string date that moment can parse
},
deadline: {
type: String,
default: () => window.data.deadline.date // same as above
}
},
computed: {
parsedNow () {
return moment(this.now)
},
parsedDeadline () {
return moment(this.deadline)
},
isPassed () {
return this.parsedNow.isAfter(this.parsedDeadline)
}
}
}
</script>
Here's the documentation about computed and filters. You may NEVER add a filter in a mounted function since it may leads to memory leak. Here's how I add my filter. In your app.js (assumed you're using default Laravel Vue preset)
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!
const app = new Vue({
el: '#app'
});
UPDATE
If you want to try this, you may edit the routes/web.php and change the deadline value:
Route::get('/', function () {
return view('welcome', [
'now' => Carbon::now(),
'deadline' => Carbon::now()->subHours(2), // Passed 2 hours ago
// 'deadline' => Carbon::now()->addHours(2), // In 2 hours
]);
});
Checkout the Carbon docs here about addition and subtraction.
UPDATE II
If you got error in app.js from the code above, maybe your transpiler doesn't know about arrow-parens.
// Looks like arrow-parens not working, see code below
// Vue.filter('timeFromX', (a, b) => a.from(b)); // TADAAA...!!!
// Change it to this ???
Vue.filter('timeFromX', function (a, b) {
return a.from(b);
});

What is the best way to use Laravel route in Vue JS component

I have a vue js component which makes an axios request to a laravel route. But in the vue files I don't have access to the route() function and have to use static url's for now.
Here's some code:
web.php:
// API
Route::group(['prefix' => 'api'], function() {
// GET
Route::get('/brands', 'BrandsController#getBrands')->name('api-get-brands');
Route::get('/{brand_id}/models', 'BrandsController#getModels')->name('api-get-models');
Route::get('/fuel-types', 'BrandsController#getFuelTypes')->name('api-get-fuel-types');
Route::get('/gearboxes', 'BrandsController#getGearboxes')->name('api-get-gearboxes');
});
Vue component:
methods: {
getBrands: function() {
let app = this
axios.get('/api/brands')
.then(function(response) {
app.brands = response.data
})
.catch(function(error) {
console.log(error)
})
},
...
}
It works now but I wonder if that's the best way or is there some better way to do it
You can pass the route as props to the component inside the blade file.
Inside the view:
<component home-route="{{ route('home') }}"></component>
Inside the vue component:
<script>
export default {
props: ['homeRoute'],
}
</script>
Then you can access the route inside the component like so:
this.homeRoute
You can learn more about props here: https://v2.vuejs.org/v2/guide/components-props.html
Hope this helps.
The only way how to use routes with parameters that I found out is like this:
The route:
Route::get('route/{param1}/{param2}', [Controller::class, 'actionName'])->name('routeName');
The blade:
<component :route="'{{ route('routeName', ["", ""]) }}'"></component>
where the number of empty strings in the array is equal to the number of required parameters for the route.
The component:
<script>
export default {
props: {
route: String
},
data() {
return {
param1: "",
param2: ""
}
},
computed: {
fullRoute() {
return this.route + '/' + this.param1 + '/' + this.param2;
}
}
}
</script>
I am using Laravel 8 and Vue 3.
Use https://github.com/tighten/ziggy
Ziggy provides a JavaScript route() helper function that works like Laravel's, making it easy to use your Laravel named routes in JavaScript.
You can then use routes in JS just like in PHP
route('posts.index');
With parameters too
route('posts.show', [1]);

Resources