Dropzone is not defined when used inside a component - vue.js

Im currently trying to import vue2-dropzone into my Laravel project so it is using Laravel mix.
I am importing it in my bootstrap.js as below:
import vueDropzone from "vue2-dropzone";
Vue.component('vueDropzone', vueDropzone)
I then want to be able to use in one of my components which is inside a file called "CreatePersonalExpense.vue". This component is accessed using Vue router.
Below is a snippet of how it is being used in my component:
<template>
<div class="form-row py-2">
<div class="col-md-12">
<h4>Upload</h4>
<vue-dropzone v-on:vdropzone-sending="sendingFiles" id="drop1" ref="myVueDropzone" #vdropzone-complete-multiple="afterAllFilesUploaded" :options="dropOptions"></vue-dropzone>
</div>
</div>
</template>
<script>
export default {
data() {
return {
type: "personal",
id: "",
total: "",
files: {
},
dropOptions: {
url: '/api/expenses/files',
autoProcessQueue: false,
uploadMultiple: true,
headers: { "x-csrf-token": document.querySelector('meta[name="csrf-token"]').getAttribute('content') },
params: {}
},
errors: new Errors(),
form: new Form(),
}
},
components: {
vueDropzone
}
}
</script>
However the dropzone is not recognised and I get the error:
Uncaught ReferenceError: vueDropzone is not defined
However if I were to import the dropzone directly into this Vue component by putting import vueDropzone from "vue2-dropzone"; at the beginning of the script tag, dropzone works fine. Why can't I just include it in the bootstrap.js file and have it work for there?

If you already register vueDropzone in bootstrap.js, you don't need to register it again in your component. You should remove this in CreatePersonalExpense.vue
components: {
vueDropzone
}
vueDropzone is an undefined variable. Just remove it and it should work.

Try defining as below =>
Vue.component('vue-dropzone', vueDropzone)

Related

Vue components - recursive rendering or what is the problem here?

I'm trying to make a new Vue app with 2 components but the components don't render.
The error is - "Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option."
I read quite a bit on the problem but could not identify the problems in the code unlike with others' codes.
Seems OK to me, not the first app with components I've written :/
App:
require('../../lib/jquery.event.drag-2.2/jquery.event.drag-2.2');
require('../../lib/jquery.event.drag-2.2/jquery.event.drag.live-2.2');
require('../../lib/jquery.event.drop-2.2/jquery.event.drop-2.2');
require('../../lib/jquery.event.drop-2.2/jquery.event.drop.live-2.2');
import Vue from 'vue';
import Axios from 'axios';
Vue.prototype.$http = Axios;
import tournamentCourtManager from
'../../components/tournament/courtManager/courtManager';
import tournamentScheduleButton from
'../../components/tournament/tournamentScheduleButton';
import { store } from "../../store/store";
new Vue({
el: '#tournamentMatchSettingsApp',
store,
components: { 'tournamentCourtManager' : tournamentCourtManager,
'tournamentScheduleButton' : tournamentScheduleButton }
});
tournamentCourtManager:
<template>
<button type="submit" class="btn btn-info">
dadada
</button>
<script>
export default {
name: 'tournamentScheduleButton',
data() {
return {}
},
mounted: function mounted() {
},
methods: {
}
}
</script>
courtManager:
<template>
<div id="tournamentCourtManager">
..
</div>
</template>
courtManager JS:
export default {
name: 'tournamentCourtManager',
components: {
'match-cell': matchCell
},
data() {
return {
};
},
....
}
And the code that prompts the error -
<tournamentschedulebutton></tournamentschedulebutton>
<tournamentcourtmanager></tournamentcourtmanager>
Because you have named the components like 'tournamentCourtManager' in the components object, they must be named like <tournament-court-manager> in the template.

Why is the activated lifecycle hook not called on first visit

