Vuejs js for multiple pages, not for a single page application - laravel

I need to build an application using laravel 5.3 and vuejs 2, because I need to use two-way binding rather than use jquery.
I need to set up the views with blade templates. Then, I need to use vuejs in each page as mentioned below.
resources/asserts/js/components/List.vue
<script>
const panel = new Vue({
el: '#list-panel',
name: 'list',
data: {
message: 'Test message'
},
methods: {
setMessage: function(){
this.message = 'New message';
}
}
})
</script>
resources/asserts/views/post/index.blade.php
<div id="panel" class="panel panel-default">
<div class="panel-heading">Posts</div>
<div class="panel-body">
<p>{{ message }}</p>
<button v-on:click="setMessage">SET</button>
</div>
</div>
There is Add.vue to create.blade.php etc...
In Add.vue el: '#add-panel'
This is my app.js. I already commented default code like follows.
Vue.component('list', require('./components/List.vue'));
Vue.component('add', require('./components/Add.vue'));
// const app = new Vue({
// el: '#app'
// });
I hardly checked most of documentations and tutorials. But they use a single js file. They use components for small elements with template, not only js.
Is it possible to use vuejs this way? Do I need to use app.js. What is the best way to do this?

If you want to sprinkle a bit of vuejs within your blade files you have basically two options:
Option #1
Declare global Vue components
Example
// in laravel built in app.js file
Vue.component('foo', require('./components/Foo.vue'));
Vue.component('bar', require('./components/Bar.vue'));
const app = new Vue({
el: '#app'
});
create a main layout file where the root div has an id of #app
// layout.blade.php
<html>
<header></header>
<body>
<div id="app">
#yield('content')
</div>
</body>
</html>
Finally in your views:
//some-view.blade.php
#extends('layout')
#section('content')
<foo :prop="{{ $someVarFromController }}"></foo>
#endsection
Option #2
This is what I am currently using, and gives me more flexibility actually
// in laravel built in app.js file
const app = new Vue({
el: '#app',
components: {
Foo: require('./components/Foo.vue'),
Bar: require('./components/Bar.vue')
}
});
In the layout file you will be using vuejs dynamic components
<html>
<header></header>
<body>
<div id="app">
#if (isset($component))
<component :is={{ $component }} inline-template>
#endif
#yield('content')
#if (isset($component))
</component>
#endif
</div>
</body>
</html>
In your views:
//some-view.blade.php
#extends('layout', ['component' => 'foo'])
#section('content')
// all the vue stuff available in blade
// don't forget to use the # symbol every time you don't want blade to parse the expression.
// Example: #{{ some.vue.propertie }}
#endsection
And finally you can create the vue components like you always would
// resources/assets/js/components/foo.vue
<script>
export default {
// the component
}
</script>

Create your 'app' for every page in seperate JS files. Good practice would be using the same name as page name to get it clear where it belongs.
Name you main div the same as the file (fileName.php + assets/js/fileName.js).
Use #fileName' as yourel`
in blade use #{{ vue expressions }} to let Blade skip this and allow VueJS handle that.
Done. Good luck!

Related

Vuejs component not registering with laravel

I know this question is being asked several times, but I couldn't find any solution to my problem.
I have two vue components on my laravel project. The first one is the laravel default component called "ExampleComponent.vue" and the second one is my own new component called "multi.vue".
I use them in a section.blade.php file like below:
#extends('layouts.app')
#section('content')
<example-component></example-component>
<multi></multi>
#endsection
but only the "example-component" works and for the "multi" component, it gives me the following error:
Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
here is my app.js code:
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('multi', require('./components/multi.vue').default);
const app = new Vue({
el: '#app',
});
Here is my components codes:
ExampleComponent.vue:
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
And my multi.vue:
<template>
<div>
I am multi component!
</div>
</template>
<script>
export default {
mounted() {
console.log('multi mounted.')
}
}
</script>
<style>
</style>
And the route is:
Route::get('/section',function(){
return view('section');
});
For solving this problem, all you need to do is to run "run npm watch".
After running that command, it will recomplie your vue code whenever you make a change in your code and save it.
Keep it in a separate terminal, and run "php artisan serve" in another terminal.
From https://v2.vuejs.org/v2/style-guide/#Multi-word-component-names-essential:
Component names should always be multi-word, except for root App
components, and built-in components provided by Vue, such as
<transition> or <component>.
This prevents conflicts with existing and future HTML elements, since
all HTML elements are a single word.

