Laravel and VueJS with blade templates - laravel

The new laravel comes with a built-in VueJs. But what I need is one instance of vuejs binded to body tag for the whole app. How can I achieve this ? Is there a way of binding vue directly on body element, even though its not recommended ? The purpose is only using vue to make an API calls for certain parts of my app, but I need vue to be available globally and without binding to specific element, which will destroy my current app
Update Code:
default layout - laravel
...
</head>
<body id="app" class="{{isActiveRoute('home')}}">
...
</body>
resources/assets/app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: '#app',
components: ['example'],
data: {
name: 'test'
},
methods: {
addToCart() {
console.log('add to cart');
}
},

Related

Laravel + SPA VueJs not giving error for unknown component

<template>
<div>
<test-component />
</div>
</template>
<script>
//import TestComponent from '../path-to-components/TestComponent';
export default {
name: 'SomeRandomComponent',
components: {
TestComponent,
}
}
</script>
Expected Behaviour:
The application should give some console error if there is a problem with the imports or anything else similar to this.
Current Behaviour:
The page get blank in the browser and there is no error in console even if the import statement is commented out.
Code for reference
app.js
import Vue from 'vue';
import router from '~/router';
import App from '~/components/App';
new Vue({
router,
...App
})
router.js
export default [
{ path: '/some-path', name: 'testing', component: import( `~/pages/path-to-component`).then(m => m.default || m) },
]
App.vue
<template>
<div id="app">
<loading ref="loading" />
<transition name="page" mode="out-in">
<component :is="layout" v-if="layout" />
</transition>
</div>
</template>
<script>
import Loading from './Loading'
// Load layout components dynamically.
const requireContext = require.context('~/layouts', false, /.*\.vue$/)
const layouts = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.vue$)/g, ''), requireContext(file)]
)
.reduce((components, [name, component]) => {
components[name] = component.default || component
return components
}, {})
export default {
el: '#app',
components: {
Loading
},
data: () => ({
layout: null,
defaultLayout: 'default'
}),
metaInfo () {
const { appName } = window.config
return {
title: appName,
titleTemplate: `%s ยท ${appName}`
}
},
mounted () {
this.$loading = this.$refs.loading
},
methods: {
/**
* Set the application layout.
*
* #param {String} layout
*/
setLayout (layout) {
if (!layout || !layouts[layout]) {
layout = this.defaultLayout
}
this.layout = layouts[layout]
}
}
}
</script>
I am assuming that you are using Vue2 since Vue3 is in beta.
The first problem I see with your code, is that your <div id="app"> is inside a Vue component.
Declarative Rendering
What happening is that everything is compile, but you are trying to render Vue inside a component that does not exist.
Instead, create a div element inside the html or blade.php file that is loaded by the client. For my part, I use a blade layout like this:
//resources/views/layouts/app.blade.php
...
</head>
<body>
<div id="app" v-cloak> //This is plain loaded when client render views, then, when script will initiate, Vue will be able to access everything inside this.
<navbar v-bind:core="core"></navbar> //There is my navbar which is a Vue component.
<div class="boxed">
<div id="content-container">
#yield('content') //Blade component are injected there. since it's inside the <div id="app">, thoses component can include Vue directive/component.
</div>
...
Another thing that seems a problem is that you are initiating Vue inside a Vue component. Things are that Vue is a package and compiled into javascript in the end. But, to make all the magic happen, you need to have somwhere to initiate all this. In that case, your App.js file should look something like this:
/**
* 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');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* 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.
*/
const app = new Vue({
el: '#app',
});
This file is the one created by default by laravel for Vue template on fresh Laravel 8 install.
The difference between import and require is that import create a promise.
You don't want a promise there, because you want that file to be execute at the moment the client will begin to render your page.
Following thoses recommendation, I think you will be able to get your app working quickly and Vue will start logging error into your console.