I have a problem where a component within a router-view that is being kept alive does not call its activated lifecycle hook when first created. The created and mounted lifecycle hooks are being called. On a second visit, the activated hook is being called.
The scenario is quite complicated as there is a bit of nesting and slot using involved.
I've tried to create a minimal example which you can find below, or a bit more detailed on https://codesandbox.io/s/251k1pq9n.
Unfortunately, it is quite large and still not as complicated as the real code which I unfortunately cannot share.
Worse, I failed to reproduce the actual problem in my minimal example. Here, the created, mounted, and activated lifecycle hooks are all called when first visiting SlotExample.
In my real code, only the created and mounted, lifecycle hooks are called on the first visit, the activated hook is called on subsequent visits. Interestingly, all lifecycle hooks are called as expected for SlotParent.
The real code involves more nesting and makes use of slots to use layout components.
My code is using Vue 2.5.16 and Vue-Router 3.0.1 but it also doesn't work as expected in Due 2.6.7 and Vue-Router 3.0.2. I am also using Vuetify and Vue-Head but don't think think this has anything to do with my problem.
index.js.
Does anyone have an idea what I could have been doing wrong. I actually suspect a bug in vue-router
when using multiple nested slots and keep-alive but cannot reproduce.
index.js
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import Start from "./Start.vue";
import SlotExample from "./SlotExample.vue";
const routes = [
{
path: "/start",
component: Start
},
{
path: "/slotExample/:id",
component: SlotExample,
props: true
}
];
const router = new VueRouter({ routes });
Vue.use(VueRouter);
new Vue({
render: h => h(App),
router,
components: { App }
}).$mount("#app");
App.vue
<template>
<div id="app">
<div>
<keep-alive><router-view/></keep-alive>
</div>
</div>
</template>
SlotExample.vue
<template>
<div>
<h1>Slot Example</h1>
<router-link to="/start"><a>start</a></router-link>
<router-link to="/slotExample/123">
<a>slotExample 123</a>
</router-link>
<slot-parent :id="id">
<slot-child
slot-scope="user"
:firstName="user.firstName"
:lastName="user.lastName"/>
</slot-parent>
</div>
</template>
<script>
import SlotParent from "./SlotParent.vue";
import SlotChild from "./SlotChild.vue";
export default {
name: "slotExample",
components: { SlotParent, SlotChild },
props: {
id: {
type: String,
required: true
}
}
};
</script>
SlotParent.vue
<template>
<div>
<div slot="header"><h1>SlotParent</h1></div>
<div slot="content-area">
<slot :firstName="firstName" :lastName="lastName" />
</div>
</div>
</template>
<script>
export default {
name: "slotParent",
props: {
id: {
type: String,
required: true
}
},
computed: {
firstName() {
if (this.id === "123") {
return "John";
} else {
return "Jane";
}
},
lastName() {
return "Doe";
}
}
};
</script>
SlotChild.vue
<template>
<div>
<h2>SlotChild</h2>
<p>{{ firstName }} {{ lastName }}</p>
</div>
</template>
<script>
export default {
name: "slotChild",
props: {
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
}
},
created() {
console.log("slotChild created");
},
mounted() {
console.log("slotChild mounted");
},
activated() {
console.log("slotChild activated");
}
};
</script>
I think you need to put SlotChild within keep-alive block.
Take a look at vue js doc about activated hook

Render and Compile String using vue.js

There is a requirement where all html elements are defined in a JSON file and used in the template.
There is a function - "markComplete" which needs to be triggered on change of a checkbox.
Code Template:
<template>
<span v-html="htmlContent"></span>
</template>
<script>
data(){
return{
htmlContent: "<input type='checkbox' v-on:change='markComplete'>"
}
}
</script>
Above code won't work as onChange event won't be mounted, and I get Uncaught ReferenceError: markComplete is not defined
Is there any way to make this work?
You are trying to compile the string as Vue Templates using v-html.
Note that the contents are inserted as plain HTML - they will not be compiled as Vue templates
Read about v-html in Vue Docs.
As solution you can read this article
You don't want to use a library? Checkout the code below:
First create a js file (preferably RenderString.js):
import Vue from "vue"
Vue.component("RenderString", {
props: {
string: {
required: true,
type: String
}
},
render(h) {
const render = {
template: "<div>" + this.string + "</div>",
methods: {
markComplete() {
console.log('the method called')
}
}
}
return h(render)
}
})
Then in your parent component:
<template>
<div><RenderString :string="htmlContent" /></div>
</template>
<script>
import RenderString from "./components/RenderString"
export default {
name: "App",
data: () => ({
htmlContent: "<input type='checkbox' v-on:change='markComplete'>"
})
}
</script>
Note: I didn't run the code above but I created a similar working CodeSandbox Example

Vue.js single file component 'name' not honored in consumer

