Button that shows modal for each b-table row - laravel

Im using laravel, vue, and bootstrap-vue.
I have created a vue component that displays a table of elements (subnets in this example).
For each of them I show a component (modal_edit-subnet) thats should open a modal that allows to edit the data of the element of the related row.
The problem is that it shows modals for all of the table elements. For example, if the table has 3 rows, it shows 3 modals (after closing one it shows the next). Each of the modals with the data of each of the rows.
I've tried to add "key"s but no success.
What am i doing wrong?
Thanks!
Component that shows the table
<template>
<div>
<b-card class="text-center">
<b-table small striped hover :items="data_subnets" :fields="fields" :tbody-tr-class="rowClass">
<template slot="[ip_address]" slot-scope="data_subnets">
<b>{{ long2ip(data_subnets.item.ip_address) }}</b>
</template>
<template slot="[actions]" slot-scope="data_subnets">
v-on:deleteSubnet="deleteSubnet"></modal_delete-subnet>
<modal_edit-subnet :key="'modal_edit_subnet' + data_subnets.item.id" :subnet="data_subnets.item" v-on:editSubnet="editSubnet"></modal_edit-subnet>
</template>
</b-table>
</b-card>
</div>
</template>
Modal modal_edit-subnet
<template>
<div>
<b-button size="sm" v-b-modal.modal-edit-subnet>Edit</b-button>
<b-modal
id="modal-edit-subnet"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>

The problem is that:
You're rendering a modal for each row of the table and;
Reading the docs, it seems like the modal is triggered by the id, and your b-modal id is not dynamic depending on the row.
How to fix it:
Use just one modal on the b-table level
Dynamically inject id into your modal_edit-subnet component:
<template>
<div>
<b-button size="sm" v-b-modal[id]>Edit</b-button>
<b-modal
:id="id"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>
<script>
export default {
props: {
id: {
type: String | Number
}
}
}
</script>
Use v-model (this is the way I would do it)
<template>
<div>
<b-button size="sm" #click="show = true">Edit</b-button>
<b-modal
v-model="show"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>
<script>
export default {
data() {
return {
show: false
}
}
}
</script>

Related

Vue.js 3 - Add list items from component dynamically

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:()=>[]},
}
}

Don't see a div into a vue component

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";
}
}

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>
..

How to pass data from one component to other in vue js?

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>

Select element within nested template in Polymer 1.0

Is there a way to select an element in a nested template? I have to access ajax within the dom-bind template so I can change the params or url.
<template>
<div class="listing" id="list">
<template is="dom-bind" id="tmp">
<iron-ajax id="bin" url="http://api.com/" last-response="{{data}}" handle-as="json" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div class="list">
<div class="pic">
<iron-icon icon="[[item.type]]" class="icon"></iron-icon>
<iron-icon class="action"></iron-icon>
</div>
<div class="cont horizontal layout">
<span class="name">[[item.name]]</span>
<span class="date">[[item.date]]</span>
<span class="time">[[item.time]]</span>
<span class="note">[[item.note]]</span>
</div>
<paper-ripple></paper-ripple>
</div>
</template>
</iron-list>
</template>
</div>
</template>
Here I have a property named filter. When filter changes it automatically fires _filterChanged. I am able to access the #tmp template but I am unable to access the iron-ajax within the #tmp template.
Polymer({
is: "event-log",
properties: {
filter: {
type: String,
value: "all",
observer: '_filterChanged'
}
},
_filterChanged: function() {
var ajax = this.$.tmp.getElementById("bin");
console.log(ajax); // Returns null
}
});

Resources