Laravel - Public directory outside project folder - Vue not working - laravel

I have searched everywhere, and all answers I found only explain how to rename the public folder. In my case, the public folder is outside the Project folder:
basefolder/
Laravel/
public_html/
I have done all changes I found for the renaming folder, and all works except for vue.
In the webpack file i entered this:
mix.setPublicPath('../public_html/');
mix.js('resources/js/app.js', 'js')
.sass('resources/sass/app.scss', 'css');
compiled, and it compiled the css and js file in the proper folder.
In my app.js i Declared this:
Vue.component('set-fav', require('./components/SetFavorite.vue').default);
and the file components/SetFavorite.vue exists and has its content...
<template>
<div>
<input type="image" src="/images/favorite.png" border="0" alt="Favorite" #click="setfavorite" />
</div>
</template>
<script>
export default {
props: ['photogId','galId','photoname'],
mounted() {
console.log('Component mounted.')
},
methods: {
setfavorite(){
axios.get('/' + this.photogId + '/' + this.galId + '/' + this.photoname + '/like')
.then(response => {
alert(response.data);
});
}
}
}
</script>
when i Load the page, i do not see the image. Instead in the developer console I see 2 error messages:
Uncaught SyntaxError: Cannot use import statement outside a module
and
app.js:38062 [Vue warn]: Unknown custom element: <set-fav> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in <Root>)
and if I look at the source of my page, it begins like this:
<script>
import SetFavorite from "../../js/components/SetFavorite";
export default {
components: {SetFavorite}
}
</script>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
...
...
Now, relative to my index.php file, the path ../../js/components/SetFavorite does not exist.. the correct existing path would be ../Laravel/js/components/SetFavorite
What do I need to do in order to fix this?
Thank you
EDIT, code of view
#extends('layouts.client')
#section('content')
<div class="container">
#if($gallery->webgal == 1)
<div class="row d-flex justify-content-around pb-3">
<h1>{{$gallery->galname}}</h1>
</div>
<div class=" row pt-1 card-deck">
#foreach($gallery->photos as $photo)
<div class="col-12 col-md-6 col-sm-12 p-1 " >
<div class="w-100 d-flex shadow justify-content-between card" style="background-color: lightgray">
<div class="w-100 m-0 p-0" style="width: 350px; height: 350px;">
<a data-fancybox="gallery" href="/images/{{auth()->user()->phcode}}/{{$gallery->galcode}}/wm/wm_{{$photo->filename}}">
<img class="card-img" src="/images/{{auth()->user()->phcode}}/{{$gallery->galcode}}/thumb/thumb_{{$photo->filename}}" style="
width:100%;
height:100%;
object-fit: scale-down;">
</a>
</div>
<div class="card-footer w-100 d-flex justify-content-around" style="font-size: smaller;">
<div class="d-flex justify-content-around w-100">
<div>
{{$photo->filename}}
</div>
<div>
<button>Download (Hi-Res)</button>
</div>
<div>
<button>Download (Social Res)</button>
</div>
<div>
<set-fav photogId="{{$gallery->user->phcode}}" galId="{{$gallery->galcode}}" photoId="{{$photo->filename}}" name="fav{{$photo->id}}"></set-fav>
</div>
</div>
</div>
</div>
</div>
#endforeach
</div>
#else
<div class="row d-flex justify-content-around pb-3">
<h1>Nothing here... :)</h1>
</div>
#endif
</div>
#endsection

You have 2 issues:
You should alias your components directory thanks to Webpack, by the way it will always use an absolute path
In your webpack.mix.js:
mix.webpackConfig({
resolve: {
extensions: [ '.js', '.vue' ],
alias : { '#': `${ __dirname }/resources` },
},
output: {
publicPath : '/',
chunkFilename: 'js/[name].[chunkhash].js',
},
});
import SetFavorite from '#/js/components/SetFavorite';
If the last sample is the source code of your HTML document, it doesn't work because import and export are unknown to a web browser. You have to do it from an asset, build it with Laravel Mix and include the output to your HTML thanks to
<script type="text/javascript" src="{{ mix(...) }}"></script>

