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>
..
Related
I am new to vue, I found some examples but I could not reproduce in my situation.
I have some inputs user will fill out and once it clicks the button, the information will populate a list of items. I am trying to crete < li > with a OrderListItem component. But I am getting this error:
runtime-core.esm-bundler.js?5c40:217 Uncaught ReferenceError: machines is not defined
at eval (OrderListItem.vue?fb66:14)
Here is the form
<template>
<div>
<div class="flex flex-col mb-4 md:w-full m-1">
<label for="planter_model_id">Planter</label>
<select v-model="registration.planter_model_id" name="planter_model_id">
<option disabled selected>Planter</option>
<option v-for="planter in planters" :key="planter" :value="planter.id">{{planter.brand.name}} {{planter.name }}</option>
</select>
</div>
<div class="flex flex-col mb-4 md:w-full m-1">
<label class=" for="lines">Lines</label>
<Input v-model="registration.lines" type="number" name="lines" />
</div>
<Button type="button" #click="addItemOrder">Add</Button>
</div>
<div>
<ul>
<OrderListItem :machines="machines" />
</ul>
<div>
</template>
Here is my code
export default {
components: {
OrderListItem,
Button,
},
props: {
planters:{
type:Array,
required: true
},
},
data() {
return {
machines: [], //this what I wish to be passed to OrderListItem component
registration:{
lines:null,
planter_model_id:null,
},
}
},
methods:{
addItemOrder(){
let item = {}
item.planter_model_id = this.registration.planter_model_id
item.lines = this.registration.lines
this.machines.push(item)
}
}
};
And here is my OrderListItem component that I created on another file:
<template>
<li v-for="machine in machines" :key="machine">
<div class="flex-initial w-3/5">
<p>Planter: {{machine.planter_model_id}}</p>
<p>Lines: {{machine.lines}}</p>
</div>
</li>
</template>
<script>
export default {
name: 'OrderListItem',
props:{
machines,
}
}
</script>
I don’t know if it is relevant but I am using vue3 and laravel.
I am very newbie here and from what I learned I think if machines array was a prop I would be able to access it on my component. But I will dynamically add a and remove itens from machines array and I think props receive data from server so It should not be declared there, that why I declared inside data().
Thanks =)
You should define the prop by adding its type and default value :
export default {
name: 'OrderListItem',
props:{
machines:{type:Array,default:()=>[]},
}
}
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>
I have a vue component with a div and a button and into another div I have two components
<script>
export default {
name: 'excursion-backend-component',
methods:{
doRedirection: function () {
window.location = APP_URL+"/excursiones/create";
}
},
mounted() {
console.log(APP_URL+"/excursiones/create");
console.log("aaaa");
}
}
</script>
<template>
<div class="container">
<h3>Adicionar excursión</h3>
<div style="text-align: right">
<a class="btn btn-primary" :href="doRedirection"><i class="fa fa-plus"></i> Adicionar</a>
</div>
<br>
<div>
<excursion-list-component></excursion-list-component>
<excursion-add-component></excursion-add-component>
</div>
</div>
</template>
But I don't see the button on the navigator.
What is wrong?
Here is how I see the page
:href="" expecting string with url to navigation, but you using method.
Use #click instead :href, if you want to use method.
<a #click="doRedirect">... </a>
Or, may be, move it to computed block
computed: {
excursionesUrl () {
return APP_URL+"/excursiones/create";
}
}
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).
I am learning vue+laravel. I want to pass value from one component to other component? I have used vue router for routing.
Here is the code for first and second component.
SelectPerson.vue
<template>
......
<div>
<input type="number" class="form-control" name="numberOfPersons" placeholder="Enter number of persons here" **v-model="inputPersons"**>
<br>
**<SelectTimeSlot v-bind:numberOfPersons="inputPersons"></SelectTimeSlot>**
</div>
<div>
<button class="btn btn-default float-right mt-2" v-on:click="selectTimeSlots">Next</button>
</div>
......
</template>
<script>
import SelectTimeSlot from './SelectTimeSlot.vue'
export default{
props:['numberOfPersons'],
data(){
return{
**inputPersons:0**
}
},
methods:{
selectTimeSlots(){
this.$router.push({name:'SelectTimeSlot'});
}
}
}
</script>
second component
SelectTimeSlot.vue
<template>
<h5>Welcome, You have selected **{{numberOfPersons}}** persons.</h5>
</template>
Can anybody help me do it?
To pass data from one component to other component, you need to use props:
First component:
<second-component-name :selectedOption="selectedOption"></second-component-name>
<script>
export default {
components: {
'second-component-name': require('./secondComponent.vue'),
},
data() {
return {
selectedOption: ''
}
}
}
</script>
Second Component:
<template>
<div>
{{ selectedOption }}
</div>
</template>
<script>
export default {
props: ['selectedOption']
}
</script>
Please visit this link.
Hope this is helpful for you!
Say I have a page with this HTML.
<div class="select-all">
<input type="checkbox" name="all_select" id="all_select">
<label #click="checkchecker" for="all_select"></label>
</div>
the function checkchecker is called in my methods
checkchecker() {
this.checker = !this.checker
}
This will show or hide my div on that page like this
<div v-show="checker === true" class="select-all-holder">
<button>Select All</button>
</div>
Now if I also want to toggle another div which is inside my child
component on that page I will pass the value like this.
<div class="content-section clearfix">
<single-product :checkers="checker"></single-product> //This is calling my child component
</div>
Now in my Child component I will have a prop declared like this
checkers: {
type: String,
default: false,
},
This is how I will write my div in my child component
<div v-show="checkers === true" class="select-holder clearfix">
<input type="checkbox" class="unchecked" name="single_select" id="1">
</div>