Functions on mixin is not being recognize by component - laravel

Hi Iam using laravel 8 and vue.js
so my problem is that the functions on my mixin is not being recognize
this is QuestionMixin.js
export default {
data(){
return{
ifClicked:true,
items:[
{
answer:null,
choices:[],
question:null
},
]
}
},
methods:{
AddQuestion:function(){
var insert = {
answer:null,
choices:[],
question:null
}
this.items.push(insert);
},
},
}
and here is my component
<template>
<section id="q-main">
{{ ifClicked }}
</section>
</template>
<script>
import QuestionMixin from "./mixins/QuestionMixin";
import QuestionHolderComponent from "./QuestionHolderComponent.vue";
export default {
components:{
'QuestionHolderComponent':QuestionHolderComponent
},
mounted() {
},
mixins:['QuestionMixin'],
}
</script>
and this is the error i recieved
[Vue warn]: Property or method "ifClicked" 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. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> at resources/js/components/QuestionComponent.vue
``

The mixin shouldn't be passed as string, you should add the imported mixin object to the array of mixins option:
mixins:[QuestionMixin],

Related

v-navigation-drawer controlled state from a sub-component

I have a v-navigation-drawer which can be opened by clicking a button in a sub component.
So I changed v-model="drawer" to simply value="drawer" otherwise I get a warning about mutating a prop which makes sense (feels like doing some dirty angular double-way data binding ^^).
Here's the code:
layouts/default.vue:
<template>
<Header :toggleLeftMenu="toggleLeftMenu" />
<LeftMenu :show="showLeftMenu" :toggleLeftMenu="toggleLeftMenu" />
</template>
<script>
export default {
data() {
return {
showLeftMenu: true,
}
},
methods: {
toggleLeftMenu() {
this.showLeftMenu = !this.showLeftMenu;
},
}
}
</script>
components/layout/LeftMenu.vue:
<v-navigation-drawer
:value="show"
width="300"
clipped
fixed
app
>
This issue is that the drawer can be closed by clicking on the backdrop (on small devices). I need to plug the backdrop click to toggleLeftMenu prop, but according to the doc, this doesn't seem to be possible.
How can I achieve full control on the component? Is this #backdropClick event missing or something?
I tried to use #input but it creates an infinite loop which also makes sense.
Thanks
Using vuetify 2.6.1.
I changed v-model="drawer" to simply value="drawer" otherwise I get a warning about mutating a prop
This is not quite the right decision. Of course you should not use drawer as model, but you can create an internalDrawer prop in LeftMenu component, and leave the v-model where it is.
One of the possible ways to resolve your issue is to emit events from both sub-components into its parent.
So let's rewrite your LeftMenu component this way:
<template>
<v-navigation-drawer v-model="internalShow" width="200" clipped fixed app>
some drawer data
</v-navigation-drawer>
</template>
<script>
export default {
props: {
show: Boolean,
},
data() {
return {
internalShow: this.show,
};
},
watch: {
show (val) {
this.internalShow = val;
},
internalShow (val) {
if (val !== this.show) {
this.$emit("change-drawer-state");
}
},
},
};
</script>
In this case, every time when the internalShow state changes, an change-drawer-state event will be emitted.
Your Header component can be rewrited the same way:
<template>
<v-btn #click="$emit('change-drawer-state')">Drawer button</v-btn>
</template>
And this is the code of your parent component:
<template>
<div>
<Header #change-drawer-state="toggleLeftMenu" />
<LeftMenu :show="showLeftMenu" #change-drawer-state="toggleLeftMenu" />
</div>
</template>
<script>
import LeftMenu from "./LeftMenu";
import Header from "./Header";
export default {
components: {
LeftMenu,
Header,
},
data() {
return {
showLeftMenu: false,
};
},
methods: {
toggleLeftMenu() {
this.showLeftMenu = !this.showLeftMenu;
},
},
};
</script>
Both change-drawer-state event handlers are calling the same method - toggleLeftMenu and then the method changes show prop of navigation-drawer.
You can test this solution in a CodeSandbox playground.

Vue component, prop is declared and passed, but console says prop is missing

