VueDraggable send request to DB while drag and drop - javascript

I need a help for vuedraggable component. I have three columns. (Photo inserted) I want to drag BoardUserCard between columns and want to send PUT request to database for changing "lead_status_id" related to column dropped. How can I achieve this ? I can not find any example about apis in documentation.
<template>
<div class="board">
<div class="boards">
<div class="boards-cards leads">
<div class="board-card-header ">
<h3>
Leads
</h3>
<span>
{{ allLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="allLeads"
class="board-card-body"
:options = "{group:allLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in allLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
<div class="boards-cards contacted">
<div class="board-card-header ">
<h3>
Contacted
</h3>
<span>
{{ contactedLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="contactedLeads"
class="board-card-body"
:options = "{group:contactedLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in contactedLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
<div class="boards-cards converted">
<div class="board-card-header ">
<h3>
Converted
</h3>
<span>
{{ convertedLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="convertedLeads"
class="board-card-body"
:options = "{group:convertedLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in convertedLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
</div>
</div>
</template>
<script>
import BoardUserCard from "#/components/BoardUserCard.vue";
import draggable from "vuedraggable";
export default {
name: "Dashboard",
components: {
BoardUserCard,
draggable,
},
data() {
return {
showModal: false,
allLeads: [
{
name: "Richard",
email: "Richard#gmail.com",
img: "avatar-small.svg",
status: "all"
},
{ name: "Rachael", email: "Rachael#gmail.com", img: "leads.svg", status: "all" },
{ name: "Matt", email: "Matt#gmail.com", img: "user-avatar.svg",status: "all" },
{ name: "Brad", email: "Brad#gmail.com", img: "leads.svg", status: "all"},
],
contactedLeads: [
{
name: "Jeniffer",
email: "Jeniffer#gmail.com",
img: "avatar-small.svg",
status: "contacted"
},
],
convertedLeads: [
{ name: "Mike", email: "Mike#gmail.com", img: "leads.svg", status: "converted" },
],
};
},
methods: {
openModal() {
this.showModal = true;
},
closeModal() {
this.showModal = false;
},
handleChange(event){
console.log(event)
}
},
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

All I need to add data attribute in component data-id="4"
<draggable
ghost-class="ghost"
:list="convertedLeads"
class="board-card-body"
:options = "{group:convertedLeads}"
group="leads"
#end="handleChange"
data-id="4"
>
And access data-id attribute in handleChange function
handleChange(event){
console.log(event.from.getAttribute("data-id"))
console.log(event.to.getAttribute("data-id"))
}
`

Related

How to filter checkbox by query api in vuejs?

I'm making a website that has a filter function before pouring data out... Currently, I'm doing the pretty stupid way of dumping all the data out and putting it in an object and then filtering. I want when I click on it, it will call the api to return according to the params that I pass, but the initial default is that the checkbox is in the all box, it still returns all. Here is my code part....
Template:
<template>
<div class="job">
<div class="container recruit flex-wrap">
<div class="job-filter">
<h3>
Ngành nghề
<img
id="icon-filter"
#click="showfilter"
:style="{ display: display.btn_show_filter }"
src="../assets/recruit/angle-down-svgrepo-com.svg"
alt=""
/>
<img
id="icon-close-filter"
:style="{ display: display.btn_close_filter }"
#click="closefilter"
src="../assets/recruit/close-svgrepo-com.svg"
alt=""
/>
</h3>
//Handle Filter
<div
class="radio-group"
id="group-filter"
:style="{ display: display.group_filter }"
>
<div
class="radio-check"
v-for="(check, index) in checks"
#click="selectFilter(check)"
:key="index"
>
<input
type="radio"
:id="index"
name="fav_language"
:value="check"
v-model="selected"
/>
<label :for="check">{{ check }}</label
><br />
</div>
</div>
</div>
//End Handle filter
<div class="search">
<div class="search-top flex-wrap">
<h5>{{ totalJobs }} {{ localised("countRecruit") }}</h5>
<div class="search-input">
<input
type="search"
placeholder="Nhập tên vị trí công việc"
v-model="search"
/>
<button #click="searchJob">
<img src="../assets/recruit/search.svg" alt="" />
</button>
</div>
</div>
<div
id="jobs"
class="job-item"
v-for="(item, index) in jobs"
:key="index"
:per-page="perPage"
:current-page="currentPage"
>
<router-link
tag="a"
:to="{ name: 'Detail', params: { id: item.id } }"
>
<h3 class="mleft-27">{{ item.Name }}</h3>
</router-link>
<div class="job-info flex-wrap">
<div class="job-info-left pleft-27 flex-wrap">
<div>
<img src="../assets/recruit/years.svg" alt="" />
<b>{{ item.Exprerience }}</b>
</div>
<div>
<img src="../assets/recruit/luong.svg" alt="" />
<b>{{ item.Salary }}</b>
</div>
<div>
<img src="../assets/recruit/diadiem.svg" alt="" />
<b>{{ item.Headequarters }}</b>
</div>
</div>
<div>
<h6>{{ momentTime(item.updatedAt) }}</h6>
</div>
</div>
<div class="info-job flex-wrap">
<div class="list-info-job">
<li>{{ item.Content }}</li>
</div>
<router-link
tag="a"
:to="{ name: 'Detail', params: { id: item.id } }"
>
<button class="btn-detail">Xem chi tiết</button>
</router-link>
</div>
</div>
<h3 class="not-found" v-show="showNoData">Not Found</h3>
</div>
</div>
</div>
</template>
And here is the js logic I'm dealing with:
<script>
import "../assets/style.css";
import "../assets/job.css";
import job from "../locales/lang";
import request from "#/utils/request";
import moment from "moment";
export default {
name: "jobs",
components: {},
data() {
return {
totalJobs: null,
tickTime: "",
currentPage: 1,
showPag: true,
showNoData: false,
perPage: 4,
search: "",
page: "",
noData: [],
checks: [
"All",
"Developer",
"Tester",
"Designer",
"Support",
"Marketing",
"Other",
],
jobinfos: [],
showJobs: [],
selected: "All",
};
},
computed: {
},
watch: {
// selected(newVal) {
// if (newVal === "All") {
// return this.jobinfos;
// } else {
// return this.jobinfos.filter((i) => i.Genres === newVal);
// }
// },
},
async mounted() {
//API
this.getJobs();
// event enter
var self = this;
window.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
self.searchJob();
}
});
},
methods: {
//Call api job information by locale
async getJobs() {
await request
.get(`jobs?_locale=${this.$route.params.locale}`)
.then((response) => {
this.jobinfos = response.data;
this.showJobs = response.data;
this.totalJobs = response.data.length;
})
.catch((e) => {});
},
//Filter item jobs
selectFilter(item) {
this.selected = item;
if (this.selected == "All") {
this.showJobs = this.jobinfos;
} else {
this.showJobs = this.jobinfos.filter((i) => i.Genres === this.selected);
if (this.showJobs.length > 0) {
this.showPag = true;
this.showNoData = false;
} else {
this.showPag = false;
this.showNoData = true;
}
}
},
// method search by filter
},
};
</script>
As for the backend, I'm using 3rd party cms, it probably already provides enough query params for me, please give me some pseudocode or a way so that when I click on the checkbox, it will call the api to return the records according to the check box ^^ thanks

Validate fields Steps Buefy and block next button until completing required

Hello I have a request in vue.js where b-input is required, if not it cannot continue, I've tried
required
validation-message="name required"
in b-step-item, also in the watch event.
watch: {
activeStep(step) {
this.ValidationSteps()
},
},
methods: {
ValidationSteps() {
this.erros = []
if (this.nameField === '') {
this.erros.push({ description: 'Field is required' })
}
},
},
but I still can't get the field to continue.
This is my code, then I'll fix how the error messages appear below the field. (if it is possible to give the solution).
I've searched and I can't find the solution in the documentation
<template>
<section>
<b-steps v-model="activeStep" :has-navigation="false">
<b-step-item step="1" label="Account" :clickable="isStepsClickable">
<h1 class="title has-text-centered">Account</h1>
<b-input
v-model="NombreCampo"
placeholder="Enter field name"
required
validation-message="name required"
></b-input>
<article v-if="erros.length > 0" class="message is-danger">
<div class="message-header">
<p>Error ({{ erros.length }})</p>
</div>
<div class="message-body">
<div class="content">
<ul>
<li v-for="(db, index) in erros" :key="index">
{{ db.description }}
</li>
</ul>
</div>
</div>
</article>
</b-step-item>
<b-step-item
step="2"
label="Profile"
:clickable="true"
:type="{ 'is-success': true }"
>
<h1 class="title has-text-centered">Profile</h1>
</b-step-item>
<template #navigation="{ previous, next }">
<b-button
:disabled="previous.disabled"
#click.prevent="previous.action"
>
Previous
</b-button>
<b-button :disabled="next.disabled" #click.prevent="next.action">
Next
</b-button>
</template>
</b-steps>
</section>
</template>
<script>
export default {
data() {
return {
activeStep: 0,
erros: [],
nameField: '',
}
},
watch: {
activeStep(step) {
this.ValidationSteps()
},
},
methods: {
ValidationSteps() {
this.erros = []
if (this.nameField === '') {
this.erros.push({ description: 'Field is required' })
}
},
},
}
</script>
Any suggestion or solution would be appreciated.

How to make a clone of the array object with new id and same name?

I'm new at vue3 and javascript. I have 2 lists and drag and drop system. The problem is when I drag and drop component from one list to another, I increase an id by 1, but I can't get the name of dragged object and display it. The problem displayed at methods in method "cloneComponent"
<template>
<div class="full-zone">
<div class="components">
<h3>Компоненты бота:</h3>
<draggable
class="dragArea"
:list="list1"
:group="{ name: 'people', pull: 'clone', put: false }"
:clone="cloneComponent"
#change="log"
item-key="id"
>
<template #item="{element}">
<div class="list-group-item">
{{ element.name }}
</div>
</template>
</draggable>
</div>
<div class="constructor">
<h3>Конструктор</h3>
<draggable
class="constructor-list"
:list="list2"
group="people"
#change="log"
item-key="id"
>
<template #item="{ element, index }">
<div class="list-group-item">
{{ element.name }}
<div>
<input type="text" class="input" v-model="element.text" placeholder="Введите текст компонента" />
<span #click="remove(index)" class="remove">x</span>
</div>
</div>
</template>
</draggable>
</div>
<div>
<button class="btn">Сгенерировать бота</button>
</div>
<rawDisplayer class="col-3" :value="list1" title="List 1" />
<rawDisplayer class="col-3" :value="list2" title="List 2" />
</div>
</template>
<script>
import draggable from "vuedraggable";
let idGlobal = 4;
export default {
name: "clone",
display: "Clone",
order: 2,
components: {
draggable
},
data() {
return {
list1: [
{ name: "Сообщение", text: "", id: 1 },
{ name: "Заметка", text: "", id: 2 },
{ name: "Кнопка", text: "", id: 3 },
],
list2: []
};
},
methods: {
log: function(evt) {
window.console.log(evt);
},
cloneComponent() {
return {
id: idGlobal ++,
}
},
remove(idx) {
this.list2.splice(idx, 1);
},
}
};
</script>
How to return not only "id", but "name" at the same time? Please help.
You need to send the item to the other list
// tolist = can be 1 or 2
cloneComponent(item, tolist) {
if (tolist === 2) {
this.list2.push(item)
} else {
this.list1.push(item)
}
}

Vue JS - How to cancel active class on button click

I have a list of people when clicking on them is marked with a red border, I also have two buttons, I want to make it so that when one of these buttons is pressed, the red border disappears, that is, cancel the active class, since when one of these people is clicked, it is activated a class named selectAvatarBorder
You can also see the given code in codesandbox
<template>
<div>
<div class="avatars-mob-container">
<div class="avatars-container">
<div class="av-row">
<div
v-for="(chunk, index) in Math.ceil(usersGroup.length / 2)"
:key="index"
>
<div
v-for="(user, index) in usersGroup.slice(
(chunk - 1) * 2,
chunk * 2
)"
:key="index"
class="avatar-columns"
:class="{ selectAvatarBorder: selectedUsers === user.id }"
#click="setUserBorderColor(user.id)"
>
<div>
<img width="100" height="100" :src="user.img" alt="avatar" />
</div>
<div>
<p class="avatar-name">{{ user.name }} {{ index }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="users-btn-group">
<div style="margin-right: 10px">
<button
:class="{
firstBtnMobUsersColor: state === 1,
secondBtnMobUsersColor: state === 2,
}"
#click="setState(1)"
>
Other
</button>
</div>
<div>
<button
:class="{
firstBtnMobUsersColor: state === 2,
secondBtnMobUsersColor: state === 1,
}"
#click="setState(2)"
>
Open to All
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
setState(s) {
this.state = s;
},
setUserBorderColor(s) {
this.selectedUsers = s;
},
},
data() {
return {
state: 0,
selectedUsers: 0,
usersGroup: [
{
id: 1,
name: "American Indian",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/1.png",
},
{
id: 2,
name: "Black/African Descent",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/2.png",
},
{
id: 3,
name: "Hispanic/Latino",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/3.png",
},
{
id: 4,
name: "White Caucasian",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/4.png",
},
],
};
},
};
</script>
<style scoped>
.selectAvatarBorder {
border: 2px solid #CC003D !important;
border-radius: 16px;
}
.firstBtnMobUsersColor {
background: #CC003D !important;
color: white !important;
}
.secondBtnMobUsersColor {
background: white !important;
color: red !important;
}
</style>
Something like this?
<template>
<div>
<div class="avatars-mob-container">
<div class="avatars-container">
<div class="av-row">
<div
v-for="(chunk, index) in Math.ceil(usersGroup.length / 2)"
:key="index"
>
<div
v-for="(user, index) in usersGroup.slice(
(chunk - 1) * 2,
chunk * 2
)"
:key="index"
class="avatar-columns"
:class="{ selectAvatarBorder: selectedUsers === user.id && isSelected }"
#click="setUserBorderColor(user.id)"
>
<div>
<img width="100" height="100" :src="user.img" alt="avatar" />
</div>
<div>
<p class="avatar-name">{{ user.name }} {{ index }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="users-btn-group">
<div style="margin-right: 10px">
<button
:class="{
firstBtnMobUsersColor: state === 1,
secondBtnMobUsersColor: state === 2,
}"
#click="setState(1)"
>
Other
</button>
</div>
<div>
<button
:class="{
firstBtnMobUsersColor: state === 2,
secondBtnMobUsersColor: state === 1,
}"
#click="setState(2)"
>
Open to All
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
setState(s) {
this.state = s;
this.isSelected = false;
},
setUserBorderColor(s) {
this.selectedUsers = s;
this.isSelected = true;
},
},
data() {
return {
state: 0,
selectedUsers: 0,
isSelected: false,
usersGroup: [
{
id: 1,
name: "American Indian",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/1.png",
},
{
id: 2,
name: "Black/African Descent",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/2.png",
},
{
id: 3,
name: "Hispanic/Latino",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/3.png",
},
{
id: 4,
name: "White Caucasian",
img:
"http://astragem.com/static/images/ClickSearchComponent/users/4.png",
},
],
};
},
};
</script>
As when you are clicking on image you are setting an index in the selectedUsers, so just add this.selectedUsers = 0; in the setState function.

Vue Dynamic List

I'm creating a basic MTG Deckbuilder using Vue.Js. I'm trying to have the user type the card name into an input box then when the button is clicked, the deck list is update with the card name. Currently,the list add's a blank element for the card instead of the card name. Any ideas?
app.Vue:
<template>
<div id="app">
<deckBuilder #addCard="addCard" :title="title" :card="card" :deck="deck" />
</div>
</template>
<script>
import deckBuilder from './components/deckBuilder'
export default {
name: 'app',
components: {
deckBuilder,
},
data: () => ({
title: 'MTG Deck Builder',
card: {
name: '',
},
deck:[],
}),
methods: {
addCard: function(event,) {
this.deck.push(this.card.name);
},
},
}
</script>
deckBuilder.Vue:
<template>
<div>
<h1>{{ title }}</h1>
<input v-model="card.name" placeholder="Type a Card Name" />
<p> the card is: {{ card.name }}
<button #click="addCard">Add!</button>
<h2>Deck</h2>
<ul>
<li v-for="item in deck">{{ item.card }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'deckBuilder',
props: ['title', 'card', 'deck'],
methods: {
addCard() {
this.$emit('addCard')
}
},
}
</script>
Because you push string item instead of object
this.deck.push(this.card.name);
Correct template will be {{ item }}, not {{ item.card }}
This is because you are not emitting any data in your $emit
Try this,
In deckbuilder.vue
addCard() {
this.$emit('addCard',this.card.name);
}
In app.vue
addCard: function(cardName){
this.deck.push(cardName);
}
In html, v-for should be this way
<li v-for="item in deck">{{ item }}</li>
Try This
<!-- Menu Content -->
<ul class="nav-list" style="overflow: visible;">
<!-- Items -->
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<nuxt-link :to="menuItem.link" :class="menuItem.class">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<!-- Link Name -->
<span class="links_name">{{ menuItem.name }}</span>
</nuxt-link>
</li>
</span>
</ul>
<script>
export default {
name: 'SidebarMenu',
menuItems: {
type: Array,
default: () => [
{
link: '/',
name: '_home',
icon: 'bx-home',
class: '',
},
{
link: '/blog',
name: '_blog',
icon: 'bx-edit',
class: '',
},
{
link: '/projects',
name: '_projects',
icon: 'bx-code',
class: ''
},
{
link: '/about',
name: '_about',
icon: 'bx-user',
class: ''
},
],
},
}
</script>

Categories

Resources