Component inside the default slot - laravel

I am fairly new to Vue and currently am working on the first project with it.
I have encountered this problem which I cannot seem to find a solution for, I have "AuthPage.vue" component which has a slot for the message and default slot for content, once I put custom componen in my login.blade.php it should be prefilled in that slot but it says that custom element does not exist. If I replace slot inside .vue file with custom element it seems to be working perfectly. I am not sure what I am doing wrong.
AuthPage.vue
<template>
<div>
<div class="page-brand-info"></div>
<div class="page-login-main">
<img class="brand-img" src="/assets/global/images/logo.jpg">
<h3 class="font-size-24 text-center"><slot name="title"></slot></h3>
<slot name="message"></slot>
<slot></slot>
<footer class="page-copyright">
<p>© {{ moment().year() }}. All RIGHT RESERVED.</p>
</footer>
</div>
</div>
</template>
<script>
import LoginForm from './LoginForm.vue';
import ResetPasswordForm from './ResetPasswordForm.vue';
export default {
components: { LoginForm, ResetPasswordForm }
}
</script>
login.blade.php
#extends('backoffice.layout.auth')
#section('content')
<auth-page>
<template v-slot:title>Sign In</template>
<login-form></login-form>
</auth-page>
#endsection
Thank you for your help!
Eddie

You'll need to register the LoginForm component globally in order for it to be passed into the AuthPage component as a slot (when passed in directly from a view). This is because, outside the scope of your component, Vue doesn't know what <login-form> is.
Since you're using laravel, in your resources/js/app.js file add the following:
import LoginForm from './path/to/LoginForm.vue';
Vue.component('login-form', LoginForm);

Related

2 way binding with Vue3 Inline template (using slots) in laravel blade template files

In Vue3, inline-templates were depreciated and now slots are used. Is it possible to have 2-way binding of variables for Vuejs components written in blade templates?
I want to have 2-way binding for Vue components that's written inline with blade templates. Although I know I can pass data like <example-component name="Hello World"> It is a ton of work to add props everywhere.
Vue recommends using slots as a inline-template replacement since it got removed in v3, however, that documentation makes no sense. I've got the components displayed using the code below. It's a dead simple text field + paragraph to display the name.
home.blade.php (Removed unnecessary HTML for brevity)
<div>
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
example-component.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
name: 'hi',
}
}
}
</script>
Unfortunately, this does not work, the name doesn't start as 'hi' and doesn't update when changing the textfield. When I try something like <slot :name=name></slot>. Which I believe would pass the name into the slots section, the component gets rendered for a second before disappearing.
Is having 2-way binding with vue variables in blade templates even possible? Any help is appreciated.
Vue: 3.0.5
Laravel: 8.29.0
Is there a reason you're storing the data in the child component? The reactivity design works by passing props down and emitting events up, even though (unfortunately) the reactivity is not maintained when passing a variable up to the parent component. Seems a little counter intuitive, but I might be missing something in what you're trying to create.
It will, however, work if you put the data into the app instead of the component.
// app
const app = Vue.createApp({
data() {
return {
name: 'hi',
}
}
})
// component
app.component('example-component', {
template: `
<div>
<slot></slot>
</div>`,
})
app.mount("#app");
<script src="https://unpkg.com/vue#3.0.5/dist/vue.global.prod.js"></script>
<div id="app">
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
<!--

Vuejs component not registering with laravel

I know this question is being asked several times, but I couldn't find any solution to my problem.
I have two vue components on my laravel project. The first one is the laravel default component called "ExampleComponent.vue" and the second one is my own new component called "multi.vue".
I use them in a section.blade.php file like below:
#extends('layouts.app')
#section('content')
<example-component></example-component>
<multi></multi>
#endsection
but only the "example-component" works and for the "multi" component, it gives me the following error:
Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
here is my app.js code:
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('multi', require('./components/multi.vue').default);
const app = new Vue({
el: '#app',
});
Here is my components codes:
ExampleComponent.vue:
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
And my multi.vue:
<template>
<div>
I am multi component!
</div>
</template>
<script>
export default {
mounted() {
console.log('multi mounted.')
}
}
</script>
<style>
</style>
And the route is:
Route::get('/section',function(){
return view('section');
});
For solving this problem, all you need to do is to run "run npm watch".
After running that command, it will recomplie your vue code whenever you make a change in your code and save it.
Keep it in a separate terminal, and run "php artisan serve" in another terminal.
From https://v2.vuejs.org/v2/style-guide/#Multi-word-component-names-essential:
Component names should always be multi-word, except for root App
components, and built-in components provided by Vue, such as
<transition> or <component>.
This prevents conflicts with existing and future HTML elements, since
all HTML elements are a single word.

