Show bootstrap modal using vuejs script - vuejs2

I want to show a modal based on conditions. Item array contains items with or without variants.If no variants i have push item to cart array directly.Otherwise i will show pop up to select variants. I have tried with below code .but not working .
<template>
<div>
<div class="row">
<div
class="col-6"
v-for="(item, index) in filteredItem"
:key="index"
style="margin-top: 10px; margin-bottom: 10px"
#click="add_cart(item)"
>
<label class="p-3 rounded border border-gray-300">
<span class="ml-2 text-gray-800">
<strong class="text-black-600"
>{{ item.name }}</strong
>
<i class="text-success my-0"> (£ {{ item.price }}) </i>
</span>
</label>
</div>
</div>
<div
class="modal fade center"
id="exampleModal"
tabindex="-1"
role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
:data-show="modal"
>
//modal body
</div>
</template>
//script
data() {
return {
modal:false
}
}
methods:{
add_cart(item) {
if (item.item_type == "simple") {
let cartItem = {
item_id: item.id,
item_name: item.name,
item_price: item.price,
quantity: 1,
};
this.cartItems.push(cartItem);
} else {
//toggle modal for select item variants
this.modal = true;
}
}

Related

Display the child array based on the id of the parent array vue?

I have an array of folders and an array of groups belonging to folders. I'm using v-for to show groups that belong to folders like this but how can I make them display correctly according to the folder they belong to. I have the folder_id property in each objects groups and I think I need to compare it to folder.id but I have no idea where I should put it in. This is the picture of my problem. It should have 1 group inside each folders. Please help
<div
v-for="(folder, index) in list_folders"
:key="folder.id"
class="d-block mb-11"
>
<div class="d-flex align-items-center mb-5">
<i class="fas fa-folder me-3 fs-30 text-primary"></i>
<span
#click="showModalEditFolder(index)"
class="text-primary fs-15 cursor-pointer"
>{{ folder.name }}</span
>
</div>
<div class="d-block">
<ul class="list-unstyled m-0">
<li
v-for="group in list_groups"
:key="group.id"
class="d-flex align-items-center mb-3"
>
<input
class="form-check-input w--4 h--4 rounded-0 m-0 me-6"
type="checkbox"
:value="group.id"
:id="group.id"
/>
<div class="w--11 h--11 me-3">
<img
:src="group.avatar"
alt="group-avatar"
class="img-cover w-100"
/>
</div>
<label :for="group.id" class="form-check-label">
{{ group.name }}
</label>
<div class="ms-auto">
<input
type="checkbox"
class="btn-check"
:id="`notify${group.id}`"
v-model="group.notify_option"
:true-value="1"
:false-value="0"
/>
<label
class="fs-15 text-primary cursor-pointer"
:for="`notify${group.id}`"
>{{
group.notify_option === 1
? $t('common.select.notify')
: $t('common.select.no_notify')
}}</label
>
</div>
</li>
</ul>
</div>
</div>
getFolders() {
let data: any[] = [
{
id: 100,
name: '店舗',
order_position: 1
},
{
id: 101,
name: '東日本統括部',
order_position: 2
}
]
this.list_folders = data
}
getGroupsOfUser() {
let data: any[] = [
{
id: 200,
folder_id: 100,
avatar: require('#/assets/images/group-avatar2.png'),
order_position: 1,
name: '仙台営業所',
notify_option: 0
},
{
id: 201,
folder_id: 101,
avatar: require('#/assets/images/group-avatar3.png'),
order_position: 2,
name: '東日本統括部',
notify_option: 1
}
]
this.list_groups = data
}
Solution 1
Simply add a v-if in
<li
v-for="group in list_groups"
:key="group.id"
class="d-flex align-items-center mb-3"
>
<template v-if="group.folder_id === folder.id">
// li content
<template>
</li>
Solution 2
Add a computed property to get the filtered list
<li
v-for="group in list_groups"
:key="group.id"
class="d-flex align-items-center mb-3"
>
<template v-if="group.folder_id === folder.id">
// li content
<template>
</li> <li
v-for="group in getListGroups(folder.id)"
:key="group.id"
class="d-flex align-items-center mb-3"
>
// li code
</li>
computed: {
getListGroups(folderId) {
return this.list_groups.filter(x => x.folder_id === folderId)
}
}

how can i pass id of object vue js

how can i pass id of object vue js
I have a json file, from it I need to get the id of the selected option from the selector
<div class="select">
<div class="select-header form-control" v-on:click="AddForm(1)">
<span class="select__current" v-if="status_id == null">Please select status</span>
<span v-else>{{ typeStatus[status_id].name }}</span>
</div>
<div class=" select__body" v-if="addedForm === 1">
<div class="select-item" v-for="(type, index) in typeStatus" v-bind:key="type.id" v-on:click="status_id = index; addedForm = false;">
{{ type.name }}
</div>
</div>
</div>
methods: {
search() {
this.filter.append('status', this.typeStatus[this.status_id].id)
this.$emit('filter', this.filter);
},
}

How do I make the hoverable dropdown close when navigating to a differerent link in Bulma?

HERE is a SANDBOX with the issue on it
I have a hoverable dropdown inside a Navbar
When I move to a different page, the dropdown is still open
I have tried this in plain Bulma, the issue still remains
I am on Nuxt.js using SSR
I am using nuxt-link / equivalent of Vue router-link to navigate to a different page.
Here is the my default.vue file
<template>
<div class="ch-container">
<header class="ch-header">
<nav
class="navbar is-fixed-top"
role="navigation"
aria-label="main navigation"
>
<div class="navbar-brand">
<nuxt-link class="navbar-item" to="/">
<img
alt="CH Logo"
src="https://i.imgur.com/v35Kfc9.png"
width="28"
height="28"
/>
</nuxt-link>
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<nuxt-link class="navbar-item" to="/news">
News
</nuxt-link>
<nuxt-link class="navbar-item" to="/resources">
Resources
</nuxt-link>
<nuxt-link class="navbar-item" to="/tickers">
Tickers
</nuxt-link>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
More
</a>
<div class="navbar-dropdown">
<a class="navbar-item">
FAQ
</a>
<nuxt-link class="navbar-item" to="/contact">
Contact
</nuxt-link>
<hr class="navbar-divider" />
<a class="navbar-item">
Feature Request
</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<a href="#">
<fa :icon="faMoon" />
</a>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless">
<fa :icon="faExclamationCircle" />
</a>
<div class="navbar-dropdown">
<a class="navbar-item">
No new notifications
</a>
</div>
</div>
<div class="navbar-item">
<div class="buttons">
<nuxt-link class="button is-primary" to="/signup">
<strong>Sign up</strong>
</nuxt-link>
<nuxt-link id="login" class="button is-light" to="/login">
Log in
</nuxt-link>
</div>
</div>
</div>
</div>
</nav>
</header>
<main class="ch-main">
<nuxt />
</main>
<footer class="ch-footer is-hidden-mobile">
<div class="level">
<div class="level-left">
<div class="level-item">
<a href="#">
<span class="icon">
<fa :icon="faFacebookSquare" />
</span>
</a>
<a href="#">
<span class="icon">
<fa :icon="faTwitterSquare" />
</span>
</a>
<a href="#">
<span class="icon">
<fa :icon="faRedditSquare" />
</span>
</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
©ch, All Rights Reserved
</div>
<div class="level-item">
<nuxt-link to="/contact">Contact</nuxt-link>
</div>
<div class="level-item">
<nuxt-link to="/terms-of-service">Terms</nuxt-link>
</div>
<div class="level-item">
<nuxt-link to="/privacy-policy">Privacy</nuxt-link>
</div>
</div>
</div>
</footer>
</div>
</template>
<script>
import {
faFacebookSquare,
faTwitterSquare,
faRedditSquare,
} from '#fortawesome/free-brands-svg-icons'
import { faMoon, faExclamationCircle } from '#fortawesome/free-solid-svg-icons'
export default {
computed: {
faFacebookSquare() {
return faFacebookSquare
},
faTwitterSquare() {
return faTwitterSquare
},
faRedditSquare() {
return faRedditSquare
},
faMoon() {
return faMoon
},
faExclamationCircle() {
return faExclamationCircle
},
},
mounted() {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(
document.querySelectorAll('.navbar-burger'),
0
)
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach((el) => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target
const $target = document.getElementById(target)
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active')
$target.classList.toggle('is-active')
})
})
}
},
}
</script>
<style></style>
Here is a GIF illustrating the problem
How to close the dropdown after you move to a different page?
Ok, the whole thing makes it complicated, because the hover is triggered by css and therefore the dropdown can always be seen when the mouse is over it. You have to overwrite this state and solve it with vue events. We also have to put a watcher on the route to reset the state.
CodeSandbox - Example
<template>
<div class="container">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<!-- <a class="navbar-item" href="https://bulma.io"> -->
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item">Home</a>
<a class="navbar-item">Documentation</a>
<div
#mouseover="toggleDropdown(true)"
#mouseleave="toggleDropdown(false)"
class="navbar-item has-dropdown is-hoverable"
>
<a class="navbar-link">More</a>
<div class="navbar-dropdown" :style="{display: showDropdown ? 'block' : 'none' }">
<nuxt-link class="navbar-item" to="/about">About</nuxt-link>
<nuxt-link class="navbar-item" to="/jobs">Jobs</nuxt-link>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong>Sign up</strong>
</a>
<a class="button is-light">Log in</a>
</div>
</div>
</div>
</div>
</nav>
<Nuxt/>
</div>
</template>
<script>
export default {
data() {
return {
routeChange: false,
showDropdown: false
};
},
watch: {
$route() {
this.routeChange = true;
this.showDropdown = false;
}
},
methods: {
toggleDropdown(payload) {
if (this.showDropdown !== payload) this.routeChange = false;
if (!this.routeChange) {
this.showDropdown = payload;
}
}
}
};
</script>
This worked form me Bootstrap 5, in touch devices it uses click, on devices with mouse it uses hover
<template>
<span
v-if="item"
class="primary-navigation-list-dropdown"
#mouseover="isTouchscreenDevice ? null : openDropdownMenu()"
#mouseleave="isTouchscreenDevice ? null : closeDropdownMenu()"
>
<nuxt-link
to="#"
#click.prevent.native="openDropdownMenu"
v-click-outside="closeDropdownMenu"
:title="item.title"
:class="[
item.cssClasses,
{ show: isDropdownMenuVisible }
]"
:id="`navbarDropdownMenuLink-${item.id}`"
:aria-expanded="[isDropdownMenuVisible ? true : false]"
class="
primary-navigation-list-dropdown__toggle
nav-link
dropdown-toggle"
aria-current="page"
role="button"
data-toggle="dropdown"
>
{{ item.label }}
</nuxt-link>
<ul
:class="{ show: isDropdownMenuVisible }"
:aria-labelledby="`navbarDropdownMenuLink-${item.id}`"
class="
primary-navigation-list-dropdown__menu
dropdown-menu-list
dropdown-menu"
>
<li
v-for="item in item.children" :key="item.id"
class="dropdown-menu-list__item"
>
<NavLink
:attributes="item"
class="dropdown-menu-list__link dropdown-item"
/>
</li>
</ul>
</span>
</template>
<script>
import NavLink from '#/components/Navigation/NavLink';
export default {
name: "DropdownMenu",
props: {
item: {
type: Object,
required: true,
},
},
data() {
return {
isDropdownMenuVisible: false,
isTouchscreenDevice: false
};
},
mounted() {
this.detectTouchscreenDevice();
},
methods: {
openDropdownMenu() {
if (this.isTouchscreenDevice) {
this.isDropdownMenuVisible = !this.isDropdownMenuVisible;
} else {
this.isDropdownMenuVisible = true;
}
},
closeDropdownMenu() {
if (this.isTouchscreenDevice) {
this.isDropdownMenuVisible = false;
} else {
this.isDropdownMenuVisible = false;
}
},
detectTouchscreenDevice() {
if (window.PointerEvent && ('maxTouchPoints' in navigator)) {
if (navigator.maxTouchPoints > 0) {
this.isTouchscreenDevice = true;
}
} else {
if (window.matchMedia && window.matchMedia("(any-pointer:coarse)").matches) {
this.isTouchscreenDevice = true;
} else if (window.TouchEvent || ('ontouchstart' in window)) {
this.isTouchscreenDevice = true;
}
}
return this.isTouchscreenDevice;
}
},
components: {
NavLink
}
};
</script>
<style scoped lang="scss">
.primary-navigation-list-dropdown {
&__toggle {
color: $white;
&:hover {
color: $blue;
}
}
&__menu {
margin-top: 0;
}
&__dropdown {
}
}
.dropdown-menu-list {
&__item {
}
&__link {
&.active,
&.nuxt-link-exact-active {
border-bottom: 1px solid $blue;
}
}
}
</style>
NavLink.vue
<template>
<component
:is="attributes"
v-bind="linkAttributes(attributes.path)"
:title="attributes.title"
:class="[ attributes.cssClasses ]"
class="nav-link active_"
aria-current="page"
prefetch
>
{{ attributes.label }}
</component>
</template>
<script>
export default {
name: 'NavLink',
props: {
attributes: {
type: Object,
required: true
}
},
methods: {
linkAttributes(path) {
if (path.match(/^(http(s)?|ftp):\/\//) || path.target === '_blank') {
return {
is: 'a',
href: path,
target: '_blank',
rel: 'noopener'
}
}
return {
is: 'nuxt-link',
to: path
}
}
}
}
</script>
click-outside.js
import Vue from 'vue'
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
if (!(el == event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent)
},
unbind: function (el) {
document.body.removeEventListener('click', el.clickOutsideEvent)
},
});
I’m not using Vue, but using Meteor (where similar route-calling trips up the Bulma drop-down removal).
Slightly hacky way to fix it, but the dropdown is made visible because the .has-dropdown element has the .is-hoverable class. So to fix, on any click on the dropdown’s items, I run this:
// Remove the hover effect = dropdown disappears
$(".has-dropdown").removeClass("is-hoverable");
// Tiny time later, put it back, so hover-drop works anew
setTimeout(function() {
$(".has-dropdown").addClass("is-hoverable");
}, 100);
Doesn’t really matter that it would hit all the dropdowns if you have more than one, because resetting them all is harmless when routing to a new page. But if you’re fussy you could target just the closest dropdown.
As Bulma’s mobile view doesn’t activate an on-hover effect anyway, this doesn’t break in the mobile “burger menu” version of my navbar.
Works OK for my project on Chrome, Safari, Firefox.