Related

How to configure Croppie for vue 3 in laravel 8?

In a vue page I added a ImageUpload component, following this tutorial: https://www.youtube.com/watch?v=kvNozA8M1HM
It works more or less. No errors, but it only shows my image and a ruler. I can zoom using the ruler, but it does not show boundaries, circle etc. It is completely different from the example in the tutorial...
It is buggy, so to say.
<template>
<div class="Image-Upload-wrapper Image-upload">
<p>
This is image upload wrapper component
</p>
<div id="croppie"> </div>
</div>
</template>
<script>
// uitleg over Croppie::https://www.youtube.com/watch?v=kvNozA8M1HM
import Croppie from 'croppie';
export default {
props:[
'imgUrl'
],
mounted(){
this.image = this.imgUrl // als component is mounted, this.image definieren, en daartmee croppie in..
this.setUpCroppie()
},
data(){
return{
image:null,
croppie:null
}
},
methods:{
setUpCroppie(){
let el = document.getElementById('croppie');
this.croppie = new Croppie(el, {
viewport:{width:200,height:200,type:'circle'},
boundary:{ width:220,height:220},
showZoomer:true,
enableOrientation: true
});
this.croppie.bind({
url:this.image
});
}
}
}
</script>
Is placed in parent as follows:
template>
<div>
<h2>Cards 1</h2>
<div class="form-group">
<input type="text" class="form-control" :placeholder="card.title" v-model="card.title">
</div>
<div class="form-group">
<textarea class="form-control" :placeholder="card.description" v-model="card.description">
</textarea>
</div>
<div id="preview" v-if="url" >
<h4> Preview</h4>
<ImageUpload :imgUrl="url"></ImageUpload>
<!-- <img class="img-circle" style="width:150px" :src="url" /> -->
</div>
<input type="file" v-on:change="onFileChange" ref="fileUpload" id="file_picture_input">
<button #click="editCard(currentSpelerCard)" class="btn btn-warning m-1" style="width:100px;color:black"> Save Card </button>
</div>
</template>
In my package.json I have:
"croppie": "^2.6.5",
in webpack mix I have:
mix.js('resources/js/app.js', 'public/js')
mix.vue();
mix.sass('resources/sass/app.scss', 'public/css');
I have a feeling that something is wrong with the installation of croppie.
Does anyone know what could be the problem here?
Googloing on I found the remark:
"#Since this package also depends on croppie.css you have to import it in your app.js import 'croppie/croppie.css'"
I added the following line to bootstrap.js:
import 'croppie/croppie.css';

Why doesn't infinite-loading-vue3 work in a Laravel Project?

I am having a problem using this library in a Vue file. The project is being done with InertiaJS and Laravel.
The controller is composed of the following code:
public function getSaldosContables()
{
$saldocontables = SaldoContable::paginate(10);
return response()->json($saldocontables);
}
And the Vue file contains the following code:
<template>
<app-layout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">Listado</h2>
</template>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<div id="app" #scroll.passive="scrollear">
<infinite-scroll
#infinite-scroll="loadDataFromServer"
:message="message"
:noResult="noResult"
>
<div>
<div
v-for="repo in saldocontables"
:key="repo.idsaldocont"
style="margin-bottom: 20px"
>
<div>
<img :src="repo.idsaldocont" alt="" style="height: 50px" />
</div>
<div>{{ repo.nombresaldocont }}</div>
</div>
</div>
</infinite-scroll>
</div>
</div>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from "#/Layouts/AppLayout";
import InfiniteScroll from "infinite-loading-vue3";
import axios from "axios";
export default {
components: {
AppLayout,
InfiniteScroll,
},
data() {
return {
saldocontables: [],
page: 1,
noResult: false,
message: "",
};
},
methods: {
async loadDataFromServer() {
try {
const result = await axios.get("/obtenerSaldos?page=" + this.page);
if (result.data.data.length) {
console.log(this.page);
this.saldocontables.push(...result.data.data);
this.page++;
} else {
this.noResult = true;
this.message = "No result found";
}
} catch (err) {
this.noResult = true;
this.message = "Error loading data";
}
},
},
mounted() {
this.loadDataFromServer();
},
};
</script>
The Laravel route file handles the following encoding:
Route::get('/obtenerSaldos', [SaldoContableController::class, 'getSaldosContables']);
The data loaded in the database is rendered correctly. The problem is generated when the Infinite Scroll must load the following pages with the respective data. When it reaches the end of the page, it remains only loaded with the data of Page 1 and does not update the data contained in the following pages taking into account the pagination returned by the Backend.
This can be seen in the following image:
If I delete the following lines from my Vue:
<app-layout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">Listado</h2>
</template>
</app-layout>
The Template responds correctly and the Infinite Scroll also works perfectly.
You can see it in the following image:
The problem is that by doing this in the view the components that refer to the Side Menu, Top Menu, Responsive Menu, etc. do not appear.
I appreciate any help you can give me.

