Set up a v-on:click directive inside v-for - javascript

I have displayed a list of images with some information. I want those images to be clickable. And when clicked it should show a div with saying "HI!!". I have been trying to add a variable as show:true in Vue data and tried to build some logic that show becomes false when clicked. But I have not been able to achieve it.
Below is the sample code:
template>
<div>
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div ><img :src="launch.links.patch.small" alt="No Image" title={{launch.name}} /></div>
<div>ROCKET NAME: {{launch.name}} </div>
<div>DATE: {{ launch.date_utc}} </div>
<div>SUCCESS: {{ launch.success}} </div>
<div>COMPLETENESS: {{ launch.landing_success}} </div>
</div>
<!-- <v-model :start="openModel" #close="closeModel" /> -->
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SpaceXTimeline',
components: {
},
data: () => ({
launches : [],
openModel : false,
show : true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + " is launched");
console.log("DETAILS: "+ launch.details);
console.log("ROCKET INFO: "+ launch.links.wikipedia);
console.log("CREW DETAILS: "+ launch.crew);
console.log("Launchpad Name: "+ launch.launchpad);
this.openModel = true;
},
closeModel () {
this.openModel = false;
}
},
async created() {
const {data} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
}
};
</script>
<style scoped>
.list {
border: 1px solid black;
}
</style>
Thanks, and appreciate a lot.