Can I send more than only value with v-model to v-for

I am new to Vue but I think that this can be really useful.
I have my first problem this simplified example
var appvue = new Vue({
el: '#appvue',
data: {
selectedProd: []
}
});
body {
background: #20262E;
}
.form-row{
width:24%;
display:inline-block;
}
#appvue {
background: #fff;
padding:10px;
}
#prod_adjust{
margin-top:20px;
background: #eee
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div class="prod-wrap" id="appvue">
<div class="form-row">
<input v-model="selectedProd" name="product-1260" id="product-1260" type="checkbox" value="1260">
<label for="product-1260">
<div class="thumb">
<img src="https://picsum.photos/100/100">
</div>
<div class="details">
<span class="brand">Brand 1</span>
<span class="product-title">Product 1</span>
</div>
</label>
</div>
<div class="form-row">
<input v-model="selectedProd" name="product-1261" id="product-1261" type="checkbox" value="1261">
<label for="product-1261">
<div class="thumb">
<img src="https://picsum.photos/100/100">
</div>
<div class="details">
<span class="brand">Brand 2</span>
<span class="product-title">Product 2</span>
</div>
</label>
</div>
<div class="form-row">
<input v-model="selectedProd" name="product-1263" id="product-1263" type="checkbox" value="1263">
<label for="product-1263">
<div class="thumb">
<img src="https://picsum.photos/100/100">
</div>
<div class="details">
<span class="brand">Brand 3</span>
<span class="product-title">Product 3</span>
</div>
</label>
</div>
<div class="form-row">
<input v-model="selectedProd" name="product-1264" id="product-1264" type="checkbox" value="1264">
<label for="product-1264">
<div class="thumb">
<img src="https://picsum.photos/100/100">
</div>
<div class="details">
<span class="brand">Brand 4</span>
<span class="product-title">Product 4</span>
</div>
</label>
</div>
<div id="prod_adjust">
<p v-for="product in selectedProd">{{product}}</p>
</div>
</div>
I have a lot of products like the checkboxes above. I need to have the list of checked items in another place.
I did this with v-model and v-for - but my main problem is now that there are sending only the value from the checkboxes - I also need img-src, brand, product-title - all these parameters I also can have more attributes in an input.
But how I can pass them in data: { selectedProd:[]} with Vue?
Or I do I need to create a separate JS function which will collect all this data and send it to the array selectedProd?
Thank you in advance
You would want to create an object with the data you need for the product. Then you can use v-for to loop through and display them the way you'd like.
In the example, I included a computed function that automatically returns the ones that get checked. This is done by v-model binding the checkbox to a flag inside your object. In this example, I called it selected, for simplicity.
var appvue = new Vue({
el: '#appvue',
data: {
products: [{
id: 1260,
brand: "Brand A",
product: "Bubblegun",
image: "https://picsum.photos/100/100",
selected: false
}, {
id: 1261,
brand: "Brand B",
product: "Bubblegum",
image: "https://picsum.photos/100/100",
selected: false
}],
},
computed: {
selectedProd() {
return this.products.map(product => {
if (product.selected) return product
})
}
}
})
body {
background: #20262E;
}
.form-row {
width: 24%;
display: inline-block;
}
#appvue {
background: #fff;
padding: 10px;
}
#prod_adjust {
margin-top: 20px;
background: #eee
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.min.js"></script>
<div class="prod-wrap" id="appvue">
<div class="form-row" v-for="product in products">
<input v-model="product.selected" name="product-1260" id="product-1260" type="checkbox">
<label for="product-1260">
<div class="thumb">
<img :src="product.image">
</div>
<div class="details">
<span class="brand">{{product.brand}}</span>
<span class="product-title">{{product.product}}</span>
</div>
</label>
</div>
<div id="prod_adjust">
<p v-for="product in selectedProd">{{product}}</p>
</div>
</div>
If you have the input as a JSON which has all the properties you are asking for (product_ID, img src, brand name) then you can assign the object to v-model instead of product_ID.
Your JSON array should look like this,
productsArray: [
{ productID: 1260,
product-title: "Product 1",
brand: "Brand 1",
img: "https://picsum.photos/100/100"
},
{ productID: 1261,
product-title: "Product 2",
brand: "Brand 2",
img: "https://picsum.photos/100/100"
},]
Then inside v-for you can read each object and when selected you can assign the entire object into selectedProd
I used next way finally
vueproducts = function(){
appvue.selectedProd = [];
var tempprod = {};
$('.form-row input').each(function(){
if ($(this).is(":checked")){
tempprod.id = $(this).val();
tempprod.img = $(this).parent().find('img').attr('src');
tempprod.title = $(this).parent().find('.product-title').html();
appvue.selectedProd.push(tempprod);
tempprod = {};
};
});
}