why component disappear when i change tab?

in my laravel project i have used Vuejs and Vuex.when page is loaded or refreshed then component is displayed but when i change tab and goto previous tab then component disappear.And when i goto next page and return back everything is fine.
below is component featured.vue
<template>
<div class="featured_slider slider">
<h4>featured</h4>
<div class="featured_slider_item" v-for="product in getFeaturedProducts">
<div class="border_active"></div>
<div class="product_item discount d-flex flex-column align-items-center
justify-content-center text-center">
<div class="product_image d-flex flex-column align-items-center justify-
content-center">
<img :src="'/Uploads/Products/'+product.id+'/cropped_'+product.image.name"
:alt="product.image.name"></div>
<div class="product_content">
<div class="product_price discount">Rs.{{product.price_old}}<span>Rs.
{{product.price_new}}</span></div>
<div class="product_name">
<div>{{product.title}}</div>`
</div>
<div class="product_extras">
<div class="product_color">
<input type="radio" checked
name="product_color"style="background:#b19c83">
<input type="radio" name="product_color"
style="background:#000000">
<input type="radio" name="product_color"
style="background:#999999">
</div>
<button class="product_cart_button">Add to Cart</button>
</div>
</div>
<div class="product_fav"><i class="fas fa-heart"></i></div>
<ul class="product_marks">
<li class="product_mark product_discount">-25%</li>
<li class="product_mark product_new">new</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
products:[]
}
},
computed:{
getFeaturedProducts(){
return this.$store.getters.featuredProducts;
}
},
created() {
return this.$store.dispatch('featuredProducts');
}
}
</script>
below is state.js
export default {
featuredProducts:[],
onSale:[]
}
below is getters.js
export const featuredProducts= state =>{
//console.log(state);
return state.featuredProducts
};
export const onSale= state =>{
//console.log(state);
return state.onSale
};
below is mutations.js
export const featuredProducts=(state,responseData)=>{
state.featuredProducts=responseData;
// console.log(responseData)
};
export const onSale=(state,responseData)=>{
state.onSale=responseData;
// console.log(responseData)
};
below is actions.js
import {sendGet} from "../../../utils/request";
export const featuredProducts =context=>{
sendGet('/product/products').then(response=>{
context.commit('featuredProducts',response.data.data)
});
};
export const onSale =context=>{
sendGet('/product/onsale').then(response=>{
context.commit('onSale',response.data.data)
});
};
Considering general file structure 'public>js>app.js', app.js
which include all compiled js, the vue dependencies and attach vue instance to to
the body of the page, your blade, eg index.blade.php you might have something like ::
<script type="text/javascript" src="js/app.js"></script>
In your blade template, change it into something like this, considering same file structure:
<script type="text/javascript" src="{{url('js')}}/app.js"></script>

Property or method is not defined on the instance but referenced during render - Vue

I have a Vue component using with Laravel app:
resources/assets/js/app.js:
Vue.component('auth-form', require('./components/AuthForm.vue'));
const app = new Vue({
el: '#app',
data: {
showModal: false
}
});
AuthForm.vue:
<template>
<div v-if="showModal">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" #click="showModal=false">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
modal body
</div>
</div>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "auth-form"
}
</script>
<style scoped>
...
</style>
I'm using component inside blade template:
<div id="app">
...
<button id="show-modal" #click="showModal = true">Auth</button>
...
<auth-form></auth-form>
</div>
And I'm getting error
Property or method "showModal" is not defined on the instance but referenced during render.
What's wrong with my component?
I used this JSFiddle as example.
The reason is you have defined showModel in the root component and AuthForm is a child of this.
change the script in AuthForm.vue to:
<script>
export default {
name: "auth-form",
data:function(){
return {
showModal: false
}
}
}
</script>
Or you could write a computed method to get the value from the parent component.
edit:
ahh ok i see what you require. you will need to use properties instead
blade template
<div id="app">
<button id="show-modal" #click="showModal = true">Auth</button>
<auth-form :show.sync="showModal"></auth-form>
</div>
script in AuthForm.vue
<script>
export default {
name: "auth-form",
props:['show'],
computed:{
showModal:{
get:function(){
return this.show;
},
set:function(newValue){
this.show = newValue;
}
}
}
}
</script>
showModal is a data item in the parent Vue, and not in the component. Since you want them to be the same thing, you should pass showModal to the child component as a prop. The click in the child component should emit an event that the parent handles (by changing the value).

Passing the Div id to another vue component in laravel

I created a simple real-time chat application using vue js in laravel.
I am having a problem with the automatic scroll of the div when there is a new data.
What I want is the div to automatically scroll down to the bottom of the div when there is a new data.
Here is my code so far.
Chat.vue file
<template>
<div class="panel-block">
<div class="chat" v-if="chats.length != 0" style="height: 400px;" id="myDiv">
<div v-for="chat in chats" style="overflow: auto;" >
<div class="chat-right" v-if="chat.user_id == userid">
{{ chat.chat }}
</div>
<div class="chat-left" v-else>
{{ chat.chat}}
</div>
</div>
</div>
<div v-else class="no-message">
<br><br><br><br><br>
There are no messages
</div>
<chat-composer v-bind:userid="userid" v-bind:chats="chats" v-bind:adminid="adminid"></chat-composer>
</div>
</template>
<script>
export default {
props: ['chats','userid','adminid'],
}
</script>
ChatComposer.vue file
<template>
<div class="panel-block field">
<div class="input-group">
<input type="text" class="form-control" v-on:keyup.enter="sendChat" v-model="chat">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" v-on:click="sendChat">Send Chat</button>
</span>
</div>
</div>
</template>
<script>
export default{
props: ['chats','userid','adminid'],
data() {
return{
chat: ''
}
},
methods: {
sendChat: function(e) {
if(this.chat != ''){
var data = {
chat: this.chat,
admin_id: this.adminid,
user_id: this.userid
}
this.chat = '';
axios.post('/chat/sendChat', data).then((response) => {
this.chats.push(data)
})
this.scrollToEnd();
}
},
scrollToEnd: function() {
var container = this.$el.querySelector("#myDiv");
container.scrollTop = container.scrollHeight;
}
}
}
</script>
I am passing a div id from the Chat.vue file to the ChatComposer.vue file.
As you can see in the ChatComposer.vue file there is a function called scrollToEnd where in it gets the height of the div id from Chat.vue file.
When the sendchat function is triggered i called the scrollToEnd function.
I guess hes not getting the value from the div id because I am getting an error - Cannot read property 'scrollHeight' of null.
Any help would be appreciated.
Thanks in advance.
the scope of this.$el.querySelector will be limited to only ChatComposer.vue hence child component can not able to access div of parent component #myDiv .
You can trigger event as below in ChatComposer
this.$emit('scroll');
In parent component write ScollToEnd method and use $ref to assign new height
<chat-composer v-bind:userid="userid" v-bind:chats="chats" v-bind:adminid="adminid" #scroll="ScollToEnd"></chat-composer>
..

Resources