Hello I have question regarding passing data to modal component using standalone Vue js.
The flow is user click on the button that 'select a country' and modal opens up and user can select a country with slider. once user clicked on confirm, modal closes.
I've tried using for loops to pass the data into modal components but it also prints out many buttons.
Thank you for your help
I have a HTML code that user can select a countries
<div class="select_championship_country" #click="enableCountryModal()">Select a country</div>
<modal v-if="showCountryModal" #close="showModal = false"></modal>
Here is the modal component code:
<!-- countury modal -->
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
select the country you want to support
</slot>
</div>
<div class="modal-body">
<slot name="body">
<div class="country_select_carousel">
<div class="countrySlide">
<!-- <img :src="imgUrl + '/flags/' + item.imgName"> -->
</div>
</div>
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<div class="modal-default-button" #click="$emit('close')">
confirm
</div>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
This is country data array object and modal component
new Vue({
el: '#root',
components: {
modal: {
template: '#modal-template',
}
},
data: {
country_carousel_data: [
{
imgName: 'brasil.svg',
desc: 'brasil',
},
{
imgName: 'canada.svg',
desc: '',
},
{
imgName: 'egypt.svg',
desc: '',
},
{
imgName: 'france.svg',
desc: '',
},
{
imgName: 'germany.svg',
desc: '',
},
{
imgName: 'india.svg',
desc: '',
},
{
imgName: 'poland.svg',
desc: '',
},
{
imgName: 'portugal.svg',
desc: '',
},
{
imgName: 'tunisia.svg',
desc: '',
},
{
imgName: 'turkey.svg',
desc: '',
},
{
imgName: 'uk.svg',
desc: '',
},
{
imgName: 'usa.svg',
desc: '',
},
],
}
Where did you use the for-loop in your modal template? I do not see any v-for.
Your should not be inside for loop. I am guessing since you mentioned it prints out many buttons you had that inside the for loop. the v-for should be on the tag like below
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
select the country you want to support
</slot>
</div>
<div class="modal-body">
<slot name="body">
<div class="country_select_carousel">
<div class="countrySlide">
<img v-for="item in country_carousel_data" :src="imgUrl + '/flags/' + item.imgName">
</div>
</div>
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<div class="modal-default-button" #click="$emit('close')">
confirm
</div>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
Related
<template>
<b-form #submit.prevent="Submit" class="mb-5">
<div class="inputArea" v-for="input in inputs" :key="input.id">
<b-form-group label-cols-sm="2" label="Solution (EN)">
<ckeditor :editor="ckeditor" v-model="form.body.en" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.en']">
<div v-for="err in errors['body.en']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (FR)">
<ckeditor :editor="ckeditor" v-model="form.body.np" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.np']">
<div v-for="err in errors['body.np']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (IT)">
<ckeditor :editor="ckeditor" v-model="form.body.in" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.in']">
<div v-for="err in errors['body.in']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
</div>
<b-form-group label="" label-cols-sm="2">
<b-button type="button" class="text-white" variant="dark" #click="addRow">Add row</b-button>
</b-form-group>
<b-form-group label="" label-cols-sm="2">
<b-button type="submit" class="text-white" variant="dark">Submit</b-button>
</b-form-group>
</b-form>
</template>
<style lang="scss">
</style>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue2'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic'
export default {
name: 'Interaction',
components: {
ckeditor: CKEditor.component
},
data(){
return{
counter: 0,
inputs: [
{
en: '',
np: '',
in: '',
}],
form: {
body: [
{
en: '',
np: '',
in: '',
}
],
},
errors: {},
ckeditorData: '<p></p>',
ckeditorConfig: {
// The configuration of the editor
},
ckeditor: ClassicEditor
}
},
methods: {
Submit(){
this.storing = true
this.errors = {}
var self = this
axios.post('/this-is-a-post-url', this.form)
.then(function(response){
console.log(response)
})
},
addRow() {
this.inputs.push({
en: '',
it: '',
fr: '',
id: `${++this.counter}`,
value: '',
});
}
}
}
</script>
I will have array coming in the body name so I am trying to to clone the clone body on a click of a button which has a function AddRow. I want to clone the three fields en,np,in and I want it work like normal html works in this. Example when we clone html form it create input field like so <input name="body['en'][0]"> and when we clone another time it creates something like this <input name="body['en'][1]">.
I have the above code, it clones the body but it also clones the added text before cloning. I want to add an empty field while cloning and also want to update v-model. How can I do that?
Refer below example:
https://codepen.io/telen/pen/OeNZVV
<main class="container">
<form id="app" data-apartments='[{ "price": "23000", "rooms": "12" }, { "price": "42000", "rooms": "32" }]'>
<h1>
Dynamic apartment forms
</h1>
<hr>
<div class="row">
<div class="col-xs-2">
<button type="button" v-on:click="addNewApartment" class="btn btn-block btn-success">
Add +
</button>
</div>
<div class="col-xs-10">
Would you like add more apartments?
</div>
</div>
<div v-for="(apartment, index) in apartments">
<div class="row">
<div class="col-xs-2">
<label> </label>
<button type="button" v-on:click="removeApartment(index)" class="btn btn-block btn-danger">
Rem -
</button>
</div>
<div class="form-group col-xs-5">
<label>Price (HUF)</label>
<input v-model="apartment.price" type="number"
name="apartments[][price]" class="form-control" placeholder="Price">
</div>
<div class="form-group col-xs-5">
<label>Rooms (PCS)</label>
<input v-model="apartment.rooms" type="number"
name="apartments[][rooms]" class="form-control" placeholder="Rooms">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" v-on:click.prevent="sumbitForm" class="btn btn-block btn-primary">
Submit
</button>
</div>
<div class="col-xs-10">
Open the console (F12) and see the result
</div>
</div>
<hr>
<pre>{{ $data }}</pre>
</form>
JS:
window.app = new Vue({
el: '#app',
data: {
apartment: {
price: '',
rooms: ''
},
apartments: [],
},
mounted: function () {
/*
* The "data-apartments" could come from serverside (already saved apartments)
*/
this.apartments = JSON.parse(this.$el.dataset.apartments)
},
methods: {
addNewApartment: function () {
this.apartments.push(Vue.util.extend({}, this.apartment))
},
removeApartment: function (index) {
Vue.delete(this.apartments, index);
},
sumbitForm: function () {
/*
* You can remove or replace the "submitForm" method.
* Remove: if you handle form sumission on server side.
* Replace: for example you need an AJAX submission.
*/
console.info('<< Form Submitted >>')
console.info('Vue.js apartments object:', this.apartments)
window.testSumbit()
}
}
})
/*
* This is not Vue.js code, just a bit of jQuery to test what data would be submitted.
*/
window.testSumbit = function () {
if (!window.jQuery) {
console.warn('jQuery not present!')
return false
}
console.info('Submitted (serverside) array:', jQuery('form').serializeJSON())
}
overview
Currently, the created new.vue and edit.vue have similar form parts, so I would like to make them common and componentized.
Therefore, I would like to create a new form.vue and display the page in the form of calling it.
However, when I made it into a component, the page disappeared.
(There is no such description in the log, and there is no error display in Console)
I think the data transfer isn't working, but I'm not sure where to fix it.
I would appreciate it if you could tell me how to fix it.
Original code before componentization
New.vue
<template>
<main>
<form>
<section>
<div>
<div>
<fieldset>
<div class="form-row">
<div class="form-group col-3">
<label>タイトル</label>
<input v-model="latest_information.title" type="text">
</div>
<div class="form-group col-3">
<label>詳細</label>
<input v-model="latest_information.detail" type="text">
</div>
</div>
</fieldset>
</div>
</div>
</section>
<div class="btn-container d-flex justify-content-center">
<button class="button-square btn-send" type="button" #click="createLatestInformation">保存する</button>
</div>
</form>
</main>
</template>
<script>
export default {
data() {
return {
latest_information: {
title: '',
detail: '',
},
}
},
methods: {
createLatestInformation() {
this.$loading.load(this.$auth.api.post('admin/latest_informations/', {
latest_information: this.latest_information
})
.then(response => {
this.$router.push({name: 'AdminLatestInformationIndex'})
}))}
},
}
</script>
Code after componentization (not behaving well)
New.vue
<template>
<form :latest_information="latest_information" #click="createLatestInformation"></form>
</template>
<script>
import Form from './Form.vue';
export default {
components:{
Form
},
data() {
return {
latest_information: {
title: '',
detail: '',
},
}
},
methods: {
createLatestInformation() {
this.$loading.load(this.$auth.api.post('admin/latest_informations/', {
latest_information: this.latest_information
})
.then(response => {
this.$router.push({name: 'AdminLatestInformationIndex'})
}))}
},
}
</script>
Form.vue
<template>
<main>
<form>
<section>
<div>
<div>
<fieldset>
<div class="form-row">
<div class="form-group col-3">
<label>タイトル</label>
<input v-model="latest_information.title" type="text">
</div>
<div class="form-group col-3">
<label>詳細</label>
<input v-model="latest_information.detail" type="text">
</div>
</div>
</fieldset>
</div>
</div>
</section>
<div class="btn-container d-flex justify-content-center">
<button class="button-square btn-send" type="button" #click="$emit('click')">保存する</button>
</div>
</form>
</main>
</template>
<script>
export default {
props: {
latest_information: {
title: '',
detail: '',
},
}
}
</script>
<style>
</style>
Environment
rails 6
vue#2.6.10
form was a reserved word.Changed to tform.
<template>
<tform :latest_information="latest_information" #click="createLatestInformation"></form>
</template>
<script>
import Form from './Form.vue';
export default {
components:{
Tform: Form
},
I have four components Dashboard.vue(parent component) it contains Three child components(DisplayBooks.vue,sortBooksHightoLow,sortBooksLowtoHigh).
Now i want to import one more component called Cart.vue inside the Dashboard.vue .By default only DisplayBooks.vue component is only visible,if i click on cart-icon inside the Dashboard component it displays the Cart.vue component and hides the DisplayBooks.vue component .
How to acheive this thing please help me to fix this thing..
Dashboard.vue
<template>
<div class="main">
<div class="navbar navbar-default navbar-fixed-top">
<div class="navbar-header">
<img src="../assets/education.png" alt="notFound" class="education-image" />
</div>
<ul class="nav navbar-nav">
<li>
<p class="brand">Bookstore</p>
</li>
</ul>
<div class="input-group">
<i #click="handlesubmit();" class="fas fa-search"></i>
<div class="form-outline">
<input type="search" v-model="name" class="form-control" placeholder='search...' />
</div>
</div>
<ul class="nav navbar-nav navbar-right" id="right-bar">
<li><a> <i class="far fa-user"></i></a></li>
<p class="profile-content">profile</p>
<li><a><i class="fas fa-cart-plus"></i></a></li>
<p class="cart-content" >cart <span class="length" v-if="booksCount">{{booksCount}}</span></p>
</ul>
</div>
<div class="mid-body">
<h6>Books<span class="items">(128items)</span></h6>
<select class="options" #change="applyOption">
<option disabled value="">Sort by relevance</option>
<option value="HighToLow">price:High to Low</option>
<option value="LowToHigh">price:Low to High</option>
</select>
</div>
<div v-if="flam==false">
<h2>Hello</h2>
</div>
<DisplayBooks v-show="flag==='noOrder'" #update-books-count="(n)=>booksCount=n"/>
<sortBooksLowtoHigh v-show="flag==='lowToHigh'" />
<sortBooksHightoLow v-show="flag==='highToLow'" />
<Cart />
</div>
</template>
<script>
import sortBooksLowtoHigh from './sortBooksLowtoHigh.vue'
import sortBooksHightoLow from './sortBooksHightoLow.vue'
import DisplayBooks from './DisplayBooks.vue'
import Cart from './Cart.vue'
export default {
components: {
DisplayBooks,
sortBooksLowtoHigh,
sortBooksHightoLow,
Cart
},
data() {
return {
booksCount:0,
flag: 'noOrder',
brand: 'Bookstore',
name: '',
flam: true,
visible: true,
}
},
methods: {
flip() {
this.flam = !this.flam;
},
applyOption(evt) {
if (evt.target.value === "HighToLow") {
this.flag = 'highToLow';
} else this.flag = 'lowToHigh';
},
}
}
</script>
Cart.vue
<template>
<div class="main">
<div v-for="book in books" :key="book.id" class="container">
<div class="content">
<h5>My Cart({{booksCount}})</h5>
</div>
<div class="mid-section">
<img v-bind:src="book.file" alt="not found">
<p class="title-section">{{book.name}}</p>
</div>
<div class="author-section">
<p>by {{book.author}}</p>
</div>
<div class="price-section">
<h6>Rs.{{book.price}}</h6>
</div>
<button class="close-btn" #click="handlesubmit();" type="submit">close</button>
<div class="btn-grps">
<button class="btn" type="submit" >Place Order</button>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default{
data(){
return {
booksCount:0,
books: [{
id: 0,
file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
name: 'Dont Make me think',
author: 'Sai',
price: '1500'
},]
}
},
methods:{
}
}
</script>
It's recommended to use vur-router, but for a simple situation you could define a property called shownComp then update when you click on cart icon :
data() {
return {
shownComp:'DisplayBooks',
booksCount:0,
flag: 'noOrder',
then <li #click="shownComp='Cart'"><a><i class="fas fa-cart-plus"></i></a></li>
and :
<DisplayBooks v-show="flag==='noOrder' && shownComp==='DisplayBooks'" #update-books-count="(n)=>booksCount=n"/>
<Cart v-show=" shownComp==='Cart'" />
...
i'm having trouble with the data that being passed to the component.
it will only shows as an object, not the item inside the object. i have
read several questions/answers from here, but i still couldn't make it works.
when i try {{ modalData.projectName }} (in child), it will show this error in console " Error in render: "TypeError: _vm.modalData is null" "
here are my codes:
parent
<template>
<section id="portFolio">
<div class="row">
<div
v-for="project in projects"
v-bind:key="project.id"
class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-xl-3"
>
<a type="button" data-toggle="modal" data-target="#exampleModal" v-on:click="openModal(project)">
<div class="project-block">
<!-- Image -->
<div class="image-preview">
<img src="/dist/img/logo-test.png" class="img-fluid" alt="Twitter">
</div>
<!-- Details -->
<div class="project-details p-t-10 p-b-10 p-l-10 p-r-10">
<div class="">
<h5 class="text-purple m-b-5">{{ project.projectName }}</h5>
<p class="text-dark">{{ project.companyName }}</p>
</div>
<p class="subtext text-dark">{{ project.projectYear }}</p>
</div>
</div>
</a>
</div>
</div>
<app-modal ref="modal" v-bind:modalData="selectedItem"/>
</section>
</template>
<script>
// Component
import modalBlock from "./component/portfolio/portfolioModal.vue";
export default{
name: "portFolio",
components: {
'app-modal': modalBlock
},
data() {
return {
// showModal: false,
selectedItem: null,
projectName: '',
companyName: '',
projectYear: null,
previewPic: '',
testText: '',
modalData: '',
projects: [
{
projectName: 'Project One',
companyName: 'CoolCompany Sdn Bhd',
projectYear: 2019,
previewPic: "/dist/img/logo-test.png",
testText: "First object"
},
{
projectName: 'Project Two',
companyName: 'NotSoCompany Sdn Bhd',
projectYear: 2018,
previewPic: "/dist/img/logo-test.png",
testText: "Second object"
},
{
projectName: 'Project Three',
companyName: 'LameCompany Sdn Bhd',
projectYear: 2017,
previewPic: "/dist/img/logo-test.png",
testText: "Third object"
}
]
}
},
methods: {
openModal(modalData) {
this.selectedItem = modalData
let element = this.$refs.modal.$el
$(element).modal('show')
}
}
}
</script>
Child component:
<template>
<div class="modal fade bd-example-modal-xl" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">The title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h2>{{ modalData.projectName }}</h2>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
name: "modalBlock",
props:['modalData'],
data(){
return {
}
},
methods: {
close() {
this.$emit('close');
},
}
}
</script>
may i know where did i done wrong? or Did i forgot to declare something on the code?
thank you
I use this package https://www.npmjs.com/package/vue-sweetalert2 and I want to past vue component in Vue.swal as html.
<template>
<div class="w-full">
<div class="py-6 w-full">
<button
type="button"
class="btn btn-default btn-primary"
#click="openTeamsModal"
>
Teams
</button>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import TeamTable from "./TeamTable";
import VueSweetalert2 from 'vue-sweetalert2';
Vue.use(VueSweetalert2);
export default {
components: {TeamTable},
props: [
'resourceName',
'resourceId',
'field'
],
data: () => ({
teams: [],
}),
methods: {
openTeamsModal() {
Nova.request().get(`/api/competitors/${this.field.seasonId}/${this.field.championshipId}`).then( responce => {
console.log(responce)
});
Vue.swal({
title: 'Test',
html: '<team-table></team-table>',
});
}
},
}
</script>
but there is nothing. I am new to VueJs and I still don’t fully understand how to insert my components as html.
Yes! is possible! ... after hours of research, I have succeeded.
this is the way:
you need to include all the logic of the template between this characters ` `
you will also need edit the vue.config.js file and add inside the configurewebpack object add this: 'vue$':'vue/dist/vue.esm.js'
configureWebpack: {
resolve: {
alias: {
'src': resolveSrc('src'),
'chart.js': 'chart.js/dist/Chart.js',
// add this line for include components inside swal alert
'vue$':'vue/dist/vue.esm.js'
}
Once this is done you must relaunch the project "npm run dev"
This is my complete example, tested and working
openSweet() {
Vue.component('my-comp', {
template: `
<div class="card-content">
<div class="span2">
<div class="col-sm-6 col-md-2 col-lg-3">
<div class="row">
<div style="margin-top: 6px;" >
<p-switch v-model="switchTrip.state" type="primary" on-text="ON" off-text="OFF" style="justify-content:center"></p-switch>
<h5 class="card-title" style="margin-left: 25px;">Recorridos</h5>
</div>
</div>
<div class="row">
<div style="margin-top: 6px;" >
<p-switch v-model="switchVel.state" type="primary" on-text="ON" off-text="OFF" style="justify-content:center"></p-switch>
<h5 class="card-title" style="margin-left: 25px;">Velocidad</h5>
</div>
</div>
</div>
</div>
<div class="span2">
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="row">
<div >
<input type="search" class="form-control input-sm" placeholder="km / h" v-model="vmax">
<h5 class="card-title">Vel. Max</h5>
</div>
</div>
<div class="row">
<div>
<input type="search" class="form-control input-sm" placeholder="minutos" v-model="tol">
<h5 class="card-title">Tolerancia</h5>
</div>
</div>
</div>
</div>
</div>
`,
data () {
return {
switchVel: {
state: false
},
switchEvent: {
state: false
},
switchTrip: {
state: false
},
search: '',
vmax: '',
tol: ''
}
},
components: {
[Button.name]: Button,
Card,
PSwitch
}
})
new Vue({
el: '#modal',
beforeCreate: () => {
swal({
titleText: "Descarga de Reportes",
showCancelButton: true,
cancelButtonText: 'Cancelar',
confirmButtonText: 'Descargar',
// confirmButtonAriaLabel: 'glyphicon glyphicon-ok-sign',
// cancelButtonAriaLabel: 'glyphicon glyphicon-remove-sign',
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
width: 800,
html: '<div id="modal"><my-comp></my-comp></div>'
})
}
})
}
I hope it helps you
Greetings from Argentina
https://github.com/aledc7