Including laravel blade template with button click

I can not find a solution how to include blade template using button click.
For example lets say I have a main view:
<div id="HEREGOESMYTEMPLATES">
</div>
<div class="row">
<button onclick="addTemplate()">ADD TEMPLATE</button>
</div>
Then script, which should include template
<script type="app/js">
function addTemplate()
{
//Get template and include into div with id HEREGOESMYTEMPLATE
}
</script>
And then the template itself (lets say partial.blade.php):
<div>Include me to main blade file</div>
Is there any possible way by including it without creating every tag in JS and then appending to the div?
Thank you.
UPDATE.
As blade template is not supposed to do such work as it is rendered in backend, I used VueJS to this, which I believe is the best solution in this situation.

Nesting custom tags in Vue

I have a Laravel / Vue app that I'm building and I've run into a bit of a snag. I have been able to successfully create individual stand-alone components, however when I try to nest a stand-alone component into another component, only the nested component shows up. A bit of code:
CompanyLogo.vue
<template>
<figure class="company-logo" :style="{
width: size,
height: size,
backgroundImage: `url(${src})`
}"></figure>
</template>
LogoUploader.vue
<template>
<div class="logo-container">
<company-logo size="65px" :src="`${company.logo.url}`"></company-logo>
</div>
<div class="logo-uploaded-details">
<p>Last updated: {company.logo.last_updated}</p>
<button class="file-browse-btn">Upload Image</button>
</div>
</template>
What's happening is that when in company.blade.php I simply have
<logo-uploader></logo-uploader>
The app compiles and loads, however only the CompanyLogo shows up on the screen. The entire markup for the logo-uploaded-details section isn't rendered at all.
I have tried adding a require for the CompanyLogo component to the registration for the LogoUploader component, but that didn't work either.
If I split out the components they both show up. The issue is only once they're nested.
Any ideas?
Vue instances and components must have a single root element. In your LogoUploader you have two root elements.
You need to wrap them in a root.
<template>
<div>
<div class="logo-container">
<company-logo size="65px" :src="`${company.logo.url}`"></company-logo>
</div>
<div class="logo-uploaded-details">
<p>Last updated: {company.logo.last_updated}</p>
<button class="file-browse-btn">Upload Image</button>
</div>
</div>
</template>

Can't pass data from blade to vue (Laravel 5.3)

I'm trying to get Vue components working in Laravel 5.3 and I want to pass data from my blade template to a Vue component.
But I'm getting an error and none of the answers I've found so far have worked.
I'm using the example component that comes with the fresh install. In my blade template I have:
<example :testinfo="someinfo"></example>
In my Example.vue I have:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
{{testinfo}} I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['testinfo'],
mounted() {
console.log('Component ready.')
}
}
</script>
The Vue component does load, but it does not display the testinfo, and it generates this error message:
Property or method "someinfo" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option. (found in root instance)
referenced to your error ->
Property or method "someinfo" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in root instance)
it means that someinfo model is not declared from your vue parent. it should be wrapped in data { someinfo:null } and from there supply him data and pass it in your component example.
regarding passing with data from vue blade. you should called ajax from your vue method like
Vue new(){
data : { someinfo : null },
ready :function() / mounted() vue2
{
this.getSomeInfo();
}
methods : {
getSomeInfo : function(){
var self = this;
your ajax request here then
self .someinfo = (your ajax.response)
}
}
}
you need an sperate ajax call from controller to achieve to get your information from controller.
after ajax call success then time to put the response to your vue model then it will automatically pass to your components re actively because of two way binding.
The answer from Tony Fale wasn't exactly what I was looking for but it did give me a clue that helped me think of the answer.
In this code:
<example :testinfo="someinfo"></example>
I thought "someinfo" would just be treated as a string but Vue treats it as a JavaScript variable. Since someinfo isn't defined anywhere, it causes an error.
If instead I do:
<example :testinfo="{somekey: 'someinfo'}"></example>
and change Example.vue to:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
{{testinfo.somekey}} I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
It works as expected.

Resources