Vuetable-2 cannot be mounted in Laravel 6

I'm trying to use the Vue component Vuetable-2 in Laravel 6. I know the component says that it's made for 5.4, but I believe it should still work.
My app.js looks like this:
require('./bootstrap');
window.Vue = require('vue');
Vue.component(
'example-component',
require('./components/ExampleComponent.vue').default
);
Vue.component(
'my-vuetable',
require('./components/MyVuetable.vue')
);
const app = new Vue({
el: '#app',
});
The console reveals that the component could not be mounted.
[Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <MyVuetable>
<Root>
The view to where I'm trying to mount the component is the following:
(note that the example component does mount correctly)
#extends('layouts.app', ['activePage' => 'integracion', 'titlePage' => __('Integracion')])
#section('content')
<div class="content" id="app">
<div class="container-fluid container">
<example-component></example-component>
<my-vuetable></my-vuetable>
</div>
</div>
#endsection
#push('js')
<script>
$(document).ready(function() {
});
</script>
#endpush
You need to require('path').default. The .default is necessary here because when you use require('path') you're just getting a JSON object back:
{ default: <VueConstructor> }
So no template or render function is defined within that object. However if you use .default then you will actually get back an SFC in this case which can be transpiled down.
The alternative would be to use import:
import MyVuetable from './components/MyVuetable.vue'
Vue.component('my-vuetable', MyVuetable)
Or alternatively, with syntax-dynamic-import enabled:
Vue.component('my-vuetable', () => import('./components/MyVuetable.vue'))

Laravel local vue component registration

I know I can register global components in the file located in resources/js/app.js.
I know when I do this I can use these component in any place (because they are global).
But I don't want that. I have a big application and different functionalities solved in different routes. So I don't want the whole components available in all my views.
How can I register locally the components I want to be available only in one view?
Thanks
Vue js register component in local:
step-1 ) storing the component object in a variable:
var demo = {
data: function() {
return {
message: 'This is a local components.'
};
},
template: `
<div>
<h1>Component: {{ message }}</h1>
</div>
`
};
Step-2 ) Add a component property with the components that we want to register locally.
new Vue({
el: '#app1',
components: { /*Here we have added property*/
'demo': demo
}
});
Step-3 ) Template
<div id="app1">
<demo></demo>
</div>
*Notice: This property should be an object and contain key-value pairs of tag names and configuration objects.
You can do it by importing the component in your parent vue component
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from '#/folder/ChildComponent'
export default {
components: {
ChildComponent
},
}
</script>
Here is the approach that I follow.
Create a new file in your components folder in resources/js/components/YourComponent.vue
<template>
<div>
<h2>My awesome component</h2>
</div>
</template>
<script>
export default {
}
</script>
And in the view where you want the component, you can import it like below
<template>
<div>
<h2>Import another component</h2>
<awesome-component></awesome-component>
</div>
</template>
<script>
import awesomeComponent from "./components/YourComponent.vue";
export default {
components: {
'awesome-component': awesomeComponent
}
}
</script>

Materialize-css+Laravel+VueJS - where to initialize modals, side-nav etc

