What is the best way to use v-model without using it in the main app.js file? - laravel

I was wondering i have this code inside my blade file:
<input type="text" class="form-control" :model="productname" id="name" name="name" aria-describedby="emailHelp" placeholder="Title" value="{{ old('name') }}" required>
and i want to create an 2 way data binding, so when user submitted 3 or more character to get an green background of this input field, but when they are less to get a red background.
I tried to do this with vue-component, but it seems for whatever reason the vue-component does not have access to the main #app id which is assign to the main app blade template in order all vue code to have access to the html code and change it. I have created an vue-component called Upload inside ressources/assests/js/components/Upload.js, but when i write this code:
<template>
</template>
<script>
export default {
data() {
return {
productname: '',
};
},
mounted() {
console.log('Upload component', this.message);
}
}
</script>
and added of course to app.js like that Vue.component('upload-component', require('./components/Upload.vue'));
and run - npm run dev to compile the code i am getting this error:
[Vue warn]: Property or method "productname" 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.
Whatever when i write this code inside the main app.js file (resources/assests/js/app.js):
const app = new Vue({
el: '#app',
data() {
return {
productname: '',
};
},
});
everything is working fine and i dont get any errors, but i dont want that, as imagine for my website/app i have to have for example 100 v-models and i dont want to put them all inside the main app.js file. Is there other way to do this?
Can i still somehow make it work inside the vue component, so the component can see the v-model and not giving me this error?
If not, can i make it work and use vue inside the blade file something like that?
new Vue({
el: '#form',
data: {
productname: ''
}
});
but this code its not working. Thanks!

It's a bit tricky to make out what you are doing exactly, but your error is related to having no data property 'message', you have only a property called 'productname'.
If you want your component to communicate up to its parents or siblings you should read into emitting events in vue using
this.$emit

Related

Vue2 + laravel6 - Component implementation

