I am doing delete and delete multiple function for the table, I used the following code but it doesn't seem to work when I click all.
template:
<tr
v-if="isAdmin == 1"
v-for="(file, index) in files"
:key="index"
>
<td class="px-4 py-3">
<div class="flex items-center text-sm">
<div
>
<input
type="checkbox"
v-model="selected"
:value="file._id"
number
/>
</div>
<div>
<p class="font-semibold">{{ file.name }}</p>
</div>
</div>
</td>
<td class="px-4 py-3 text-sm">{{ file.size }} KB</td>
</tr>
And here is the script:
<script setup lang="ts">
const selected = ref([]);
const selectAll = computed({
get() {
return files.value ? selected.value.length == files.value.length : false;
},
set(value) {
let objnull: any = [];
let selected = [];
if (value) {
files.value.forEach((file) => {
selected.push(file._id);
});
}
selected = objnull;
},
});
</script>
Hope there is some solution for me, and I want to get the selected ids to call the api, thanks for everyone's help
Related
I am attempting to pass user id's fetched from an API trough props from parent (App) to child (Modal). The problem is that when I pass the props down to the modal they don't render as they should in the div with the modal-body class, in fact all of them display an id of 1.
App.vue:
<template>
<div class="container mt-3">
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Username</th>
</tr>
</thead>
<tbody v-for="user in users" :key="user.id">
<tr>
<th scope="row">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>
<Modal :id="user.id" />
</td>
</tr>
</tbody>
</table>
</div>
<pre>{{ user }}</pre>
</template>
<script>
import axios from "axios";
import Modal from "#/components/Modal.vue";
export default {
name: "App",
components: {
Modal,
},
data() {
return {
users: null,
};
},
methods: {
async load_users() {
try {
const { data } = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
this.users = data;
} catch (error) {
console.log("error");
}
},
},
mounted() {
this.load_users();
},
};
</script>
Modal.vue:
<template>
<!-- Button trigger modal -->
<button
type="button"
class="btn btn-danger"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
>
Delete
</button>
<!-- Modal -->
<div
class="modal fade"
id="exampleModal"
tabindex="-1"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
Are you sure you want to delete user: {{ id }}
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["id"],
};
</script>
The page preview is the following:
It does not matter on which Delete button I click the id is always 1.
But when I inspect the props in the Vue Devtools they are different, for the second for example it appears 2 as it should:
Any help is appreciated.
Thank you.
You are rendering 10 modals each with the same id - exampleModal, so it's always the first one which is opened. This is why you are experiencing the behaviour you describe.
However - the real problem is with your structure.
Why are you rendering 10 modals? Why not render one and pass in the respective props?
Something like this:
<template>
<Modal v-if="modal.isActive" :id="modal.userId" />
<tbody v-for="user in users" :key="user.id">
<tr>
<th scope="row">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>
<button
type="button"
class="btn btn-danger"
#click="onClick(user.id)"
>
Delete
</button>
</td>
</tr>
</tbody>
</template>
<script>
import Modal from '#/components/Modal.vue'
export default {
name: 'App',
components: {
Modal,
},
data() {
return {
users: null,
modal: {
isActive: false,
userId: null,
},
}
},
methods: {
onClick(userId) {
Object.assign(this.modal, { isActive: true, userId })
},
},
}
</script>
I want to use the same component twice from a parent component; all that was stopping me was the use of an ID for a dropdown in the subcomponents! So I currently have duplicated the subcomponent.
My parent component:
<template>
<div id="compare-page">
<div class="row">
<div class="col-md-12">
<div class="row campaign-overview">
<div class="col-md-4">
<h2>{{ campaign.name }}</h2>
<strong>Published</strong>
<strong>Starts: {{ campaign.start_date }} - Ends: {{ campaign.end_date }}</strong>
</div>
<div class="col-md-4 text-right">
<select name="daterange" id="" #change="onChangeDaterange($event)">
<option v-for="(daterange, index) in dateranges" v-bind:key="daterange.index" :value="index" :data-start="daterange.start" :data-end="daterange.end" :selected="daterange.optionSelected == 1">{{ index }}</option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<left-device ref="leftDevice"></left-device>
</div>
<div class="col-md-6">
<right-device ref="rightDevice"></right-device>
</div>
</div>
</div>
</template>
<script>
import left from './compared_device_component_left.vue';
import right from './compared_device_component_right.vue';
export default {
components: {
'left-device': left,
'right-device': right,
},
mounted() {
this.fetchCampaignData().then(result => {
});
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
leftDevice: '',
rightDevice: ''
}
},
methods: {
fetchCampaignData() {
return this.$http.get('/api/portal/campaign/' + this.campaign_id + '/campaign?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
});
},
onChangeDaterange(event) {
this.$router.push('?range=' + event.target.value);
this.$refs.leftDevice.onChangeDaterange(event);
this.$refs.rightDevice.onChangeDaterange(event);
},
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
}
</script>
<style lang="scss">
</style>
One of my subcomponents
<template>
<div>
<div class="row device-overview">
<div class="col-md-4">
<select name="devices" id="deviceLeft" #change="onChangeDevice($event)">
<option v-for="(device, index) in devices" v-bind:key="device.index" :value="index" :data-device_id="device.device_id" :data-address="device.address" :selected="device.optionSelected == 1">{{ device.device_id }} | {{ device.address }}</option>
</select>
</div>
</div>
<div class="row totals">
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Total Interactions</h5>
<p class="card-text">{{ total_interactions }}</p>
</div>
</div>
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Average Interactions Per Day</h5>
<p class="card-text">{{ average_daily_interactions }}</p>
</div>
</div>
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Total Average Dwell Time</h5>
<p class="card-text">{{ average_dwell_time }}s</p>
</div>
</div>
</div>
<div class="row interactions">
<div class="col-md-12">
<h5>Total Interactions Per Product</h5>
<table class="table table-condensed table-hover">
<tbody>
<tr>
<td class="">Tag</td>
<td class="">Mapped Product</td>
<td class="">Lifts</td>
</tr>
<tr v-for="interaction in table_product_interactions">
<td class="">{{ interaction.tag }}</td>
<td class="">{{ interaction.mapping }}</td>
<td>{{ interaction.tag_count }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-12">
<h5>Total Interactions Per Day</h5>
<div class="chart" ref="chartdaily"></div>
</div>
</div>
<div class="row interactions">
<div class="col-md-8">
<h5>Total Interactions Per Hour</h5>
<div class="chart" ref="charthourly"></div>
</div>
</div>
</div>
</template>
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
this.fetchData(null).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
device: [],
devices: [],
total_interactions: '',
average_daily_interactions: '',
average_dwell_time: '',
interaction_type: '',
chart_daily_interactions: [],
chart_hourly_interactions: [],
table_product_interactions: []
}
},
methods: {
fetchData(deviceID) {
// Use JS to get by ID!
var device = document.getElementById("deviceLeft");
// ... call to API
},
chartTotalPerDay() {
// ...
},
chartTotalPerHour() {
// ...
},
onChangeDaterange(event) {
// Use JS to get by ID!
var device = document.getElementById("deviceLeft");
// st cookie
document.cookie = "deviceLeft="+device.value;
this.fetchData(device.value).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
},
onChangeDevice(event) {
// st cookie
document.cookie = "deviceLeft="+event.target.value;
this.fetchData(event.target.value).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
}
},
created() {
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
<style lang="scss">
.interactions {
h5 {
text-align: center;
}
}
.chart {
min-height: 550px;
}
</style>
I am currently using
var device = document.getElementById("deviceLeft");
...in my duplicated left/right subcomponents (this is 'left' and I also have 'right').
Should I use a 'ref' for my devices dropdown, so that each instance of the subcomponent is looking at the devices dropdown relative to that instance? Currently if I merge these into one the devices dropdown ID is the same for both instances and therefore I get incorrect ID in one of the instances!
Any helpful pointers would be much appreciated.
Thanks,
K...
I'm new to Vue.js and struggling to understand how to open a modal window on click.
Basically when I call the modal from another component I want to open the modal itself and show the data I'm passing to it from an API call. The problem is that that the modal still not shown with an inline "display:none". I'm going crazy why I cannot make it "display:block" even if I'm setting to true the prop I'm passing to the modal.
Can anyone look at the code and advise something? I'm out of resources :/
Modal component below:
<template>
<div id="modal" class="modal fade show" v-show="modalVisible" aria-labelledby="myModalLabel">
<div class="container">
<img :src="movieDetails.Poster" />
<div class="copy">
<p>
<span>Title:</span>
{{ movieDetails.Title }}
</p>
<p>
<span>Year:</span>
{{ movieDetails.Released }}
</p>
<p>
<span>Genre:</span>
{{ movieDetails.Genre }}
</p>
<p>
<span>Director:</span>
{{ movieDetails.Director }}
</p>
<p>
<span>Actors:</span>
{{ movieDetails.Actors }}
</p>
<p>
<span>Plot:</span>
{{ movieDetails.Plot }}
</p>
<p>
<span>IMDB Rating:</span>
{{ movieDetails.imdbRating }}
</p>
</div>
<button class="btn btn-light" #click="$emit('close')">Close</button>
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["movieDetails", "modalVisible"]
};
</script>
Component I'm calling the modal from:
<template>
<div class="container">
<h3>Movies database</h3>
<div class="input-group w-50 mx-auto">
<input
class="form-control"
id="input-search"
type="text"
v-model="textSearch"
placeholder="Search movie by title"
/>
<span class="input-group-btn">
<button type="button" class="btn btn-primary" v-on:click="searchMovie">Go!</button>
</span>
</div>
<div class="list-results" v-if="resultsFeed && resultsFeed.length">
<table class="table table-hover text-left">
<thead class="thead-light">
<tr>
<th scope="col">Title</th>
<th scope="col">Year</th>
<th scope="col">Poster</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="result in resultsFeed" v-bind:key="result.imdbID" :data-id="result.imdbID">
<td>{{ result.Title }}</td>
<td>{{ result.Year }}</td>
<td>
<img alt="movie poster" :src="result.Poster" />
</td>
<td class="text-right">
<button class="btn btn-secondary" #click="moreMovieInfo(result)">Show info</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="list-message" v-else>No results!</div>
<modal v-if="modalVisible" #close="modalVisible = false" :movieDetails="extraInfoFeed" />
</div>
</template>
<script>
import axios from "axios";
import modal from "./Modal.vue";
export default {
name: "Search",
components: {
modal
},
data() {
return {
resultsFeed: [],
extraInfoFeed: [],
textSearch: "",
modalVisible: false,
modalData: null
};
},
methods: {
searchMovie() {
var that = this;
axios
.get(
`https://www.omdbapi.com/?s=${encodeURIComponent(
this.textSearch
)}&apikey=a56adf1b`
)
.then(function(response) {
that.resultsFeed = response.data.Search;
})
.catch(function(error) {
console.log(error);
});
},
moreMovieInfo: function(result) {
var that = this;
axios
.get(
`https://www.omdbapi.com/?i=${encodeURIComponent(
result.imdbID
)}&apikey=a56adf1b`
)
.then(function(response) {
that.extraInfoFeed = response.data;
that.modalVisible = true;
// document.getElementById("modal").style.display = "block";
})
.catch(function(error) {
console.log(error);
});
// this.modalData = result;
}
}
};
</script>
<modal v-if="modalVisible" #close="modalVisible = false" :movieDetails="extraInfoFeed" />
So you are using v-if here and your Model component is expecting modalVisible as a prop to work. So, even when modalVisible is true, v-if will allow Modal component to be created, but its internal v-show will hide it as its modalVisible prop is null.
This should work:
<modal :modal-visible="modalVisible" #close="modalVisible = false" :movieDetails="extraInfoFeed" />
I try to enable/disable each input from a loop. The problem is that my method it works just after refresh. After I modify something in code and save, then the input works.
<tr v-for="(item, index) in customer_names" :key="item.id">
<td>
<input :disabled="!item.disabled"
v-model="item.name"
type="text"
</td>
</tr>
<div class="edit_mode"
:class="{'display-none':!item.disabled}">
<i class="fa fa-save" #click="disableInput(index)" aria-hidden="true"></i>
</div>
<div class="edit_mode"
:class="{'display-none':item.disabled}">
<i class="fa fa-edit" #click="enableInput(index)" aria-hidden="true"></i>
</div>
props:['customer_names'],
data(){
return{
disabled: [],
}
}
enableInput(index){
console.log('enableInput',this.customer_names[index].disabled);
this.customer_names[index].disabled = false;
},
disableInput(index){
console.log('disabeInput',this.customer_names[index].disabled);
this.customer_names[index].disabled = true;
}
I didn't fully understand your problem. I deduced that you might want to enable or disable the text fields that you create from the data provided. If this is still not what you meant, correct your question by pasting more source code, and explain your problem in more detail.
Vue.component("custom", {
template: "#custom-template",
props: ["customer_names"],
methods: {
enableInput(item) {
item.disabled = false;
},
disableInput(item) {
item.disabled = true;
},
toggleInput(item) {
item.disabled = !item.disabled;
}
}
});
new Vue({
data() {
return {
items: [
{ name: "fus", disabled: false },
{ name: "ro", disabled: false },
{ name: "dah", disabled: true }
]
};
}
}).$mount("#app");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<custom :customer_names="items" />
</div>
<script type="text/x-template" id="custom-template">
<table cellpadding=5>
<tr>
<th>Input</th>
<th>Version 1</th>
<th>Version 2</th>
</tr>
<tr v-for="item in customer_names" :key="item.id">
<td>
<input :disabled="item.disabled" v-model="item.name" type="text" />
</td>
<td>
<button #click="item.disabled = false">E</button>
<button #click="item.disabled = true">D</button>
<button #click="item.disabled = !item.disabled">T</button>
</td>
<td>
<button #click="enableInput(item)">E</button>
<button #click="disableInput(item)">D</button>
<button #click="toggleInput(item)">T</button>
</td>
</tr>
</table>
</script>
I have one component
<template>
<div class="section">
<a v-if='type == "events"' class="button is-primary" #click="showForm()">
<i class="fa fa-calendar"></i>  <span class="card-stats-key"> Add Event</span>
</a>
<a v-if='type == "places"' class="button is-primary" #click="showForm()">
<i class="fa fa-location-arrow"></i>  <span class="card-stats-key"> Add Place</span>
</a>
<table class="table" v-if="!add">
<thead>
<tr>
<th>
<abbr title="Position"># Client Number</abbr>
</th>
<th>Title</th>
<th>
<abbr title="Played">Status</abbr>
</th>
<th>
<abbr title="Played">View</abbr>
</th>
</tr>
</thead>
<tbody>
<tr v-for="event in events">
<th>{{event.client_number}}</th>
<td v-if='type == "events" '>{{event.title}}</td>
<td v-if='type == "places" '>{{event.name}}</td>
<td>
<p class="is-danger">Waiting</p>
</td>
<td> View </td>
</tr>
</tbody>
</table>
<add v-if="add" v-on:hideAdd="hideFrom()"></add>
</div>
</template>
<script>
import Add from '../forms/AddPlace.vue'
export default {
name: 'Tabbox',
data() {
return {
events: [],
add: ''
}
},
props: ['type'],
created() {
let jwt = localStorage.getItem('id_token')
var ref = wilddog.sync().ref('users').child(jwt).child(this.type);
ref.once("value")
.then((snapshot) => {
this.events = snapshot.val();
}).catch((err) => {
console.error(err);
})
},
methods: {
showForm(add) {
if (this.add == true)
this.add = false;
else {
this.add = true;
}
},
hideFrom() {
this.add = false
console.log('This add is false');
}
},
components: {
Add
}
}
</script>
and another component
<template>
<div class="field is-horizontal">
<div class="field-label">
<!-- Left empty for spacing -->
</div>
<div class="field-body">
<div class="field">
<div class="control">
<button class="button is-primary" v-bind:class="{ 'is-loading': loading } " #click="addPlace()">
Add place
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
add: false
}
},
methods: {
addPlace() {
this.$emit('hideAdd', this.add)
},
},
}
</script>
How i can calling method from showForm() from first first component in second one! I'm trying to that with $emit function, it doesn't work. And trying with $broadcast, same. How i can use event there?
Add a ref attribute to the child component in the parent component's template like this:
<add v-if="add" v-on:hideAdd="hideFrom()" ref="add-component"></add>
Now your parent component will have access to the child component's VueComponent instance and methods, which you can access like this:
methods: {
showForm() {
this.$refs['add-component'].addPlace();
}
}
Here's documentation on refs.