I'm trying to build a website with Laravel 5.4, Laravel Mix, VueJS and Materialize-css.
VueJS and jQuery are shipped with Laravel, so nothing to do there. All created components work as they should work.
I installed Materialize-css via npm following the instructions on the website.
But now I get an error when I try to implement a sidenav which should fly in on button-click. Other materilizecss-components (like Toasts, Collapsibles) work fine.
Here is my bootstrap.js which loads jQuery, Materialize-css etc:
window._ = require('lodash');
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
require('materialize-css');
import 'materialize-css/js/materialize.js';
import 'materialize-css/bin/materialize.js';
window.Vue = require('vue');
window.axios = require('axios');
window.axios.defaults.headers.common = {
'X-CSRF-TOKEN': window.Laravel.csrfToken,
'X-Requested-With': 'XMLHttpRequest'
};
And this is my adminarea.js, which contains all the stuff I need for my admin-area:
require('./bootstrap');
Vue.component('example', require('./Vue/components/Example.vue'));
Vue.component('admindashboard', require('./Vue/components/Admindashboard.vue'));
Vue.component('test', require('./Vue/components/Test.vue'));
Vue.component('adminnav', require('./Vue/components/Adminnav.vue'));
const app = new Vue({
el: '#app',
data: {
title: 'Admindashboard'
},
methods: {},
mounted() {
console.log('Da bin ich!');
Materialize.toast('I am a toast!', 4000);
}
});
My Adminnav-component:
<template>
<div>
<ul id="slide-out" class="side-nav">
<li><div class="userView">
<div class="background">
<img src="">
</div>
<img class="circle" src="">
<span class="white-text name">John Doe</span>
<span class="white-text email">jdandturk#gmail.com</span>
</div></li>
<li><i class="material-icons">cloud</i>First Link With Icon</li>
<li>Second Link</li>
<li><div class="divider"></div></li>
<li><a class="subheader">Subheader</a></li>
<li><a class="waves-effect" href="#!">Third Link With Waves</a></li>
</ul>
Sidenav
</div>
</template>
<script>
export default {
mounted() {
console.log('Mainnav mounted');
},
methods: {
openSidenav(){
$('.button-collapse').sideNav('show');
}
}
}
</script>
And the html-file:
<body>
<div id="app">
<adminnav></adminnav>
#yield('content')
</div>
<script src="{{ asset('assets/js/adminarea.js') }}"></script>
</body>
jQuery itself works, too. I don't know where to initialize the materilizecss-components. Any ideas?
Thanks!
Take a look at https://vuematerial.github.io/#/getting-started
You have a lot of custom components which are pretty easy to use.
If you want to stick to your implementation you have 2 options
import Materialize from 'materialize-css/js/materialize.js';
const app = new Vue({
el: '#app',
data: {
title: 'Admindashboard'
},
methods: {},
mounted() {
console.log('Da bin ich!');
Materialize.toast('I am a toast!', 4000);
}
});
or
import Materialize from 'materialize-css/js/materialize.js';
window.Materialize = Materialize;
I suggest not setting Vue to window because there is no need to do so. Same with axios. You can bind axios to the vue instance instead. Vue.prototype.$http = axios. You can make calls via this.$http.get.... after that.
Also stick with imports only rather than combining require and imports.
I've found a solution:
Instead of require('materialize-css') in adminarea.js (normally app.js in a fresh Laravel installation) I had to require('materialize-css/dist/js/materialze.js') and require('materialize-css/js/init.js').
Now everything works fine.

Laravel & vue.js - not rendering imported component

I'm starting to play around with vue.js on top of the laravel framework.
But im having trouble with rendering of a component which is imported.
My app.js (main entry point)
// app.js
var Vue = require('vue');
var Router = require('vue-router');
Vue.use(Router);
var router = new Router();
var ContractsOverview = Vue.extend({
template: '<p>contract page</p>'
});
var ContractDetail = Vue.extend({
template: '<p>detail page</p>'
});
import DashboardView from './app/components/DashboardView.vue';
router.map({
'/dashboard': {
component: DashboardView
},
'/contracts': {
component: ContractsOverview
},
'/contracts/:id': {
component: ContractDetail
}
});
var App = Vue.extend({
});
router.redirect({
'*': '/dashboard'
});
router.start(App, '#reminder-app');
This is my Dashboard component
(located at resources/assets/js/app/components/DashboardView.vue)
<template>
<section class="content-header">
<h1>
Dashboard
<small>Control panel</small>
</h1>
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i> Home</li>
<li class="active">Dashboard</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<!-- .. some html -->
</section>
</template>
<script>
export default {}
</script>
and in my master layout i have a normal blade template with the <router-view></router-view> tag at one point.
At the end i build my app.js with laravels elixir and the following gulpfile:
var elixir = require('laravel-elixir');
elixir.config.js.browserify.transformers.push({
name: 'vueify',
options: {}
});
elixir(function(mix) {
mix.less(['bootstrap.less', 'app.less']);
mix.scripts([
'admin-lte/plugins/jQuery/jQuery-2.1.4.min.js',
'admin-lte/plugins/jQueryUI/jquery-ui-1.10.3.min.js',
// some more scripts,
'admin-lte/app.js',
'admin-lte/pages/dashboard.js',
'admin-lte/demo.js'
], 'public/js/ui.js');
mix.browserify('app.js');
});
When i go to the page the routes /contracts and contracts/:id the templates are shown as expected.
But when i go the /dashboard route, i dont see anything (besides the layout).
Am I missing something? Did I forget to import or require something?
Ok, i spent at least 4 hours finding my error, but it was just a simple typo somewhere.
But if you run gulp inside the virtual machine (homestead), you dont get the same output as if you run gulp locally. On my local machine it told what went wrong.
Also gulp watch doesn't work on the homestead machine.

Resources