Building a Laravel MPA with Blade, but adding Vue to some pages [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am developing a classic MPA webpage using Laravel and Blade templates.
But in some of the pages, I would like to add some reactivity to improve the user experiencie, using the Vue framework for that.
So far so good, if I import Vue and JS code in a normal script tag at the end of the corresponding blade templates, I get it done.
But my problem is that I need all the JS code to be minified and processed by webpack (Laravel Mix) so that javascript source is not exposed.
Any ideas?
Thanks in advance.
If you ran the following artisan commands to install Vue in Laravel:
composer require laravel/ui
php artisan ui vue
your app.js file which comes standard with Laravel will have been updated automatically to import Vue. It will look something like this (but with comments):
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
const app = new Vue({
el: '#app',
});
So with that, you could begin creating Vue components for different sections of your website.
However, if your issue is that you want to have multiple different Vue instances throughout your application based on the page, you would begin by taking the same layout as the code block above (minus the bootstrap require statement) and choose a different element id for the new instance. Then you would create a new Javascript file to house the specific components/functions you desire and add them to your webpack.mix.js like this:
mix.js('resources/js/app.js', 'public/js') // old line
.js('resources/js/header/header.js', 'public/js') // additional line
then in your blade file, you would simply use the new script like so:
<script src="{{ asset('js/header.js') }}"></script>
Edit: Based on Comment
Probably the easiest way to pass the data from your blade file to the specific Vue instance would be to prop the data on the element the Vue instance is initiated one (comparable to propping a blade variable through to a Vue component as well). If this was your element:
const app = new Vue({
el: '#show-order',
});
You could prop the id of the order ($id needs passed from the controller/view)
<div id="show-order" order_id="{{ $id }}">
...
</div>
Then you set up the prop within the Vue instance:
const app = new Vue({
el: '#show-order',
props: ['order_id'],
});
and maybe used in a method like so:
const app = new Vue({
el: '#show-order',
props: ['order_id'],
methods: {
logMyProp: function() {
console.log(this.order_id);
}
}
});
Alternatively you could create a method within your instance that's responsible for calling a method that loads the data directly into the instance instead of passing the data from the controller => blade => vue component.
...
data: function() {
return {
order: {},
}
},
methods: {
loadMyData: function() {
let vm = this;
$.ajax({
url: '/orders/load/'
}).done(function(response) {
vm.order = response;
});
}
},
...

Vue Component not showing text when called from blade.php file

I have a basic vue 2.6.11 component that lives in a laravel 6 application. It lives at resources/js/components. I create a basic component and then in my app.js file I have vue imported and I define my vue component. Then in my app.blade.php I use the vue component but the text within my <template><div>Text here</div></template> does not appear on the screen. The <h1> text appears but not the vue component text. I looked at other posts but the vue versions other questions on here use are 2-3 years too old and don't apply. Any help is appreciated, thanks.
TableDraggable.vue
<template>
<div>
<h1>Test Text</h1>
</div>
</template>
<script>
export default {
mounted() {
console.log('this component has been mounted');
}
}
</script>
What I am using in my app.blade.php file
<h1>This is a test to see if VUE is working</h1>
<table-draggable></table-draggable>
app.js snippet
//Bring in VUE and vue draggable
window.Vue = require('vue');
import VueDraggable from 'vuedraggable';
Vue.component('table-draggable', require('./components/TableDraggable'));
In app.js try the following:
...
window.Vue = require('vue');
import VueDraggable from 'vuedraggable';
Vue.use(VueDraggable);
import TableDraggable from './components/TableDraggable';
Vue.component('table-draggable', TableDraggable);
const app = new Vue({
el: '#app',
data() {
return {};
},
});
...
Then in some parent element of where you are using your component, make sure it has an id of app. eg:
<div id="app">
<h1>This is a test to see if VUE is working</h1>
<table-draggable></table-draggable>
</div>
This is a basic example of getting vue working on your site, and not necessarily the best way to be structuring your assets depending on your needs. The biggest considerations about how to structure these are how bulky your assets will become if you include everything in app.js.

Vue template not being displayed?

I am new to vue and I am trying to get a simple component to display in a div. I am using laravel 5.4 with laravel mix and vue version 2.6.6 to display a vue component.
this is the div in my view file:
<div id="sidenav"> </div>
This is my app.js
require('./bootstrap');
import Vue from 'vue';
Vue.component('SideNav', require('./components/SideNav.vue').default);
var SideNav = new Vue({
el: '#sidenav'
});
This is SideNav.vue
<template>
<div>
<h1>Test</h1>
</div>
</template>
<script>
export default {
name: 'SideNav'
}
</script>
There aren't any errors with npm install, npm build, npm run dev, or npm run watch. On the page I do not see
Test
I'm sorry for such a newb question, but this has been driving me crazy for a few hours.
Try something like this;
<div id="sidenav">
<SideNav></SideNav>
</div>
You "mount" your Vue instance to the root element with id #sidenav here:
var SideNav = new Vue({
el: '#sidenav'
});
meaning, when you created your Vue component here: Vue.component('SideNav', require('./components/SideNav.vue'));, you have access to the <SideNav> tag within that root element.
Also, I'm not sure if you need the .default at the end of your Vue.component(...) creation.

Laravel Vuejs pass data from blade to .vue template

I am new in Vuejs. I have the following code and i am getting an error. I am trying to pass a var into vue file.
What do i do wrong? And how can i achieve this?
App.js:
window.Vue = require('vue');
Vue.component('formlements' ,require('./components/formelements/Input.vue') );
const app = new Vue({
el: '#app'
});
Blade:
<formlements :testinfo="{somekey: 'someinfo'}"></formlements>
Vue file
<template>
<div class="container">
{{testinfo.somekey}}
</div>
</template>
Error:
Property or method "testinfo" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
As per my comment, you have not defined props on your component or app. Even though you have bound the variable to the prop using :bind, it is still not accessible to the component.
All you need to do is declare the prop, e.g. props: { testinfo: Object }.

Resources