I'm pretty new to using browserify etc. for js development. Also I'm new to Vue. I wanted to create additional custom components for my application. However I fail at so many points even when following different tutorials step by step.
This is What I currently got:
example.js
var MyComponent = Vue.extend({
data: function() {
return { message: 'This is a test' }
},
template: '{{ message }}'
});
Vue.component('my-component', MyComponent);
new Vue({
el: '#example'
});
app.js
require('spark-bootstrap');
require('./../example.js');
require('./components/bootstrap');
require('./backoffice/main.js');
var app = new Vue({
mixins: [require('spark')]
});
view.blade.php
<div id="example">
<my-component></my-component>
</div>
gulpfile.js
elixir(function(mix) {
mix.less('app.less')
.browserify('app.js', null, null, { paths: 'vendor/laravel/spark/resources/assets/js' })
.copy('node_modules/sweetalert/dist/sweetalert.min.js', 'public/js/sweetalert.min.js')
.copy('node_modules/sweetalert/dist/sweetalert.css', 'public/css/sweetalert.css');
});
My error
app.js:24638[Vue warn]: Unknown custom element: <my-component> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Since example.js is a separate module, you'll need to import Vue in that file as well. I assume you've done that. You also don't want to new up a Vue instance in that file though, because you're already doing that later on. If <my-component> is inside of the spark body you already have a Vue app running.
Related
I have a vue js application which is compiled and rendered in its own enviroment within my php project. I use a old version of a PHP framework and not Laravel.
My vue js application instance is created in the main.js file
Vue.component(
'Dashboard',
require('./components/dashboard/Index.vue').default
);
console.log(window.location);
const router = new VueRouter({
mode: "history",
base: window.location.pathname,
});
var myVueInstance = new Vue({
router
}).$mount('#app');
and then i use this compiled vue js application just before the closing tag in my project.
<script src="<?php echo getenv('APP_DEBUG') == 'false'
? Yii::app()->baseUrl.'/js/vue/js/main.min.js'
: 'http://localhost:8080/js/main.js' ?>"></script>
The issue is that i am trying to inject and set a data key inside one of the components using the ref name but i cannot get hold of anything to set the key.
<div id="app">
<quote-upload ref="quoteUpload"></quote-upload>
<view-quote ref="viewQuote"></view-quote>
<invoice-upload ref="invoiceUpload"></invoice-upload>
</div>
var self = this;
$(document).on("click", ".openQuoteModal", function () {
myVueInstance.$refs.quoteUpload.vehicleid = $(this).data('id'); //this doesnt work.
});
but i am unable to do so as it is always undefined.
Is there any way to do this?
I tried the following but still got the my vue instance variable was undefined. Strange that it is because it is above the call i do.
I ended up listen for the click within the vue component itself when the vue component got mounted. I got the value on click and then set the vehicleid internally within the component.
mounted() {
var self = this;
this.$nextTick(() => {
$(document).on("click", ".quoteUploadModal", function(){
self.vehicleid = $(this).closest('.openQuoteModal').data('id');
});
});
},
I have a project in Laravel where I import my app.js is:
require('./bootstrap');
window.Vue = require('vue');
const app = new Vue({
el: '#app',
data: {},
methods: {},
});
This file is imported in my main layout (app.blade.php) like so:
<div id="app">
#yield('content')
</div>
<script src="{{asset('js/app.js')}}"></script>
#yield('scripts')
I guess you can't instantiate a new Vue instance within another one... so I MUST work with a single Vue instance. The #app div encompasses all of the dynamic content of my multiple-page application, and so my question is... on different pages, how do I separate my Vue.js code? If I put all of the code in app.js, it will get cluttered, and my code will have missing references depending on which page the user is on.
I tried writing a separate <script></script> for each page, but this requires me to input the CSRF token for each page, but this feels DRYish.
How do people do this?
Your route should be like this to accept vue router
Route::get('/{view?}', function () {
return view('vue');
})->where('view', '^(?!api\/)[\/\w\.-]*');
this will accept every route exept api routes
I have an application with multiple web pages. On each webpage, I want to be able to bind a Vue instance to some element on the page as to give it a more dynamic user interaction.
In the base Laravel project, you're supposed to bind a Vue instance to #app in app.js which I've done. Including any more instances, however, give a "element not found" error when you're on any page that doesn't include that element. I imagine you're not supposed to put all of your instances in app.js...
What is the general architecture for having a different Vue instance on each page? Do I make a new js file for each page, and include it?
Sorry for my naivety!
You can create a new Vue instance on a yielded scripts section in app.blade.php that every view extends (mostly) for each page where needed to avoid the Vue warning
For example, Laravel Vapor website does* this, in the main page you can find this code
*they use a CDN to include the library instead of the compiled one from webpack
A Vue instance just for the Form
<script>
var app = new Vue({
el: '#form',
data: {
email: '',
submitted: false,
submitting: false
},
methods: {
onSubmit: function () {
this.submitting = true;
fetch('/api/early-access', {
method: 'POST',
body: JSON.stringify({ email: this.email }),
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
this.submitted = true;
this.submitting = false;
});
}
}
})
</script>
In layouts/app.blade.php yield a section for the scripts right before the closing tag of the body, for example
<main class="py-4">
#yield('content')
</main>
</div>
#yield('scripts')
</body>
Then instantiate a new Vue instance in the Blade view file of a page like so
#extends('layouts.app')
#section('content')
<div class="container">
<div id="home-page"></div>
</div>
#endsection
#section('scripts')
<script>
new Vue({
el: '#home-page',
});
</script>
#stop
Hope this helps
I just use a single Vue instance.
I have a master blade layout in which the body section looks like the code given below and I extend it for all the pages. It's basically a template with head tag filled with #yield('tags_like_meta', default_value) and some other javascript imports.
<body>
<div id="app">
#yield('contents')
</div>
</body>
And then I have a single Vue instance like this on my js file.
const app=new Vue({el:"#app"});
For different pages I use Vue-router to dynamically load the component. For example, if I want my contact page to be loaded via Vue, I will have my contact_page.blade.php look like this
#extends(layout.master)
#section('contents')
<router-view></router-view>
#endsection
And Vue-router will handle the rendering if I have the contact page url specified in the routes.
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/contact',
name: 'contact',
component: () => import('./components/contact/index')
}]
});
This way, you can work with single Vue instance (as mentioned in the docs)
As you can see from the title I am trying out Laravel 5.3 and passport.
So I have gone through the steps to install Laravel passport and as far as I can see everything is in place.
I have put the corresponding Vue components into the markup of my home.blade.php as follows to test as per the docs which I have done like so
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Dashboard</div>
<div class="panel-body">
You are logged in!
</div>
</div>
</div>
</div>
</div>
<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>
#endsection
Vue is detected as running in my dev tools however no Vue components are showing up.
Here is my app.js
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: 'body'
});
Vue.component(
'passport-clients',
require('./components/passport/Clients.vue')
);
Vue.component(
'passport-authorized-clients',
require('./components/passport/AuthorizedClients.vue')
);
Vue.component(
'passport-personal-access-tokens',
require('./components/passport/PersonalAccessTokens.vue')
);
I am getting the error
vue.common.js?4a36:1019 [Vue warn]: Unknown custom element: <passport-clients> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Any idea how I can fix this?I am fairly new to Vue
In your app.js file, import the components immediately below or in place of the example component, but before creating the new Vue object where it gets bound to the DOM.
Don't forget to run gulp as well. :)
I had the same issue with the following resolution with Laravel 5.4:
Find resources/assets/app.js.
put all Vue.component... before new Vue (not after)
in each Vue.component's import, append .default
Vue.component(
'passportclients',
require('./components/passport/Clients.vue').default
);
Vue.component(
'passportauthorizedclients',
require('./components/passport/AuthorizedClients.vue').default
);
Vue.component(
'passportpersonalaccesstokens',
require('./components/passport/PersonalAccessTokens.vue').default
);
And then run npm run dev again.
I had the same problem and it turned out that this matters:
put the code
const app = new Vue({
el: 'body'
});
at the END of the app.js file.
That started showing the components on the webpage.
Tarun is correct:
Make sure you include your vue references in app.js before:
const app = new Vue({
el: 'body'
});
I have fixed that issue, we do not need to include any Vue libraries, laravel by default provides this (this is for laravel 5.4 and > ) :
Go to your project-folder/public/js/app.js
Find the code where your passport clients, passport authorized clients and passport-personal-access-tokens are registered.
Replace the code with :
Vue.component('example-component', webpack_require(41));
Vue.component('passport-clients', webpack_require(44));
Vue.component('passport-authorized-clients', webpack_require(50));
Vue.component('passport-personal-access-tokens', webpack_require(55));
var app = new Vue({ el: '#app' });
Note : Register the Vue.component before "Var app = new Vue"
I decided to create a little project using Laravel 5.1, vueJS (with vue-resource) and some file interaction on the server-side.
Everything works fine but in the process of creating the app I questioned myself what the best way of receiving data from the server was. Besides the ovious solution, AJAX, I tried writing the data with laravel-blade inside the data object of my Vue instance, which looked like this:
FileController.php:
$files = Auth::user()->files;
return view('files.index', compact('files'));
The files() function is just a simple belongsToMany() relationship on the User Model with a pivot table in the background.
index.blade.php:
new Vue({
el: '#files',
data: {
// pass the data to Vue via PHP so you don't need an AJAX request
files: {!! $files !!}
// ..
}
The other solution would be something like this in my Vue instance:
ready: function() {
this.$http.get('/todos', function (data) {
this.$set('todos', data);
}).error(function (data) {
console.log(data);
});
Now my question is whether or not my approach has any disadvantages because in my opinion it's better because it's less AJAX interaction and that means the app should be faster (at least in theory).
Edit: of course it's possible to simply write it with a blade foreach for example but I want to do the presentation of the data in vue.
You can get the data using the props:
<div id="files" :files="{{ $files }}"></div>
And in your Vue instance:
new Vue({
el: "#files",
props: ['files'],
data: {
list: []
},
ready: {
this.list = JSON.parse(this.files)
}
});
The props option files is filled by the $files from laravel, and is parsed to json to use in vue, after the ready option, you can use in HTML:
<div v-for="l in list">
#{{ l.name }}
#{{ l.last_name }}
</div>
The list contains the json with the files that comes from Laravel controller.
You need props
So your element will look like:
<div id="#files" :files="{!! $files !!}"></div>
And your Vue:
new Vue({
el: '#files',
props: {
files: {
type: Object // <- not necessary, you can also have props: ['files']
}
}
});