I just started using Vue2 with Laravel6 and got stuck when trying to understand how to use component method.
As I am totally new for Vue, I am using the official tutorial of Vue as a reference. What I learned from here(https://v2.vuejs.org/v2/guide/components.html) about Vue component instantiation is we give options to a component.(e.g. we give 'template:' options for HTML part.)
When I look at laravel6 codes of resouces/js/app.js, it looks something like this:
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
I looked at js/components/ExampleComponent.vue expecting to see some options declared there. However, there's no option in the ExampleComponent.vue file. Instead, I see <template></template> tag. Apparently, the <template></template> tag seems to work as 'template:' option.
I have two questions regarding above:
Does <template></template> tag have the same meaning as 'template:' option?
If question 1 is yes, are other options also replacable with corresponding tags? (e.g. Can I use <props></props> tag for 'props:' option? or <data></data> tag for 'data:' option?
Thanks in advance!
In Vue world, there are two popular types of defining a component
First Type
in this type, you add all of your HTML inside the template property
and the props add as attribute inside the component object to
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
Second Type
in this type you add your component logic in a separate file ends with .vue
for example in laravel there is an ExampleComponent.vue file you will find on
it just template tag just as a wrapper for your component content and your logic you can write it as it mentions below.
<template>
// some content here
</template>
<script>
export default {
props: [],
methods: {
},
data(){
return {
}
}
}
</script>
Finally
there is no tag called props or data
for more info read this article

Upload multiple files, picking them one by one, with BootstrapVue b-form-file

I'm uploading files with b-form-file in BootstrapVue, setting multiple to true works perfectly for multiple files, BUT each time I choose a file it removes any previously added ones. And the files will often be spread across multiple folders, so I need to be able to pick a file from one folder, choose it, pick another file from another folder, and so on.
Here's the HTML:
<b-form ref="form" novalidate action="upload" method="post" enctype="multipart/form-data">
<b-form-file name="file_upload[]" :multiple="true" :file-name-formatter="formatAssetUpload" no-drop placeholder="Click to choose"></b-form-file>
</b-form>
I've tried adding
ref="fileUpload"
to the b-form-file tag and then in the formatAssetUpload function just setting the value, but that doesn't work. There's a setFiles function in there but it doesn't seem to affect anything. I tried catching the form on submit and manually adding the files to formdata but that's not working either, whatever I try there's always only the last file/files that were picked coming through on the backend.
Any ideas?
Thanks for any help! :)
If you like to remember the file objects which have been selected by the user you an use this javascript:
new Vue({
el: '#app',
data() {
return {
files: [],
filesAccumulated: []
}
},
methods: {
onChange(event) {
this.files.forEach(thisFile => {
this.filesAccumulated.push(thisFile)
})
},
onReset() {
this.filesAccumulated = []
}
}
})
Together whit this vue template
<div id="app">
<b-form-file
v-model="files"
multiple plain
v-on:input="onChange">
</b-form-file>
<div>
<ul>
<li v-for="thisFile in filesAccumulated">
{{ thisFile.name }}
</li>
</ul>
</div>
<b-button v-on:click="onReset">
Reset
</b-button>
</div>
The b-form-file vue component is emitting an input event when the user performs the selection. The file objects can be picked up
from the variable bound with the v-model directive. See documentation
Look at this fiddle https://jsfiddle.net/1xsyb4dq/2/ to see the code in action.
General comments
Let me make some comments on your code example and b-form-file component in general: With bootstrap-vue and <b-form-file> it is not the idea to use an enclosing form tag to submit forms. Instead you use vue's v-model feature to obtain the file objects from vue's data object.
I have created a more comprehensive example here https://jsfiddle.net/to3q7ags/ , but I will explain step by step:
The value of the v-model attribute is the name of a vue data property:
<b-form-file v-model="files" multiple plain></b-form-file>
After the user has clicked 'Browse' in the file input field, has selected the files and pressed ok, the vue data property will hold an array of file objects:
new Vue({
el: '#app',
data() {
return {
files: []
// initially empty, but will be populated after file selection
}
}
})
From the b-form file documentation:
When no files are selected, an empty array will be returned. When a
file or files are selected the return value will be an array of
JavaScript File object instances.
After files are selected by the user you can send the files to your server on a button click or change event.
<b-button v-on:click="onSubmit">
Submit
</b-button>
the corresponding vue method looks like this
methods: {
onSubmit() {
// Process each file
this.files.forEach(thisFile => {
console.log("Submitting " + thisFile.name)
// add submit logic here
}
}
To submit the files you need to manually create a http post request which is using the multipart/form-data encoding. That can be done by using FormData class.
const formBody = new FormData()
formBody.set("formParameter", thisFile)
The FormData.set() method is accepting file blobs as arguments. Then you can use XMLHttpRequest.send() or fetch() to send the post request:
fetch(
"https://yourserver/post",{
method: 'POST',
body: formBody})
.then(response => console.log(response))
Now all selected files are posted to the server. The user can repeat the process with the same form, select new set of files and again press the post button.
You can also send the form automatically without the use of a button by listening to the 'input' event. Drag and drop also works.

Laravel 7 and VueJs Vue Multiselect Noob Question

I am a totally noob at laravel and npm and vuejs things.
I made a new Laravel Project and instead of playing around with jquery I want to learn how to use vuejs.
I ran against a wall today :( trying 2 days to get this Multiselect (https://vue-multiselect.js.org/#sub-select-with-search) running on my project.
I think I am missing some basics ...
What I've done:
ran on terminal npm install vue-multiselect
created in resources/js/comonents/Multiselect.vue
pasted this code in /Multiselect.vue:
<template>
<div>
<multiselect
v-model="selected"
:options="options">
</multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: { Multiselect },
data () {
return {
selected: null,
options: ['list', 'of', 'options']
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
added to my app.js in resources folder:
- import Multiselect from "vue-multiselect";
- Vue.component('v-multiselect', require('./components/Multiselect.vue'));
- const app = new Vue({
- el: "#app",
- data: {
- users: '',
- firmas: '',
}});
and in my blade file I used:
<v-multiselect></v-multiselect>
So far ... so good
npm run dev and refreshed the page.
Error:
index.js:133 [Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <VMultiselect>
<Root>
so I have two questions is this the correct way to implement external vuejs components inte Laravel ?
and what If it is the right way am I doing wrong - at which points???
Thank you all out there to help me to learn ...
I'm glad you got your code working! To answer your question, it looks like you're using a mix of the external component you're importing and your own custom component which uses that component which may be what is confusing you a little bit.
When you do the following:
import Multiselect from "vue-multiselect";
inside your app.js file, you are importing an external component globally. When you place that import inside of a component, you are importing the external component for use within that component only. In your current code you've posted, you are importing it both globally and within your component.
If you are registering a component globally (within the element id assigned to the vue instance), you can register it like this within your app.js file:
import Multiselect from "vue-multiselect";
Vue.component('multiselect', Multiselect);
Then in your components, you will not have to import it again, but simply use it like this:
<template>
<div>
<multiselect v-model="selected" :options="options" placeholder="Select one" label="name" track-by="name"></multiselect>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: ['one','two','three'],
}
},
}
</script>
You would also be able to use this component in your blade since it is defined within your app.js file.
However with the setup you're using now, your fix of:
Vue.component('v-multiselect', require('./components/Multiselect.vue').default);
is not actually registering the external component. You are registering YOUR component.
So to answer your question, yes, you've taken an external component where you can make your custom component and easily add reusable content around it which is perfectly valid use, but you could either remove the extra import of Multiselect in your app.js file, or import the Multiselect external component globally, like I mentioned above.
Update:
Found the solution for my problem:
in my app js there was the error!
Vue.component('v-multiselect', require('./components/Multiselect.vue').default);
I registered the component wrong :(
So second question is answered :)
But do you guys do it the same way? or I am completly wrong implementing external commponets into laravel?
I don't want to use vueex or vuerouter for now ... I need to learn laravel itself ... afterwards I know how Laravel works I will use vuerouter ... for my projects ...
So sorry for the long text - but needed to explain a little bit more about the situation - thnaks for reading guys!
Thank you very much Sawyer,
I got it, I thought :(
I want to use this multiselect component muptliple times in my page.
So I removed the extra import in my app.js - saw it in phpstorm that it was unused but didn't know why :) - now I know.
What I have so far:
hit me if I am wrong :)
in app.js: (registering my own component)
Vue.component('v-multiselect', require('./components/Multiselect.vue').default);
added Multiselect.vue to my components folder in laravel with this src:
<template>
<div>
<multiselect v-model="value" :options="options"></multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
// register globally
Vue.component('multiselect', Multiselect)
export default {
// OR register locally
components: { Multiselect },
data () {
return {
value: null,
options: ['option1','option2','option3']
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
and in my blade file:
<v-multiselect :options="['one','two','three']" ></v-multiselect>
I get no errors at all from vuejs butit isn't working as it should:
How do I overwrite the options array from my blade file ? As I saw on the documentation "options" is a prop of the component so why am I getting as select the predefined option array ['option1','option2','option3'] and not the array from the blade file:['one','two','three'] am I missing a shortcut or something else?? Thanks a lot for your patience ...
If you can tell me where to read about it - except the docs of vuejs - I think this will help me a lot!

Custom Component in Laravel Spark

I try to add my custom component to my Laravel Spark instance and always get the error:
Property or method "obj" is not defined on the instance but referenced during render..
It all works fine if i only bind a data value (ex. "testkey") without a loop...but if i add the for loop i receive this error...so my code:
app.js (spark)
require('spark-bootstrap');
require('./components/bootstrap');
//my new Component
import OmcListObjects from './components/modules/omc/objectlist.vue';
Vue.component('omc-objectlist', OmcListObjects);
var app = new Vue({
mixins: [require('spark')]
});
my Component (objectlist.vue)
<template>
<div :for="(obj in objlist)" class="property-entry card col- col-md-4 shadow-sm">
</div>
</template>
<script>
export default {
data () {
return {
objlist: [{title: 'test1'}, {title: 'test2'}],
testkey: 'testval'
}
}
}
</script>
I think you mean by :for the v-for directive, directives are always prefixed by v- like v-for one in which the compiler can recognize the obj variable as an temporary element used in the loop, but if you set :for which is recognized as a prop bound to a data or another property.

How to pass an object from Laravel to Vue without using props

I'm setting up some Vue Components in my Laravel 5.8 application, that require user information available through Auth::user(), most importantly, the api_token that I must use in my axios requests. I want to pass the Auth::user() object from Laravel to Vue in a secure and private method.
I initially passed the object as props, but I don't want private information on the object to be easily exposed using browser extensions such as Vue DevTools. Now, I've been searching for a way to define global variables inside the Blade Template and access them in Vue:
Pass data from blade to vue component
https://forum.vuejs.org/t/accessing-global-variables-from-single-file-vue-component/638
https://zaengle.com/blog/layers-of-a-laravel-vue-application
Based on those links above, it seems like what I need to do is set the variables to the window object, but I'm unsure on what I'm doing something wrong to achieve this. When I define the variable in the Blade Template, I can see the variable is assigning properly by doing console.log() but the problem comes when I try to use it in Vue.
app.blade.php
#if(Auth::user())
<script>
window.User = {!! json_encode(Auth::user()) !!}
console.log(window.User)
</script>
#endif
component.vue
<script>
export default {
data: function() {
return {
user: window.User
}
}
}
</script>
I've tried setting the data as window.User, this.User, and simply just User but it always comes up as undefined. What am I missing? Or is there any other/better way to do this?
Try the following Vue Component:
<template></template>
<script>
export default {
data: function() {
return {
user: window.User
}
},
created(){
console.log(this.user)
},
}
</script>
I could see the user data from the console.log in Vue component.

Resources