Issues using vue-js-modal component - vue.js

I followed directions on how to use the component from their documentation however I get TypeError: show is not a function
In my main JS file (app.js) I added the following and adding to my project using npm
import VModal from 'vue-js-modal'
Vue.use(VModal)
The documentation states that I can now call a modal from anywhere in the app, so I created a page specific JS file and included the following to hide/show a modal with name="hello-world" on the page that included vue, app.js and the page specific profile.js file.
export default {
methods: {
show() {
this.$modal.show('hello-world');
},
hide() {
this.$modal.hide('hello-world');
}
}
}
When I load the page, I don't see the modal content, however when I click the link Modal I get an error about the show method TypeError: show is not a function
I am using laravel mix and verified that everything is being compiled as expected. Below is a how I am including JS files on the profile page:
<script type='text/javascript' src='/assets/js/manifest.js?ver=5.2.3'></script>
<script type='text/javascript' src='/assets/js/vendor.js?ver=5.2.3'></script>
<script type='text/javascript' src='/assets/js/app.js?ver=1569678574'></script>
<script type='text/javascript' src='/assets/js/profile.js?ver=1569678574'></script>
I am trying to "level up" my Vue and JavaScript experience, previously I just stuck to writing ES5 and my Vue was written without components and bound to a page specific Vue instance, so any help would be greatly appreciated!
EDIT
app.js
window.Vue = require('vue');
require('./global/header.js');
Vue.component('tabs', require('./components/Tabs.vue'));
Vue.component('tab', require('./components/Tab.vue'));
import VModal from 'vue-js-modal'
Vue.use(VModal)
new Vue({
el: '#app'
});
profile.js
export default {
methods: {
show() {
this.$modal.show('hello-world');
},
hide() {
this.$modal.hide('hello-world');
}
}
}
webpack.mix.js that compiles profile.js
mix
.js("resources/js/pages/home.js", "assets/js/home.js")
.js("resources/js/pages/teams.js", "assets/js/teams.js")
.js('resources/js/pages/profile.js', 'assets/js/profile.js')

The error doesn't specify if its the $modal.show() function or your profile.js show() function that is undefined. I suspect that it's your profile.js show() function because it looks like everything is in order with regards to vue-js-modal.
You need to add profile.js as a vue mixin (https://v2.vuejs.org/v2/guide/mixins.html) in order for its functions to be added to the vue instance. So in your app.js add:
import profile from '/assets/js/profile'
Vue.mixin(profile);

Related

VUE Web component inside legacy app results in error "_Ctor, object is not extensible"

I'm having trouble importing my custom component in my legacy app.
I pre-compiled my SFC as a webcomponent with vue-cli builder, and I import inside my main.js file this way :
import * as HelloWorld from '../dist/hello-world.js'
Vue.component('hello-world',HelloWorld); //if I add my component globally (same _Ctor error)
Then I load my app on a container div :
var app = new Vue({
el:"#container",
data: {
test: 'Vue is init !' //just a test to validate init
},
components:{
HelloWorld //my web component locally (same _Ctor error)
}
});
When my app load, I get this JS error...
I noticed that when the page is loaded without the following component tag :
<hello-world></hello-world>
no error is thrown and if I add the component tag through JS after the page is loaded, component is properly working.
If I add this component outside of my Vue.el (#container) scope, it's working too.
However, I would like to add this component to #container.
I import Vue 2 through CDN.
Seems like a loading or building error but I can't get it.
Thanks for your help.
hello-world.js is a precompiled .VUE file with vue-cli, just a test file catching some events :
<template>
<h1 v-on:click="clickon"
v-on:mouseenter="addone"
>{{msg}}</h1>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
msg: 'Hello world!'
}
},
methods : {
clickon: function () {
// `this` inside methods points to the Vue instance
alert('Clicked')
},
addone: function(){
this.msg = 'Mouse entered'
},
}
}
</script>
<style>
h1{
color:red;
}
</style>
Precompiled with :
vue build --target wc HelloWorld.vue
Got it working by building it with --target lib and importing my JS file with:
import '../dist/HelloWorld.umd.js';
Then it can be added to my Vue instance with:
components:{
"hello-world":HelloWorld
}
Seems to be the right way to do it; web components can't be imported this way.

Import npm package into a Vue.js Single File component