v-model is a binding and not an element, unless you've named a component that? Is it a misspelling of "modal"?
Either way, sounds like you want a v-if:
<v-model v-if="openModel" #close="closeModel" />
Example:
new Vue({
el: '#app',
components: {},
data: () => ({
launches: [],
openModel: false,
show: true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + ' is launched');
console.log('DETAILS: ' + launch.details);
console.log('ROCKET INFO: ' + launch.links.wikipedia);
console.log('CREW DETAILS: ' + launch.crew);
console.log('Launchpad Name: ' + launch.launchpad);
this.openModel = true;
},
closeModel() {
this.openModel = false;
},
},
async created() {
const {
data
} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
},
})
Vue.config.productionTip = false;
Vue.config.devtools = false;
.modal {
cursor: pointer;
display: flex;
justify-content: center;
position: fixed;
top: 0;
width: 100%;
height: 100vh;
padding: 20px 0;
background: rgba(255, 255, 255, 0.5);
}
img {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div id="app">
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div>
<img :src="launch.links.patch.small" alt="No Image" :title="launch.name" />
</div>
<div>ROCKET NAME: {{ launch.name }}</div>
<div>DATE: {{ launch.date_utc }}</div>
<div>SUCCESS: {{ launch.success }}</div>
<div>COMPLETENESS: {{ launch.landing_success }}</div>
</div>
<div v-if="openModel" #click="closeModel" class="modal">
MODAL
</div>
</div>

Related

y-Maps+VueJS.I want the label to be deleted when clicking on the button in the CustomBalloon.But the function of the button is applied to marker

yandex maps + VueJS. I want the label to be deleted when clicking on the button in the Custom balloon. But the function of the button is applied to the entire grid, not to the button itself. Because of this, when you click on the label to open this window, the page is reloaded and the label is deleted
<template>
<div>
<yandex-map
:coords="currentCenter"
:zoom="zoom"
:controls="controls"
style="width: 100%; height: 100%"
>
<div v-if="!!this.token">
<ymap-marker
v-for="(marker, index) in markers"
:key="index"
:markerId="index"
:name="marker.street"
ref="myMarker"
:coords="marker.coords"
:street="marker.street"
:balloon-template="balloonTemplate(selectedMarker)"
#click="onClick"
/>
</div>
<div v-else>
<ymap-marker
v-for="(marker, index) in markers"
:key="index"
:markerId="index"
:name="marker.street"
ref="myMarker"
:coords="marker.coords"
:street="marker.street"
:balloon-template="balloonTemplate1(selectedMarker,dellSelectedMarkerF)"
#click="onClick"
/>
</div>
</yandex-map>
</div>
</template>
<script>
import axios from "axios";
import { mapGetters, mapMutations } from "vuex";
export default {
name: "SimpleMap",
data() {
return {
zoom: 12,
currentCenter: [47.2243657, 38.9105216],
markers: [],
errors: [],
markerIconSVG: require("#/assets/MarkerIcon2.svg"),
controls: [
"typeSelector",
"zoomControl",
"rulerControl",
"geolocationControl",
],
staticAnchor: [16, 37],
staticIconSize: [26, 34],
selectedMarker: {},
dellSelectedMarkerF:()=>{},
token: this.$store.state.isAuthenticated,
};
},
created() {
axios
.get("api/v1/map/markers")
.then((response) => {
for (var marker_info of response.data) {
// var delete_link = "http://tagproject-api.sfedu.ru/api/v1/map/markers/delete/"+marker_info.id
this.markers.push({
id: marker_info.id,
street: marker_info.street,
name: marker_info.name,
description: marker_info.description,
marker_type: marker_info.marker_type,
coords: marker_info.gps.split(","),
image: marker_info.get_image,
});
}
})
.catch((e) => {
this.errors.push(e);
});
},
methods: {
...mapMutations(["verifyRefreshToken"]),
deleteMarker: function(marker_id) {
this.verifyRefreshToken();
axios
.delete(
`https://tagproject-api.sfedu.ru/api/v1/map/markers/delete/${marker_id}`,
{
headers: {
Authorization: `Bearer ${this.$store.state.accessToken}`,
},
}
)
.then((response) => {
console.log(response);
this.$router.go();
})
.catch(function (error) {
console.log(error.response);
});
},
balloonTemplate1: function(selectedMarker) {
return `
<div class="balloon">
<img class="balloon__img" center id="marker-image" src="${selectedMarker.image}" alt="..."/>
<div class="container" style="width: 300px !important">
<div class="balloon__info">
<div class="col-md-12">
<p class="text-center">${selectedMarker.street}</p>
</div>
</div>
</div>
</div>`;
},
balloonTemplate: function(selectedMarker) {
return `
<div class="balloon">
<img class="balloon__img" center id="marker-image" src="${selectedMarker.image}" alt="..."/>
<div class="container" style="width: 300px !important">
<div class="balloon__info">
<div class="col-md-12">
<p class="text-center">${selectedMarker.street}</p>
<div class="d-flex justify-content-center">
<br><br>
<b-button id="${selectedMarker.id}" class="delete-marker-button" variant="outline-danger" onClick="${this.deleteMarker(this.selectedMarker.id)}">Удалить маркер</b-button>
</div>
</div>
</div>
</div>
</div>
`
},
onClick(e) {
this.selectedMarker =this.markers[e.originalEvent.target.properties._data.markerId]
}
},
computed: {
...mapGetters(["isLoggedIn"]),
},
};
</script>
<style type="text/css">
.balloon__info {
margin-top: 10px;
}
.balloon {
display: flex;
flex-direction: column;
align-items: center;
}
.balloon__img {
max-height: 250px;
max-width: 250px;
}
.ymaps-2-1-79-balloon,
.ymaps-2-1-79-balloon__layout {
border-radius: 20px !important;
border: 0;
}
.ymaps-2-1-79-balloon__layout {
padding: 10px;
}
</style>
I tried to throw the function through
document.getelementsbyclassname("delete-marker-button").onclick(()=>,,,,)
also tried various manipulations of the rollover function.
I thought to approach from the side of event.preventDefault(); , but all to no avail

How to display all icons from icons folder in vuejs

Created a small project with vuejs and want to display all my icons but for some reason it does not displays my icons, Can anyone tell me where I am making the mistakes.
I want to display all my icons from that icons list in the div element.
Any help will be much appreciated, thanks!
ValidatingProps.vue
<template>
<div>
<h1>How to use Validation in props</h1>
<h3>{{ status }}</h3>
<div class="icons" v-html="icons"></div>
</div>
</template>
<script>
import icons from "./icons";
console.log(icons);
export default {
name: "validatingProps",
props: {
status: {
type: String,
default: "Validating",
validator: (value) => {
console.log("Val", value);
return ["in-progress", "complete"].includes(value);
},
},
icons: {
type: String,
required: true,
validator: (value) => {
console.log("Value >>>> ", value);
Object.keys(icons).includes(value);
console.log("Icons props: ", Object.keys(icons).includes(value));
},
},
},
mounted() {
console.log("mounted ", Object.keys(icons));
console.log("this.Icons: ", this.icons);
},
};
</script>
<style scoped>
.icons {
height: 200px;
width: 200px;
border: 2px solid red;
margin: 0 auto;
background: lightcyan;
}
App.vue
<div>
<template>
<ValidatingProps
status="progress"
:icons="Object.keys(this.icons.default)"
/>
</div>
</template>
<script>
import ValidatingProps from "./components/validatingProps.vue";
import * as icon from "./components/icons/";
export default {
name: "App",
components: {
ValidatingProps,
},
data() {
return {
icons: icon,
}
}
</script>
my icons folder structure:
My Div box shows:

How can I duplicate my component in vue.js?

<template>
<!--This is my main file -->
<div id="inputs">
<h1>언어 관리</h1>
<v-btn color="primary" elevation="10" large #click="duplicateEl"
>Add row</v-btn
>
<Contents />
</div>
</template>
<script>
import Contents from "./Contents.vue";
export default {
name: "LanguageMainMenu",
components: { Contents },
methods: {
duplicateEl() {
alert("You can duplicate buttons");
},
},
};
</script>
<style>
h1 {
text-align: center;
font-size: 38px;
padding-top: 20px;
margin: auto;
}
</style>
The best apprach is to use the component inside v-for.
Increment the index when the button is clicked.
Dont forget to use key inside the v-for
Working Fiddle
var example1 = new Vue({
el: '#app',
name: "LanguageMainMenu",
components: {
Contents: {
template: `<div>Contents Component</div>`,
}
},
data() {
return {
totalCount: 1,
}
},
methods: {
duplicateEl() {
this.totalCount++;
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<div id="app">
<!--This is my main file -->
<div id="inputs">
<h1>언어 관리</h1>
<button #click="duplicateEl">Add row</button>
<Contents v-for="count in totalCount" :key="`component-${count}`" />
</div>
</div>
You can add a property in data object and use v-for for render buttons.
Let method duplicateEl to change the property value.
<v-btn v-for="item in btnNumber" ....>
duplicateEl(){
this.btnNumber++
}

Vue doesn't recognize my components, am I registering them wrong?

I'm working on a basic blog app in Laravel using Vue.js. I've created custom components, registered them in my app.js file, and referred to them in the views by their component names. But I'm getting this error on load:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in )
Can anyone spot what I'm doing wrong? Here is my code:
CreatePost.vue:
<template>
<div class="card mt-4" :key="componentKey">
<div class="card-header">New Post</div>
<div class="card-body">
<div v-if="status_msg" :class="{ 'alert-success': status, 'alert-danger': !status }" class="alert" role="alert">
{{ status_msg }}
</div>
<form>
<div class="form-group">
<label for="exampleFormControlInput1">Title</label>
<input v-model="title" type="text" class="form-control" id="title" placeholder="Post Title" required />
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">Post Content</label>
<textarea v-model="post_body" class="form-control" id="post-content" rows="3" required></textarea>
</div>
<div class>
<el-upload action="https://jsonplaceholder.typicode.com/posts/" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-change="updateImageList" :auto-upload="false">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
</div>
</form>
</div>
<div class="card-footer">
<button type="button" #click="createPost" class="btn btn-success">{{ isCreatingPost ? "Posting..." : "Create Post" }}</button>
</div>
</div>
</template>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
<script>
import { setTimeout } from "timers";
import { mapState, mapActions } from "vuex";
export default {
name: "create-post",
props: ["posts"],
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
imageList: [],
status_msg: "",
status: "",
isCreatingPost: false,
title: "",
post_body: "",
componentKey: 0
};
},
computed: {},
mounted() {},
methods: {
...mapActions(["getAllPosts"]),
updateImageList(file) {
this.imageList.push(file.raw);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.imageList.push(file);
this.dialogVisible = true;
},
createPost(e) {
e.preventDefault();
if (!this.validateForm()) {
return false;
}
const that = this;
this.isCreatingPost = true;
let formData = new FormData();
formData.append("title", this.title);
formData.append("post_body", this.post_body);
$.each(this.imageList, function(key, image) {
formData.append(`images[${key}]`, image);
});
api.post("/post/create_post", formData, { headers: { "Content-Type": "multipart/form-data" }})
.then(res => {
this.title = this.post_body = "";
this.status = true;
this.showNotification("Post Successfully Created");
this.isCreatingPost = false;
this.imageList = [];
/* "that", defined above, used here instead of "this" to avoid conflict issues */
that.getAllPosts();
that.componentKey += 1;
});
},
validateForm() {
if (!this.title) {
this.status = false;
this.showNotification("Post title cannot be empty");
return false;
}
if (!this.post_body) {
this.status = false;
this.showNotification("Post body cannot be empty");
return false;
}
return true;
},
showNotification(message) {
this.status_msg = message;
setTimeout(() => {
this.status_msg = "";
}, 3000);
}
}
};
</script>
app.js:
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
import store from './store/index';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('all-posts', require('./components/AllPosts.vue').default);
Vue.component('create-post', require('./components/CreatePost.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
store,
el: '#app',
});
posts.blade.php:
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-6">
<create-post />
</div>
<div class="col-md-6">
<all-post />
</div>
</div>
</div>
#endsection
Your component must be wrapped in an element with the id "app".
<div id="app">
<all-posts />
</div>
make sure that somewhere in your posts.blade or layouts.app you have this element surrounding the code that includes your component
Try to import the components and let your Vue instance know that there are custom components. In CreatePost.vue:
import { elUpload, elDialog } from '...'; // path to your components or lib
...
export default {
...
components: {
elUpload,
elDialog,
}
...
}

Vue.js: Collapse/expand all elements from parent

I need to add "expand/collapse all" functionality for my Vue component(some collapsible panel).
If user clicks collapse button then clicks on some panel and expand it then clicking on collapse button will do nothing because watched parameter will not change.
So how to implement this functionality properly (buttons must collapse and expand components always)?
I prepared simple example(sorry for bad formatting, it looks nice in editor :( ):
var collapsible = {
template: "#collapsible",
props: ["collapseAll"],
data: function () {
return {
collapsed: true
}
},
watch: {
collapseAll: function(value) {
this.collapsed = value
}
}
}
var app = new Vue({
template: "#app",
el: "#foo",
data: {
collapseAll: true
},
components: {
collapsible: collapsible
}
});
.wrapper {
width: 100%;
}
.wrapper + .wrapper {
margin-top: 10px;
}
.header {
height: 20px;
width: 100%;
background: #ccc;
}
.collapsible {
height: 100px;
width: 100%;
background: #aaa;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="foo"></div>
<script type="text/x-template" id="collapsible">
<div class="wrapper">
<div class="header" v-on:click="collapsed = !collapsed"></div>
<div class="collapsible" v-show="!collapsed"></div>
</div>
</script>
<script type="text/x-template" id="app">
<div>
<button v-on:click="collapseAll = true">Collapse All</button>
<button v-on:click="collapseAll = false">Expand All</button>
<collapsible v-for="a in 10" v-bind:collapseAll="collapseAll" v-bind:key="a"></collapsible>
</div>
</script>
Thanks!
This is a case where I might use a ref.
<button v-on:click="collapseAll">Collapse All</button>
<button v-on:click="expandAll">Expand All</button>
<collapsible ref="collapsible" v-for="a in 10" v-bind:key="a"></collapsible>
And add methods to your Vue.
var app = new Vue({
template: "#app",
el: "#foo",
methods:{
collapseAll(){
this.$refs.collapsible.map(c => c.collapsed = true)
},
expandAll(){
this.$refs.collapsible.map(c => c.collapsed = false)
}
},
components: {
collapsible: collapsible
}
});
Example.

Categories