Laravel 7 and VueJs Vue Multiselect Noob Question - laravel

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!

Related

Pass data from Blade template to Vue component [duplicate]

This question already has answers here:
Vue template or render function not defined yet I am using neither?
(28 answers)
Closed 1 year ago.
This is a new-comer question. I have a Blade template:
<div id="app">
<example-component
:componentMessage="appMessage"
></example-component>
</div>
<script>
var app = new Vue({
el: "#app",
data: function() {
return {
appMessage: {{$message}}
}
}
})
</script>
And a Vue component
resources/js/components/ExampleComponent.vue
<template>
<p>{{componentMessage}}</p>
</template>
<script>
export default {
props: ['componentMessage'],
}
</script>
So the data flow will look like this: $message -> appMessage -> componentMessage
The <example-component> is not working because I haven't imported it properly.
How am I supposed to use Example component inside Blade template? Providing that I'm using Vue CDN and I want to keep the app declaration right on the Blade template for fancy data transformation (with Blade syntaxes) before passing it to component with appMessage in the middle?
I have been searching for documents. Some requires app declaration in resources/js/app.js, but if I follow this way, I can not pass data to app with Blade mustache syntax.
Update:
resources/js/app.js
import ExampleComponent from "./components/ExampleComponent.vue";
I have tried adding
<script src="{{mix('js/app.js')}}"></script>
And added components declaration in the instance:
components: {
'example-component': ExampleComponent,
}
But it is still not working (Invalid Component definition: ExampleComponent). Probably I missed some steps.
Silly me. I do not need to declare components property in the app Vue instance. Just specify the component that you are going to use in resources/js/app.js and that component will be available globally in Blade template.
Watch for syntax differences between Laravel Mix differences tho. It could be the problem (Vue template or render function not defined yet I am using neither?)
import ExampleComponent from './components/ExampleComponent.vue';
Vue.component('example-component', ExampleComponent);

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

How to use form mask in Laravel with Vue

I'm trying to use mask on Form with Laravel and VueJS using https://vuejs-tips.github.io/vue-the-mask/, I'm new to Vue so I looked for some way to use mask, I ended up finding this lib. However, I do not know how to use the example of the site since it does not show a complete example, just snippets of code.
Displays the second error:
SyntaxError: import declarations may only appear at the top level of a module inscriation: 62: 8
[Vue Warn]: Error compiling template:
[Vue Warn]: Failed to resolve directive: mask
(found in )
I added the code in the blade.php
<script src = "https://cdn.jsdelivr.net/npm/vue/dist/vue.js"> </ script>
<script>
// Local Directive
import {mask} from 'vue-the-mask'
export default {
directives: {mask}
}
</ script>
<template>
<input type = "tel" v-mask = "'##/##/####'" />
</ template>
You can't do import in native (browser) JS, you need to use laravel mix or webpack (or any other bundler)
easiest solution: laravel-mix
npm install laravel-mix --save
then open (or create webpack.mix.js file), and type this (of course you need to specify your own path)
var mix = require('laravel-mix');
mix.js('/resources/path_to_input_javascript', '/public/path_to_resulting_javascript')
In your input file you create simple vue instance (and import your component)
import Vue from 'vue';
import mask from 'path_to_component.vue'
var app = new Vue({
el: "#root", //root element name
components: {'x-mask': mask}
});
and in your component you put the code:
<script>
// Local Directive
import {mask} from 'vue-the-mask'
export default {
directives: {mask}
}
</script>
<template>
<input type = "tel" v-mask = "'##/##/####'" />
</template>
It's not that complex, once you get used to it. You should read/watch about bundlers.

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

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

call to ReactJS component in Laravel blade templates

I use Laravel 5.4 and React 15.5.4, code is writing in ES6.
I'd like replace Vue and use React and I did it. But I often will use small components for example 2 in different places of blade template. I don't want use one app component.
I'd like use something like:
<span class="react">
<TestComponent property={true} />
</span>
I can't do it automatically. Now I use
<span data-component="TestComponent" data-props="{property:true}" />
and in app.js
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
if(item.name !== 'data-react'){
element.removeAttribute(item.name);
}
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works but I need to use add all properties to one react component property and then use for example this.props.out.propery
I also would like set normal component tag in my blade component
I've try to use in app.js
_.each(document.querySelectorAll('.react'), item => {
ReactDOM.render(item.children,item);
});
Someone have any idea to solve this problem?
EDIT
I changed my solution to:
<span data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
or
<LoginForm data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
in blade and in resources/assets/js/app.js
var reactComponents = {
LoginForm: require('./components/login').default,
};
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works fine. This is not super clear solution but I have impression that the reasonable.
I can set components name in html code and add props almost same like in JSX.
As far as I know, you can not mix JSX components directly with Blade templates. The only server side rendering available today for React is NodeJS.
What you could do to improve your architecture is add specific HTML tags with certain ids and render the react components in them. So inside Blade you could do something like:
<div id="componentA"></div>
This will act as a place holder in your Blade template for that react component. Then you render your componentA from your app.js like this:
React.render(<ComponentA prop1='valueX'/>, document.getElementById("componentA"))
Remember that in this case the world of react and world of Blade run at different times.
You could use document.getElementsByTagName('LoginForm') getting all the instances and later iterate its attributes. It's clear code but not generic, because it will work just for LoginForm components.
If you want to render any tag name, then maybe it's better to use some attribute as you used with data-react.
getElementsByTagName isn't super supported by old browsers so maybe could a good idea to use jQuery as fallback $('LoginForm')

Resources