I would like to use Jodit in a SFC, but I am not sure how this is supposed to be done. I realized there is a wrapper (jodit-vue), but for educational purposes, I would like to know how it's done without it. I created a Vue CLI project with default presets, and all I changed is the App.vue:
<template>
<div id="app">
<textarea id="editor" name="editor"></textarea>
</div>
</template>
<script>
import "../node_modules/jodit/build/jodit.min.js"
export default {
name: 'App',
created(){
let editor = new Jodit('#editor');
editor.value = '<p>start</p>';
}
}
</script>
<style>
#import "../node_modules/jodit/build/jodit.min.css" ;
</style>
This produces the error: error 'Jodit' is not defined no-undef, and
if I change the import to:
import Jodit from "../node_modules/jodit/build/jodit.min.js"
Then the compilation is fine, but the browser console says:
vue.runtime.esm.js?2b0e:1888 TypeError: _node_modules_jodit_build_jodit_min_js__WEBPACK_IMPORTED_MODULE_0___default.a is not a constructor
Admittedly, I am new to all of this, but pointing me to the right direction is appreciated.
The jodit module exports the Jodit constructor, so your component would import it like this:
import { Jodit } from 'jodit'
You'd also need the Jodit styles, which could be imported like this:
import 'jodit/build/jodit.min.css'
To create a Jodit instance, we need to provide an element or selector to an existing <textarea>. The Vue component's elements are available in the mounted() lifecycle hook (not in the created() hook), so that's where we would initialize:
export default {
mounted() {
const editor = new Jodit('#editor')
editor.value = '<p>start</p>'
},
}
demo

After laravel-mix upgrade app no longer sees global vars