Apply different class to list item in v-for dynamically created items vuejs

All I want to do is apply a conditional class to a list item as it is pushed to my messages array and then shown on screen. However, I do not want the all of the previous list items to have the same styling applied. Every time a new item is added, it checks what class should be applied, depending on whether sender or receiver of message, and then it applies whichever class necessary to all list items, but I only want it to be applied that new item. How can I achieve this?
app.js:
const chatWindow = new Vue({
el: '#chatWindow',
data: {
messages: [],
currentUser: document.getElementById('sender').value,
sender: true
},
methods: {
sendMessage: function () {
this.$http.post('/chat', {message: this.message, sender: this.currentUser}).then((response) => {
console.log('request sent successfully');
}, (response) => {
console.log('request not sent');
});
this.message = '';
}
},
props: ['message']
});
window.Echo.channel('test-chat-channel')
.listen('MessageSent', (event) => {
chatWindow.$data.sender = event.sender == chatWindow.$data.currentUser;
chatWindow.$data.messages.push(event);
});
chat.blade.php (view):
#extends('layouts.app')
#section('content')
<div class="container text-center">
<div class="row">
<div class="col-sm-3 hidden-xs" style="border: 2px solid black; height: 500px;">
<h2 class="text-center no-top">Sidebar</h2>
</div>
<div id="chatWindow" class="col-sm-7">
<h1 class="text-center no-top">Chat</h1>
<div class="chat-window">
<input type="hidden" id="sender" value="{{ Auth::user()->id }}">
<ul id="chat-messages">
<li v-for="message in messages" :class="sender ? 'left' : 'right'">
#{{ message.message }}
<span class="pull-right">#{{ message.timestamp }}</span>
</li>
</ul>
<div class="form-group">
<input title="Send Message" v-model="message" #keyup.enter="sendMessage" class="form-control" placeholder="Send message...">
</div>
</div>
</div>
<div class="col-sm-2 hidden-xs" style="border: 2px solid black; height: 500px;">
<h2 class="text-center no-top">Infobar</h2>
</div>
</div>
</div>
#endsection
#section('scripts')
#endsection