Ability to click on content under modal with bootstrap-vue - vue.js

Want to be able to click on a button or to copy/select content from the background/page when a modal is opened.
Found something at: Allow people to click on links under bootstrap modal when modal backdrop is not present
that recommends to use .modal{bottom:initial!important;} but this doesn't seem to work with bootstrap-vue.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="node_modules/bootstrap-vue/dist/bootstrap-vue.css" />
<style>
.modal{bottom:initial!important;}
</style>
</head>
<body>
<div id="app-2">
<b-navbar toggleable="lg" type="dark" variant="dark">
<b-navbar-brand href="#">NavBar</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item href="#">Link</b-nav-item>
<b-nav-item href="#" disabled>Disabled</b-nav-item>
</b-navbar-nav>
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
</b-nav-form>
<b-nav-item-dropdown text="Lang" right>
<b-dropdown-item href="#">EN</b-dropdown-item>
<b-dropdown-item href="#">ES</b-dropdown-item>
<b-dropdown-item href="#">RU</b-dropdown-item>
<b-dropdown-item href="#">FA</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown right>
<!-- Using 'button-content' slot -->
<template slot="button-content"><em>User</em></template>
<b-dropdown-item href="#">Profile</b-dropdown-item>
<b-dropdown-item href="#">Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id="modal-1" #shown='dragable' title="BootstrapVue" no-close-on-backdrop hide-backdrop>
<p class="my-4">Hello from modal!</p>
</b-modal>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="node_modules/bootstrap-vue/dist/bootstrap-vue.js"></script>
<script>
window.dragable = function (a) {
let header = a.vueTarget.$refs.header;
let el = a.vueTarget.$refs.content;
let mousePosition;
let offset = [0, 0];
let isDown = false;
header.onmousedown = (e) => {
isDown = true;
offset = [
el.offsetLeft - e.clientX,
el.offsetTop - e.clientY
];
}
header.onmouseup = (e) => {
isDown = false;
};
header.onmousemove = (e) => {
e.preventDefault();
if (isDown) {
mousePosition = {
x: e.clientX,
y: e.clientY
};
el.style.left = (mousePosition.x + offset[0]) + 'px';
el.style.top = (mousePosition.y + offset[1]) + 'px';
}
};
}
var app2 = new Vue({
el: '#app-2',
methods: {
dragable: dragable
}
})
</script>
</body>
</html>
Solution:
Adding pointer-events:none to the modal css/style
window.dragable = function(a) {
let header = a.vueTarget.$refs.header;
let el = a.vueTarget.$refs.content;
let modal = a.vueTarget.$refs.modal;
let mousePosition;
let offset = [0, 0];
let isDown = false;
modal.onmousedown = (e) => {
document.querySelectorAll('.modal').forEach(e => {
e.parentNode.style.zIndex = e.isSameNode(a.vueTarget.$refs.modal) ? 1041 : 1040;
})
}
header.onmousedown = (e) => {
isDown = true;
offset = [
el.offsetLeft - e.clientX,
el.offsetTop - e.clientY
];
document.querySelectorAll('.modal').forEach(e => {
e.parentNode.style.zIndex = e.isSameNode(a.vueTarget.$refs.modal) ? 1041 : 1040;
})
}
header.onmouseup = (e) => {
isDown = false;
};
header.onmousemove = (e) => {
e.preventDefault();
if (isDown) {
mousePosition = {
x: e.clientX,
y: e.clientY
};
el.style.left = (mousePosition.x + offset[0]) + 'px';
el.style.top = (mousePosition.y + offset[1]) + 'px';
}
};
}
var n = 0;
var app2 = new Vue({
el: '#app-2',
methods: {
dragable: dragable
}
})
.modal {
pointer-events: none;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
</head>
<body>
<div id="app-2">
<b-navbar toggleable="lg" type="dark" variant="dark">
<b-navbar-brand href="#">NavBar</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item href="#">Link</b-nav-item>
<b-nav-item href="#" disabled>Disabled</b-nav-item>
</b-navbar-nav>
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
</b-nav-form>
<b-nav-item-dropdown text="Lang" right>
<b-dropdown-item href="#">EN</b-dropdown-item>
<b-dropdown-item href="#">ES</b-dropdown-item>
<b-dropdown-item href="#">RU</b-dropdown-item>
<b-dropdown-item href="#">FA</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown right>
<!-- Using 'button-content' slot -->
<template slot="button-content"><em>User</em></template>
<b-dropdown-item href="#">Profile</b-dropdown-item>
<b-dropdown-item href="#">Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id="modal-1" #shown='dragable' title="BootstrapVue" no-close-on-backdrop hide-backdrop>
<p class="my-4">Hello from modal!</p>
</b-modal>
<b-button v-b-modal.modal-2>Launch demo modal</b-button>
<b-modal id="modal-2" #shown='dragable' title="BootstrapVue" no-close-on-backdrop hide-backdrop>
<p class="my-4">Hello from modal!</p>
</b-modal>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
</body>
</html>

You can also disable the backdrop via the hide-backdrop prop, and disable close on backdrop click via the no-close-on-backdrop prop.
See docs at https://deploy-preview-3503--bootstrap-vue.netlify.com/docs/components/modal#comp-ref-b-modal

I don't quite remember modal backdrop class. But you should try to set backdrop css property pointer-events: none; it would make it "transparent" to all mouse/touch events.

Related

in svelte shows me variable hash in the variables

I have a problem, i am trying to search an element by id in the script but it was not working, when i go to show the values in console, i see that it adds after each variable a random hash, and that is why it does not find the id.
How can I avoid those random hashes?
Svelte
console
I tried different declarations, splits and so on, but it always adds it. Help
<script>
import { page } from '$app/stores';
import { onMount, beforeUpdate } from 'svelte';
import { Line } from 'svelte-chartjs';
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale } from 'chart.js';
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale);
export let param = String($page.params.slug);
let ruta_api = `${import.meta.env.VITE_WP_API}posts?slug=${param}`;
let ruta_api_chart = '';
let value = [];
let value_chart = [];
let data_chart = new Array;
let id_chart = '';
onMount(async () => {
await loadData();
});
async function loadData() {
const response = await fetch(ruta_api);
const newData = await response.json();
value = [...value, ...newData];
ifChart();
}
beforeUpdate(async () => {
});
async function ifChart(){
//comprobamos si viene una grafica en el contenido
let posicion_chart = value[0].content.rendered.indexOf('m-chart-container-');
if(posicion_chart >= 0){
console.log(id_chart);
const regex = /(?<=m-chart-container-)(.*?)(?=-)/mg;
console.log(value[0].content.rendered.match(regex)[0]);
id_chart = value[0].content.rendered.match(regex);
//recorremos los ids
id_chart.forEach(function(id) {
getChart(id);
let div_chart = 'm-chart-container-'+id+'-1';
console.log('primero');
console.log({div_chart});
console.log('segundo');
console.log(`${div_chart}`);
console.log('tercero');
console.log(div_chart);
document.getElementById(div_chart).innerHTML = '11111';
})
//<Line data={data_chart} options={{ responsive: true }} />
}
};
export async function getChart(id){
ruta_api_chart = `${import.meta.env.VITE_WP_API}m-chart/` + id;
console.log(ruta_api_chart);
const response_chart = await fetch(ruta_api_chart);
const newData_chart = await response_chart.json();
value_chart = newData_chart['m-chart'];
var datos = value_chart['data'][0][1].filter(n => n).map(Number);
data_chart =
{'labels' : value_chart['data'][0][0].filter(n => n),
'datasets': [{
'label' : 'My First dataset',
'borderColor': 'rgb(205, 130, 158)',
'data' : datos
}]
};
};
</script>
{#each value as article}
<div class="hero" style="background-image: url({article.featured_image_url ? article.featured_image_url : '../img/componentes/blog-img-defecto.png'});">
<div class="hero-overlay bg-opacity-60"></div>
<div class="hero-content text-center text-neutral-content">
<div class="max-w-md">
<h1 class="mb-5 text-5xl font-bold text-secondary">{#html article.title.rendered}</h1>
</div>
</div>
</div>
<div class="w-full mb-32 contenidoblog pt-8">
{#html article.content.rendered}
<div class="flex items-center flex-col my-20">
<button onclick="" class="btn btn-sm border-0 w-40 rounded-full bg-primary font-normal hover:bg-accent text-secondary hover:text-primary transition ease-in-out duration-500 transform hover:scale-105 px-10 mt-4 pr-10 relative">
<span class="absolute left-8">Descargar</span>
<span class="material-symbols-outlined absolute right-8">
download
</span>
</button>
</div>
<!--
<div class="flex items-center flex-col w-full bg-accent h-24">
Bloque post relacionados
</div>
-->
<div class="flex items-center flex-col my-20">
<button onclick="" class="btn btn-sm border-0 w-40 rounded-full bg-accent font-normal hover:bg-primary text-primary hover:text-secondary transition ease-in-out duration-500 transform hover:scale-105 px-10 mt-4 pr-10 relative">
<span class="absolute left-6">Suscribete</span>
<span class="material-symbols-outlined absolute right-6">
add_circle
</span>
</button>
</div>
</div>
{/each}

Data is not coming if i use async in vue js 3

I am implementing Quiz App but here I am facing an issue if I put static data in array the questions are coming.
Data is not coming if i use async in Vue JS 3
But If I Call data from the API the questions are not showing.
when I console the questions are showing in console and not showing in the front end.
For ref please find the attached code and image.
Home.vue (please see fetchQuestionsFromServer function)
<template>
<main class="flex h-screen items-center justify-center bg-gray-100">
<!-- quiz container -->
<QuizComplatePage v-if="endofQuiz" />
<div
class="overflow-hidden bg-white flex-none container relative shadow-lg rounded-lg px-12 py-6"
>
<img
src="#/assets/images/abstract.svg"
alt=""
class="absolute -top-10 left-0 object-none"
/>
<!-- contents -->
<div class="relative z-20">
<!-- score container -->
<div class="text-right text-gray-800">
<p class="text-sm leading-3">Score</p>
<p class="font-bold">{{score}}</p>
</div>
<!-- timer container -->
<div class="bg-white shadow-lg p-1 rounded-full w-full h-5 mt-4">
<div class="bg-blue-700 rounded-full w-11/12 h-full"
:style= "`width: ${timer}%`"
></div>
</div>
<!-- question container -->
<div
class="rounded-lg bg-gray-100 p-2 neumorph-1 text-center font-bold text-gray-800 mt-8"
>
<div class="bg-white p-5">
{{currentQuestion.question}}
</div>
</div>
<!-- options container -->
<div class="mt-8">
<!-- option container -->
<div v-for="(choice,item) in currentQuestion.choices" :key="item">
<div
class="neumorph-1 option-default bg-gray-100 p-2 rounded-lg mb-3 relative"
:ref="optionchosen"
#click="onOptionClick(choice,item)"
>
<div
class="bg-blue-700 p-1 transform rotate-45 rounded-md h-10 w-10 text-white font-bold absolute right-0 top-0 shadow-md"
>
<p class="transform -rotate-45">+10</p>
</div>
<div class="rounded-lg font-bold flex p-2">
<!-- option ID -->
<div class="p-3 rounded-lg">{{item}}</div>
<!-- option name -->
<div class="flex items-center pl-6">{{choice}}</div>
</div>
</div>
</div>
<!-- option container -->
</div>
<!-- progress indicator container -->
<div class="mt-8 text-center">
<div class="h-1 w-12 bg-gray-800 rounded-full mx-auto"></div>
<p class="font-bold text-gray-800">{{questionCounter}}/{{questions.length}}</p>
</div>
</div>
</div>
</main>
</template>
<script>
import { onMounted, ref } from 'vue'
import QuizComplatePage from './QuizCompleteOverlay.vue'
export default{
components: {
QuizComplatePage
},
setup(){
//data
let canClick = true
let score = ref(0)
let timer = ref(100)
let endofQuiz = ref(false)
let questionCounter = ref(0)
const currentQuestion = ref({
question: '',
answer: 1,
choices: [],
});
const questions = []
const loadQuestion = () =>{
canClick = true
timer.value=100
//Check question array had questions or not
if(questions.length > questionCounter.value){
currentQuestion.value = questions[questionCounter.value]
console.log('Current Question is : ', currentQuestion.value);
questionCounter.value++
}else{
endofQuiz.value = true
console.log('Out of Questions');
}
}
//methods
let itemsRef = []
const optionchosen = (element) =>{
if(element){
itemsRef.push(element)
}
}
const clearSelected = (divselected) =>{
setTimeout(()=>{
divselected.classList.remove('option-correct')
divselected.classList.remove('option-wrong')
divselected.classList.add('option-default')
loadQuestion()
},1000)
}
const onOptionClick = (choice,item) =>{
if(canClick)
{
const divContainer = itemsRef[item]
const optionId = item+1
if(currentQuestion.value.answer ===optionId){
console.log('You are Correct');
score.value += 10
divContainer.classList.add('option-correct')
divContainer.classList.remove('option-default')
}else{
console.log('You are Wrong');
divContainer.classList.add('option-wrong')
divContainer.classList.remove('option-default')
}
timer.value=100
canClick=false
//to go next question
clearSelected(divContainer)
console.log(choice,item);
}else{
console.log('Cant Select Option');
}
}
const countDownTimer = () =>{
let interval= setInterval(()=>{
if(timer.value>0){
timer.value--
}else{
console.log('Time is over');
clearInterval(interval)
}
},150)
}
const fetchQuestionsFromServer = async function(){
fetch('https://opentdb.com/api.php?amount=10&category=18&type=multiple')
.then((res) =>{
return res.json()
})
.then((data) =>{
const newQuestions = data.results.map((serverQuestion) =>{
const arrangedQuestion = {
question: serverQuestion.question,
choices: '',
answer: ''
}
const choices = serverQuestion.incorrect_answers
arrangedQuestion.answer = Math.floor(Math.random() * 4 + 1)
choices.splice(arrangedQuestion.answer-1 , 0 , serverQuestion.correct_answer)
arrangedQuestion.choices = choices
return arrangedQuestion
})
console.log('new formated questions' , newQuestions);
questions.value = newQuestions
loadQuestion()
countDownTimer()
console.log('questions: =>' , questions.value);
})
}
//lifecycle hooks
onMounted(() =>{
fetchQuestionsFromServer()
})
//return
return {
timer,
currentQuestion,
questions,
score,
questionCounter,
loadQuestion,
onOptionClick,
optionchosen,
endofQuiz,
}
}
}
</script>
<style scoped>
.neumorph-1 {
box-shadow: 6px 6px 18px rgba(0, 0, 0, 0.09), -6px -6px 18px #ffffff;
}
.container {
max-width: 400px;
border-radius: 25px;
}
</style>
QuizComplatePage.vue
<template>
<div class="w-screen h-screen absolute z-30 bg-white bg-opacity-30 flex justify-center items-center">
<div class="bg-green-700 p-4 text-center text-white">
<p class="font-bold text-2xl">All DOne!</p>
<p class="my-4 font-bold text-3xl">100% Score</p>
<!-- Buttons -->
<div class="flex justify-center">
<div class="rounded-full py-1 w-28 border cursor-pointer hover:text-black hover:bg-white">Done</div>
<div class="rounded-full py-1 w-28 border cursor-pointer hover:text-black hover:bg-white">Retry</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'QuizComplatePage'
}
</script>
<style>
</style>
Image.
You are not using value when you need to:
For instance look in this function
questions.length should be questions.value.length
Also currentQuestion.value = questions.value[questionCounter.value]
Start by fixing that.
Everything that is a ref in your setup needs to be accessed by .value in anything inside your setup. Outside your setup it will have this and can be treated normally. Mixing these two up is the most common error.
const loadQuestion = () =>{
canClick = true
timer.value=100
//Check question array had questions or not
if(questions.value.length > questionCounter.value){
currentQuestion.value = questions.value[questionCounter.value]
console.log('Current Question is : ', currentQuestion.value);
questionCounter.value++
}else{
endofQuiz.value = true
console.log('Out of Questions');
}
}
Here is my solution
let questions = []
questions = newQuestions
Now I am able to load questions.

[Vue warn]: Property or method "StartGame" is not defined on the instance but referenced during render

[Vue warn]: Property or method "StartGame" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
enter image description here
This is the code from jsfiddle:
html
<!DOCTYPE html>
<html>
<head>
<title>Monster Slayer</title>
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<link rel="stylesheet" href="css_project1/">
<link rel="stylesheet" href="css_project1//app.css">
<script src="https://unpkg.com/vue#2.6.9/dist/vue.js"></script>
</head>
<body>
<div id="app">
<section class="row">
<div class="small-6 columns">
<h1 class="text-center">YOU</h1>
<div class="healthbar">
<div class="healthbar text-center"
style="background-color: green; margin: 0; color: white;"
:style="{width:playerHealth + '%'}">
{{ playerHealth }}
</div>
</div>
</div>
<div class="small-6 columns">
<h1 class="text-center">MONSTER</h1>
<div class="healthbar">
<div class="healthbar text-center"
style="background-color: green; margin: 0; color: white;"
:style="{width:monsterHealth + '%'}">
{{ monsterHealth }}
</div>
</div>
</div>
</section>
<section class="row controls" v-if="!gameIsRunning">
<div class="small-12 columns">
<!-- <input type="text"> -->
<button id="start-game" #click="StartGame" >START NEW GAME</button>
</div>
</section>
<section class="row controls" v-else>
<div class="small-12 columns">
<button id="attack" #click="attack">ATTACK</button>
<button id="special-attack" #click="specialAttack">SPECIAL ATTACK</button>
<button id="heal" #click="heal">HEAL</button>
<button id="give-up" #click="giveUp">GIVE UP</button>
</div>
</section>
<section class="row log" v-if="gameIsRunning">
<div class="small-12 columns">
<ul>
<li>
</li>
</ul>
</div>
</section>
</div>
<script src="app.js"></script>
</body>
</html>
new Vue({
el:"#app",
data: {
playerHealth: 10,
monsterHealth: 10,
gameIsRunning:false,
},
methods:{
StartGame: function(){
this.gameIsRunning = true;
this.playerHealth = 40;
this.monsterHealth = 40;
},
}
})
Create a javascript file. for example game.js . move the code to that file..
new Vue({
el:"#app",
data:{
playerHealth: 100,
monsterHealth: 100,
gameIsRunning:false,
},
methods:{
StartGame: function(){
this.gameIsRunning = true;
this.playerHealth = 100;
this.monsterHealth = 100;
},
attack: function(){
// var max = 10;
// var min = 3;
// var damage = this.calculateDamage(3,10);
this.monsterHealth -= this.calculateDamage(3,10);;
if(this.checkWin()){
return;
}
// if(this.monsterHealth <= 0){
// alert("we won");
// this.gameIsRunning = false;
// return;
// }
// max = 12;
// min = 5;
// damage = this.calculateDamage(5,12);
this.playerHealth -= this.calculateDamage(5,12);;
// if(this.playerHealth <= 0){
// alert("we lost");
// this.gameIsRunning = false;
// return;
// }
this.checkWin();
},
specialAttack:function(){
this.monsterHealth -= this.calculateDamage(10,10);;
if(this.checkWin()){
return;
}
this.playerHealth -= this.calculateDamage(5,12);;
this.checkWin();
},
heal: function(){
},
giveUp: function(){
},
calculateDamage: function(min, max){
return Math.max(Math.floor(Math.random() * max) + 1, min);
},
checkWin: function(){
if(this.monsterHealth <= 0){
if(confirm("You won! New Game?")){
this.StartGame();
}else{
this.gameIsRunning = false;
}
return true;
}
else if(this.playerHealth <= 0){
if(confirm("You lost! New Game?")){
this.StartGame();
}else{
this.gameIsRunning = false;
}
return true;
}
return;
}
}
})
Then include that javascript file before </body> tag. for example
<script src="app.js"></script>
<script src="https://YOURDOMAIN.COM/game.js"></script>
</body>
</html>
Your data must be a function that returns object:
data() {
return {
playerHealth: 10,
monsterHealth: 10,
gameIsRunning:false,
}
},
For the other methods to work - add them to methods object ;-)

Vue add a component on button click

I have three templates. AddCard.vue , ImageCard.vue and VideoCard.vue
AddCard.vue has two buttons on it one is to add the Image Card and Other To Add the video Card.. I need to add components based on the button click. Here are three templates and my index.html file.
index.html
<!doctype html>
<html lang="en">
<head>
</head>
<body>
<div id="app">
<div class="container">
<div id="dynamic_components">
<!-- add components here -->
</div>
<addcard></addcard>
</div>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
AddCard.vue
<template>
<div class="buttons">
ul class="no-margin-list">
<li #click="imagecard">
<span class="card_icon">
<img :src="'img/image.jpg'" >
</span>
<p>Add Image Card</p>
</a>
</li>
<li #click="videocard">
<span class="card_icon">
<img :src="'img/video.jpg'" >
</span>
<p>Add Video Card</p>
</a>
</li>
</div>
</template>
<script>
export default {
computed: {
},
methods: {
imagecard(val) {
//how to add image card
},
videocard() {
//how to add video card
}
},
}
</script>
ImageCard.vue
<template>
<h1> I am a image Card </h1>
</template>
<script>
</script>
VideoCard.vue
<template>
<h1> I am a Video Card </h1>
</template>
<script>
</script>
I need to add components dynamically one after another in the <div id="dynamic_components"> . User can add as many as cards they want.
How do I add the components dynamically. Please point me to a tutorial.
Uses v-for + dynamic component.
Vue.config.productionTip = false
Vue.component('card1', {
template: '<div>Card:<span style="background-color:green">{{title}}</span></div>',
props: ['title']
})
Vue.component('card2', {
template: '<div>Card:<span style="background-color:blue">{{title}}</span></div>',
props: ['title']
})
Vue.component('card3', {
template: '<div>Card:<span style="background-color:yellow">{{title}}</span></div>',
props: ['title']
})
new Vue({
el: '#app',
data() {
return {
cards: [
{'card': {'title': 'I am one card1'}, 'card-type':'card1'},
{'card': {'title': 'I am one card2'}, 'card-type':'card2'}
]
}
},
computed: {
computedNoCard1: function () {
let availableCards = new Set(['card2', 'card3'])
return this.cards.filter((item) => {
return availableCards.has(item['card-type'])
})
}
},
methods: {
addCard: function () {
let supportedCards = ['card1', 'card2', 'card3']
let seed = Math.floor(Math.random()*supportedCards.length)
this.cards.push({'card': {'title': 'I am new card for ' + supportedCards[seed]}, 'card-type': supportedCards[seed]})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<button #click="addCard()">Add Card</button>
<table>
<tr><th>Data Property</th><th>Computed Property</th></tr>
<tr>
<td>
<div v-for="(card, index) in cards" :key="index">
<component :is="card['card-type']" :title="card.card.title">
</component>
</div>
</td>
<td>
<div v-for="(card, index) in computedNoCard1" :key="index">
<component :is="card['card-type']" :title="card.card.title">
</component>
</div>
</td>
</tr>
</table>
</div>

v-on:click not working in a child component

First thing first I'm new to vue.js.
what I'm trying to do when the user click on the expander anchor tag in the item-preview component the item-details will display and the item-preview will be hide. Now the problem occurs when the item-preview displayed and i'm trying to toggle it by clicking its own expander anchor tag. I do not whats wrong with this.
Here is my HTML templates.
<script type="text/x-template" id="grid">
<div class="model item" v-for="entry in data">
<item-preview v-bind:entry="entry" v-if="entry.hide == 0">
</item-preview>
<item-details v-bind:entry="entry" v-if="entry.hide == 1">
</item-details>
</div>
</script>
<script type="text/x-template" id="item-preview">
<header class="preview">
<a class="expander" tabindex="-1" v-on:click="toggle(entry)"></a>
<span class="name rds_markup">
{{ entry.name }}
</span>
</header>
</script>
<script type="text/x-template" id="item-details">
<div class="edit details">
<section class="edit" tabindex="-1">
<form action="#">
<fieldset class="item name">
<a class="expander" v-on:click="toggle(entry)"></a>
{{ entry.name }}
</fieldset>
</form>
</section>
</div>
</script>
And here how I called the grid component on my view.
<grid
:data="packages">
</grid>
And for my Vue implementation
var itemPreview = Vue.component('item-preview',{
'template':"#item-preview",
'props':{
entry:Object
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var itemDetails = Vue.component('item-details',{
'template':"#item-details",
'props':{
entry:Object
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var grid = Vue.component('grid',{
'template':"#grid",
'props':{
data:Array,
},
components:{
'item-preview': itemPreview,
'item-details': itemDetails
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var vm = new Vue({
el:'#app',
data:{
message:'Hello',
packages:{}
},
ready:function(){
this.fetchPackages();
},
methods:{
fetchPackages:function(){
this.$http.get(url1,function( response ){
this.$set('packages',response);
});
},
}
});
Silly me. It took me 30minutes to figure out what is wrong with this code.
What I did to fix this is instead of entry.hide = !!entry.hide; I use entry.hide = true in item-preview component and in the item-details entry.hide = false. this fix my issue.