I'm upgrading a project from laravel-mix v2.0 to v4.0 and I'm seeing an issue now where at runtime my components can't see globally scoped variables like they did before. How can upgrading the build tool impact the runtime?
I see I can add instance properties to the vue prototype, but is that really the approach I need to take? Seems like it should still be able to read global variables like it did before.
html
<script type="text/javascript">
var games = [
// a bunch of objects
];
</script>
<script src="{{ mix('js/app.js') }}"></script>
app.js
import ChannelSubscriptionSlider from './components/guild-subscriptions/ChannelSubscriptionSlider.vue';
Vue.component('channel-subscription-slider', ChannelSubscriptionSlider);
ChannelSubscriptionSlider.vue
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);
export default {
data: function () {
return {
games: games, // undefined when used within this component, but used to work before upgrade
}
},
Edit 2
Use `window.games, this would "register" your variables globally.
Although, what i do, is the following, consider a MPA not a SPA:
In app.js i just leave the following lines:
require('./bootstrap');
window.Vue = require('vue');
In a separate file, called main.js that i made, i put this, as an example:
import Sidebar from './components/layouts/Sidebar.vue'
import Topnav from './components/layouts/Topnav.vue'
new Vue({
el: '#sidebar',
render: h => h(Sidebar)
});
new Vue({
el: '#topnav',
render: h => h(Topnav)
});
at the end of app.blade.php i put:
<script src="{{ asset('js/app.js') }}"></script>
<script type="text/javascript">
const user_props = {
fullName : {!! json_encode(Auth::user()->fullName) !!},
username : {!! json_encode(Auth::user()->username) !!},
}
user_props.install = function(){
Object.defineProperty(Vue.prototype, '$userProps', {
get () { return user_props }
})
}
Vue.use(user_props);
</script>
<script src="{{ asset('js/main.js') }}"></script>
This works because i mount vue in app.js but the components that use user_props are loaded after i declare and install the prototype... Also, since vue is mounted in app.js i can use Vue.use(user_props); after loading it...
And forgot to mention that in webpack.mix.js you should add the main.js:
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.js('resources/js/main.js', 'public/js/')
Edit 1
Based on your comments, and the docs: https://v2.vuejs.org/v2/cookbook/adding-instance-properties.html#The-Importance-of-Scoping-Instance-Properties
The $ is just a convention:
... We scope instance properties with $ to avoid this. You can even use your own convention if you’d like, such as $_appName or ΩappName, to prevent even conflicts with plugins or future features.
So with that in mind you could set it up as:
Vue.prototype.games = games;
then you can access it on every component as this.games
As the documentation implies, when doing this you've got to be careful to not overwrite it. So if you have it declared on the data section of your Vue components i think you should delete those lines...

How to install flickity carousel with vuejs and nuxtjs

I'm a new vuejs developer. I have study vueje for a while and now I decided to develop a project using vuejs.
So I learn about nuxtjs which is server side rendering. everything goes well. I can use bootstrap4 with my project.
Now I would like to use flickity carousel https://flickity.metafizzy.co on my project and I found that there is a vuejs package on https://github.com/drewjbartlett/vue-flickity
I follow the instruction how to install this component to my project by
npm install vue-flickity --save
and put on some code
<script>
import Logo from '~/components/Logo.vue'
import Searchbar from '~/components/Searchbar.vue'
import axios from 'axios'
import Flickity from 'vue-flickity';
export default {
data () {
return {
has_location: false,
flickityOptions: {
initialIndex: 3,
prevNextButtons: false,
pageDots: false,
wrapAround: true
}
}
},
components: {
Logo,
Searchbar,
Flickity
}
}
</script>
but it show window is not defined
I have try this with another component like google map, it's show the same error.
Please tell me what wrong did I do and how to install new component to the project.
Thank you.
Nuxt.js use SSR to render your website server side, therefore window object is not accessible on node.js environment.
What you need to do is use the built-in no-ssr component to prevent Nuxt.js to render it on the server side.
You can simply do this:
<no-ssr>
<Flickity :options="...">
<!-- slides -->
</Flickity>
</no-ssr>
UPDATE: If you still get an error at this point, then load Flickity in
a custom Plugin that you will load with ssr disabled
Create a file named plugins/VueFlickity.js
import Vue from 'vue'
import Flickity from 'vue-flickity'
Vue.component('Flickity', Flickity)
Then in your nuxt.config.js your add:
module.exports = {
// ...
plugins: [
{ src: '~/plugins/VueFlickity.js', ssr: false }
]
}
Don't forget to remove the Flickity local component registration:
components: {
Logo,
Searchbar
// Flickity <-- remove this line
}
This was tested and is now fully working.
I fixed it with:
let Flickity = {};
if (process.browser) {
Flickity = require('flickity.js');
}
#rayfranco pointed a great way.:) The thing is that by doing this in that way You're importing this plugin globally, but not as local component which is better for performance.
So You can do it also like this:
let Flickity;
if (process.client) {
Flickity = require('vue-flickity')
}
export default {
components: {
Flickity
}
}
and use this component this way:
Important: <no-ssr>......</no-ssr> is deprecated in Nuxt > 2.9, so use
<client-only>
<Flickity :options="...">
<div class="carousel-cell">1</div>
<div class="carousel-cell">2</div>
<div class="carousel-cell">3</div>
</Flickity>
</client-only>
you can also look into brief example by Josh Deltener
https://deltener.com/blog/common-problems-with-the-nuxt-client-only-component/

Add components to Vue instance after instance is created

If you've created a VueJS instance like this...
var app = new Vue({
el: '#app',
components: {...}
})
Is it possible to add components to this instance it's instantiated?
The reason I ask is that we have a multi-page app which stares a template. We want the instantiation of the Vue app to be in the shared template code but we want each page to use different components so for example the code on the contact page would be split between two files...
Master.js
Contact.js
The contact.js file would need to tell the main app that it wanted to use the conract-form component, but that component is not used on other pages so we don't want to add it to the initial app declaration in the master.js
Any help would really be appreciated.
Thanks to #thanksd
It seems as though components only have to be registered when instantiating Vue if you want the registered "locally", which means you don't have to register them at all as long as the component code comes before Vue is instantiated.
So, my master template and master.js can contain this...
<div id="app">
<header>Master header</header>
<contact-page inline-template>
Contents of contact page
</contact-page>
<footer>Master Footer</footer>
</div>
var app = new Vue({
el: '#app'
})
Then, my contact.js can contain this....
Vue.component('contact-page', {
... Contact page specific code here...
});
We had a similar trouble, with multiple pages, a layout et multiple components. Our system isn't a SPA. Each page reload. The page content is insert in a global layout with some global options by server code.
We have global components and some more especific by page, our solution is use window to catch Vue and initialize vue after charge the components by page.
IMPORTANT: follow this order declarations: windowVue / code specific for the page / startVue
EX:
layout file:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="../js/windowVue.js"></script>
<!-- all header content -->
<!-- depend your system here call your js specific by page ex: productPage.js -->
<script type="text/javascript" src="../js/productPage.js"></script>
</head>
<body>
<div id="vueApp">
<!-- Your page content-->
</div>
<script type="text/javascript" src="../js/startVue.js"></script>
</body>
</html>
windowVue.js
import Vue from 'vue';
window.Vue = Vue;
productPage.js
// Here two options declare the external components only
import ComponentA from '../js/components/component-a.js';
import ComponentB from '../js/components/component-b.vue';
window.Vue.component('component-a', ComponentA)
window.Vue.component('component-b', ComponentB)
// Or if you use a page component with more logic and options you can declare here
// and include the other components as usual
window.Vue.component('product-page', {
components: {
ComponentA,
ComponentB
},
// rest of the code as usual
})
startVue.js
import GlobalA from '../js/components/global-a.js';
import GlobalB from '../js/components/global-B.js';
new window.Vue({
el:"#vueApp",
delimiters: ['${', '}'],
components: {
GlobalA,
GlobalB
}
})
That's all now each page has their owns components and we have some shared components too.
some remarks:
build the 3 js part separately
Only windowVue.js use import Vue from 'vue' the rest use window.Vue.
.js files components are declared as an object.
component-a.js
import ComponentB from '../js/components/component-b.vue';
import ComponentC from '../js/components/component-c.vue';
import ComponentD from '../js/components/component-d.vue';
export default {
name:'component-a',
components: {
ComponentB,
ComponentC,
ComponentD
},
data() {
return {
variableExample: 'example'
}
} // more of your Vue code
}