I'm working on creating reusable form inputs using vue + laravel.
I have one prop that is required, and I pass it and it renders as expected, but the console still logs the error:
"Vue warn]: Missing required prop: "inputId"".
Inspecting the vue element shows the prop as defined. Why is an error being generated while the the data is being passed?
Text Input Component
<template>
<input type="text" :name="inputId" :id="cssid" :placeholder="placeholder" :value="value">
</template>
<script>
export default {
props: {
inputId: {
type: String,
required: true,
},
isRequired: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
},
value: {
type: String,
default: '',
},
},
mounted() {
console.log('text mounted.')
},
computed: {
cssid() {
return this.inputId + '_selection';
},
},
}
</script>
Fragment of blade view where component is being called (I've tried with title in quotes and not in quotes, no difference)
<text-input
input-id="title"
></text-input>
Resultant html Result is correct, but why the error?
<input type="text" name="title" id="title_selection">
In this case, I had two instances of the component and I didn't realize the older one was there. The older one didn't have the prop declared and was giving the error, but it wasn't obvious in the console that I had loaded it twice. Removing the older instance of the component fixed the error.

Laravel Nova | Arrow functions | computed property not working in Tool.vue

I have a computed property that is not working correctly. When reading the docs this is how it should be done for Vue 2.x. The code i have:
<template>
<div>
<button :disabled="isDisabled">Import configurator data</button>
<input class="input" type="file" id="file" v-on:change="setFile">
</div>
</template>
<script lang="js">
export default {
data: () => {
return {
importDisabled: true,
}
},
computed: {
isDisabled() {
return this.importDisabled;
},
},
methods: {
setFile: (e) => {
this.importDisabled = false;
},
}
}
</script>
Expected behaviour: Button enables when a file is selected.
Actual behaviour: Button stays disabled.
What am i missing here? A console.log within the isDisabled() methods shows it is only called once. It is not called after importDisabled changes.
Other info:
vue 2.6.12
laravel nova
Also note: Vue tools does not detect a Vue component in the inspector. But the Vue behaviour is working when loading the tool.
It seems arrow functions are bound to the parent context. That was the reason my code did not work. this is then not bound to the Vue instance but the parent (Window) which causes it not to work.
Wrong:
setFile: (e) => {
this.importDisabled = false;
},
Right:
setFile: function() {
this.importDisabled = false;
},
More information:
https://codingexplained.com/coding/front-end/vue-js/using-es6-arrow-functions-vue-js

How to avoid warning "mutating a prop directly" using Vue and Laravel

I am using Laravel 7 and Vue.js 2.
I want to pass an eloquent query result from a controller to a Vue.js component (passing through a View and another component).
This is my controller:
$permissions = Permission::select('id')->get();
return view('admin')->with(['permissions'=>$permissions]);
This is my view:
<div id="app">
<admin-panel :permissions="{{ $permissions }}"></admin-panel>
</div>
This is admin-panel component (passing data through props):
<template>
<div>
<admin-operations></admin-operations>
<hr>
<insert-employee :permissions="permissions"></insert-employee></div>
</template>
This is insert-employee component script:
<script>
export default {
components: {
},
props: ['permissions'],
mounted() {
console.log('Component mounted.');
},
computed:{
},
data: function() {
return {
}
},
methods: {
}
}
</script>
This is the select in insert-employee component:
<select required v-model="permissions" class="form-control" id="permissions">
<option v-for="permission in permissions" :value="permission.id" :key="permission.id">
{{ permission.id }}
</option>
</select>
The results of the query should be visualized in the select options.
However in the select I can visualize correctly the values in the options, but when I select an option the selection doesn't work and in the console appears two times the following warning:
app.js:40160 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "permissions"
found in
---> <InsertEmployee> at resources/js/components/InsertEmployee.vue
<AdminPanel> at resources/js/components/AdminPanel.vue
<Root>
Can help?
Let's try this. I think we're just mixing the values up a bit. I'll try to think of props that are passed in as a read only thing. In this case permissions is an array that holds the id's of each permission.
Next we'll want to use that array to give our user object some values. This way we aren't trying to manipulate values of permissions. That's where Vue was initially getting angry.
<script>
export default {
components: {},
props: {
permissions: {
type: Array,
required: true,
default: () => [],
}
},
mounted() {
console.log('Component mounted.');
},
computed:{},
data: () => ({
user: {
permissionId: "",
}
}),
methods: {},
}
</script>
Then in your component template:
<select required v-model="user.permissionId" class="form-control" id="user-permissionId">
<option v-for="permission in permissions" :value="permission.id" :key="permission.id">
{{ permission.id }}
</option>
</select>

Two way bind into template

I've been searching for hours now and i just can't figure it out..
Is there any way that i could bind the data from an input, send it to the template and here use the data?
Let me paint the picture...
edit.php
<form>
<input v-model="?">
</form>
<prod-preview name="somehowsendthename"></prod-preview>
prod-preview.vue
<template>
<h1>{{ name }}</h1>
</template>
<script>
export default {
name: "product-preview",
props: ["name"],
data(){
return {
name: ""
}
},
}
Don't worry about binding the actual component, that works. Thank you
Something like this should work:
// edit.vue
<template>
<form>
<input v-model="name">
</form>
<prod-preview :name="name"></prod-preview>
</template>
<script>
import ProdPreview from './prod-preview'
export default {
name: "edit",
components: [ProdPreview],
data(){
return {
name: ""
}
},
}
</script>
// prod-preview.vue
<template>
<h1>{{ name }}</h1>
</template>
<script>
export default {
name: "product-preview",
props: ["name"]
}
</script>
To pass a name in from the blade and bind it to the data in the view component, you want a prop with a different name, something like initialName and then set the data name that you bind with v-model using the initialName like this...
export default {
name: "product-preview",
props: ["initialName"],
data(){
return {
name: this.initialName
}
},
}
Note that html attributes are case insensitive so you'd pass that in like this and it will be received by the correct prop:
<prod-preview initial-name="{{ $name }}"></prod-preview>
You can now v-bind to "name" and it will keep the data attribute name current as you change that input and you won't be attempting to change a prop which should not be done.

Resources