Please pardon my syntax, I'm new to vue.js and may not be getting the terms correct.
I've got a single file component (SFC) named CreateTodo.vue. I've given it the name 'create-todo-item' (in the name property). When I import it in my app.vue file, I can only use the component if I use the markup <create-todo>. If I use <create-todo-item>, the component won't render on the page.
I've since learned that I can do what I want if I list the component in my app.vue in the format components: { 'create-todo-item': CreateTodo } instead of components: { CreateTodo }.
My question is this: is there any point to giving the component a name in the name property? It's not being honored in the consumer, and if I leave it empty, the app runs without error.
Also, am I correct in my belief that vue-loader is assigning the kebab-case element name for template use based on the PascalCase import statement?
Bad - component name property
Here's the code where I try to name the SFC (CreateTodo.vue)
<script>
export default {
name: 'create-todo-item',
data() {
return {
titleText: '',
projectText: '',
isCreating: false,
};
},
};
</script>
The name as listed in the component is ignored by my App.vue. The html renders fine even though I have the element <create-todo> instead of <create-todo-item>:
<template>
<div>
<!--Render the TodoList component-->
<!--TodoList becomes-->
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:make-todo="addTodo"></create-todo>
</div>
</template>
<script>
import TodoList from './components/TodoList.vue'
import CreateTodo from './components/CreateTodo.vue'
export default {
name: 'app',
components: {
TodoList,
CreateTodo,
},
// data function avails data to the template
data() {
return {
};
},
methods: {
addTodo(todo) {
this.todos.push({
title: todo.title,
project: todo.project,
done: false,
});
},
}
};
</script>
Good - don't use component name property at all
Here's my CreateTodo.vue without using the name property:
<script>
export default {
data() {
return {
titleText: '',
projectText: '',
isCreating: false,
};
},
};
</script>
And here's my App.vue using the changed component:
<template>
<div>
<!--Render the TodoList component-->
<!--TodoList becomes-->
<todo-list v-bind:todos="todos"></todo-list>
<create-todo-item v-on:make-todo="addTodo"></create-todo-item>
</div>
</template>
<script>
import TodoList from './components/TodoList.vue'
import CreateTodo from './components/CreateTodo.vue'
export default {
name: 'app',
components: {
TodoList,
'create-todo-item': CreateTodo,
},
// data function avails data to the template
data() {
return {
};
},
methods: {
addTodo(todo) {
this.todos.push({
title: todo.title,
project: todo.project,
done: false,
});
},
}
};
</script>
First note that the .name property in a SFC module is mostly just a convenience for debugging. (It's also helpful for recursion.) Other than that, it doesn't really matter when you locally register the component in parent components.
As to the specific details, in the first example, you're using an ES2015 shorthand notation
components: {
TodoList,
CreateTodo,
},
is equivalent to
components: {
'TodoList': TodoList,
'CreateTodo': CreateTodo
},
so that the component that is imported as CreateTodo is given the name 'CreateTodo' which is equivalent to <create-todo>.
In the second example, you give the name explicitly by forgoing the shorthand notation
components: {
TodoList,
'create-todo-item': CreateTodo,
},
That's equivalent, btw to
components: {
TodoList,
'CreateTodoItem': CreateTodo,
},
So you can see, in that case, that you're giving the component the name 'CreateTodoItem' or, equivalently, <create-todo-item>

Why are my Vue instance's properties and methods not available in the template?

I set up a Vue.js CLI project.
On a page, I want to define a variable in data() and then use it in my template.
Why does the following code tell me:
Property or method "message" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
<template>
<div>
<h1>Page 2</h1>
<p> You can go back to
<router-link to="/">home</router-link>.</p>
<p>[{{message}}]</p>
</div>
</template>
export default {
name: "Page2",
data() {
return {
message: "here it is"
}
}
}
And this code:
<button class="btn" #click="test()">the test</button>
</p>
</div>
</template>
export default {
name: "Page2",
data() {
return {
message: "here it is"
}
},
methods: {
test() {
console.log('test');
}
}
}
Tells me similarly:
Property or method "test" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
What else do I need to do to make these variables and methods available in my template on the page?
This structure of code has worked in other Vue.js CLI projects so it much be something not set right in the project in the environment somewhere.
For instance, this code works in another project:
<template>
<div class="start alert alert-success" role="alert">
{{ msg }}
</div>
</template>
<script>
export default {
name: 'start',
data() {
return {
msg: 'Please choose an option.'
}
}
}
</script>
And it works on the Home page but not on Page1 or Page2. My index.js page looks like this:
import Vue from "vue";
import Router from "vue-router";
import Home from "#/components/Home";
import Page1 from "#/components/Page1";
import Page2 from "#/components/Page2";
Vue.use(Router);
export default new Router({
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/page1",
name: "Page1",
component: Page1
},
{
path: "/page2",
name: "Page2",
component: Page2
}
]
});
You need to add <script> tags around the javascript for your Page1 and Page2 components.
Otherwise, it seems like vue-loader just ignores that script and doesn't give you a relevant warning (just that the data being referenced in your template is missing).