Don't see div with v-if, regardless of the value in the data - vue.js

I have problem with displaying component with v-if.
In one component i have <div v-if="seen">...</div>.
In another component I have <button v-on:click="seen = !seen">...</button>.
In "var vue = nev Vue({...})" file, in data: I have seen: true and this is not working.
I found "solution" which works: example
and I tried this "function version" of data in my code, but it doesn't work too :/
Here is my code:
Main File
var vue = new Vue({
el: '#app',
components: {
Navigation,
Home,
Footer,
Login
},
data: function () {
return {
seen: true
}
},
template: "<div><navigation></navigation><login></login><home></home><Footer></Footer></div>"
})
template that I can't see
<div v-if="seen" id="loginbox">
<form>
<input type="text" placeholder="login" class="input is-rounded"/>
<input type="password" placeholder="password" class="input is-rounded"/>
</form>
</div>
button template
<div class="navbar-menu">
<div class="navbar-start"></div>
<div class="navbar-end">
<p class="nav-item">
<a class="nav-link" v-on:click="seen = !seen">Login</a>
</p>
<p class="nav-item">
<a class="nav-link">Register</a>
</p>
</div>
</div>
I expect that when I click on button, "loginbox" template will be shown.
EDIT:
I did it in half way. I used props (used export default...) in in template that I cannot seen. It not work properly, becouse now I can change value of "seen" only with button which is in this template. I'd like change value of it by button which is in another template.

You should somehow share data between components.
You can do it many ways, but for this case i suggest to use event handling https://v2.vuejs.org/v2/guide/events.html#ad
Edited your sandbox with example - https://codesandbox.io/s/mzq0r2w88j

Related

Bootstrap-Vue Modal: How to open different modals in an V-For rendered list?

I am using Bootstrap-Vue Modals to open an "Edit" modal when clicking the "Edit" button that is attached to each item I have rendered in a list from v-for rendered list.
Each time, however, when I click on the edit button, it opens all of the modals, stacked on top of eachother with the last element in the list being the top modal.
How can I specify it to only open the modal/information for the item that is clicked to be edited?
//Parent Component
<div class="dataList">
<div v-bind:key="item.id" v-for="item in this.$store.getters.data">
<Child v-bind:item="item"></Child>
</div>
</div>
//Child Component
<div>
{{this.item.name}}
{{this.item.details}}
{{this.item.completedBy}}
{{this.item.status}}
<button v-b-modal.modal-1>Edit</button>
<button v-on:click="deleteItem">Delete</button>
<div>
<b-modal id="modal-1" title="BootstrapVue">
<form #submit="editItem">
<input v-model="name">
<input v-model="details">
<input v-model="completedBy">
<select v-model="status">
<option>Fail</option>
<option>Warn</option>
<option>Pass</option>
</select><br>
<input type="submit" value="Submit" #click="$bvModal.hide('modal-1')">
</form>
</b-modal>
</div>
</div>
Now each modal shows the correct information (like the proper name, details, status, etc), but I just need it only the specific modal.
I imagine it has something to do with the 'v-b-modal.modal-1' but I'm not sure how to dynamically set the id of each modal...is there a way to easily set each modal id to match the item.id?
Here is the documentation for Bootstrap-Vue Modals, but I wasn't to find what I needed.
I'd recommend moving the <b-modal> out of your v-for.
This way you only have one.
Then you instead set the user/item you want to edit to a variable, and utilize that in your modal to show the data for the selected user.
Example
new Vue({
el: "#app",
data() {
return {
selectedUser: null,
items: [{
name: "Name 1",
status: "Fail",
details: "Details 1"
},
{
name: "Name 2",
status: "Warn",
details: "Details 2"
}
]
}
},
methods: {
editUser(user) {
this.selectedUser = user;
this.$bvModal.show("edit-modal");
}
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<link href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="//unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app" class="p-4">
<div v-for="item in items" class="mt-3">
{{item.name}} {{item.details}} {{item.status}}
<b-btn variant="primary" #click="editUser(item)">Edit</b-btn>
<b-btn variant="danger">Delete</b-btn>
</div>
<b-modal id="edit-modal" title="Edit User">
<form v-if="selectedUser">
<input v-model="selectedUser.name">
<input v-model="selectedUser.details">
<input v-model="selectedUser.completedBy">
<select v-model="selectedUser.status">
<option>Fail</option>
<option>Warn</option>
<option>Pass</option>
</select><br>
<input type="submit" value="Submit">
</form>
</b-modal>
</div>
If you want to keep the modal inside your v-for, you will have to give it a unique id. If you item has one i would recommend using that, otherwise you can use the index from the v-for.
Simplified example
<div v-for="item in items">
<button v-b-modal:[`edit-modal-${item.id}`]>Edit Item</button>
<b-modal :id="`edit-modal-${item.id}`">
<!-- Modal Content-->
</b-modal>
</div>
One of the most quick way but maybe not the best is Conditional Rendering the modals.
You can toggle the active modal number/index when the Edit is clicked by setting a prop/data/var as activeModal: 1 or n.
Then at the section where you iterate modals you can use v-if directive for modal like: <v-modal v-if="activeModal"> that'd be one way to ignore/not render other modals but would cost re-rendering on each Edit click.
Best/Final solution would be to vue-portal the content to a single universal modal.

Vue / Buefy Datetimpciker: How can I submit the results of an vue compontent to a form?

For my new website project I wanted to use a datetime picker in a html form. As i use Bulma as CSS framework, I want to use the buefy datetimepicker https://buefy.org/documentation/datetimepicker, which is using vue.
For now, the datetimepicker is displayed nicely on my website, however, I am not able to receiving results when submitting the html form by a POST request.
What do I need to change to make the selected datetime available as a variable in php $_POST variable?
Code on codepen
<form action="submit.php" method="POST">
<div id="app" class="container">
<b-field label="Select datetime">
<b-datetimepicker
rounded
placeholder="Click to select..."
icon="calendar-today"
:locale="locale"
:datepicker="{ showWeekNumber }"
:timepicker="{ enableSeconds, hourFormat }"
horizontal-time-picker>
</b-datetimepicker>
</b-field>
</section>
</div>
<div class="field">
<div class="control">
<button class="button is-primary">Submit</button>
</div>
</div>
</form>
<script>
const example = {
data() {
return {
showWeekNumber: true,
enableSeconds: false,
hourFormat: undefined, // Browser locale
locale: undefined // Browser locale
}
}
}
const app = new Vue(example)
app.$mount('#app')
</script>
You should bind datetimepicker to a variable normally with v-model, then assign that variable to a hidden input field.
In HTML file
<input type="hidden" name="mydate" value="{{ mydate }}" />
<b-datetimepicker
v-model="mydate"
...>
</b-datetimepicker>
In JS file
data() {
...,
mydate: null
}

How to show using vue static data into modal?

I have this couple of 'cards' with this content
<div class='card'>
<span>title one </span>
<button #click='open = !open'>show</button>
</div>
<div class='card'>
<span>title two </span>
<button #click='open = !open'>show</button>
</div>
Where in the same component I show this modal. What i need to show inside of it is if I click the first button, show title one, if I click button 2,show title 2 and so on...
What will be the best approach to do this task? (show in modal the card content)
First a couple of things:
ooen might be a typo, did you mean open?
=! looks like a single operator but it actually means open = !open in this context. Put a space between the = and ! to make it clear what it means.
If you want to control the visibility of two sections independently then you will need two separate data properties (open1 and open2). Use v-if or v-show to control the visibility.
new Vue({
el: '#app',
data: {
open1: false,
open2: false,
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="card">
<span v-if="open1">title 1</span>
<button #click="open1 = !open1">toggle</button>
</div>
<div class="card">
<span v-if="open2">title 2</span>
<button #click="open2 = !open2">toggle</button>
</div>
</div>
If you will have lots of these, then wrap the functionality into a separate component so you don't have to define open1, open2, ... and so on.
Vue.component('card', {
template: `
<div class="card">
<span v-if="open"><slot/></span>
<button #click="open = !open">toggle</button>
</div>`,
data() {
return {
open: false
}
}
})
new Vue({
el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<card>title 1</card>
<card>title 2</card>
</div>
I found the solution.
Create the cards data into a array of objects in the data instance
Use a v-for to loop through the cards
Create a method that capture the card clicked, create a projectSelected value in data
<button #click="showModal = !showModal,open(project)">Open</button>
captureProject(card) {
this.projectSelected = project;
},
Show the selected project inside the modal
{{ projectSelected .title }}

Vue.js and Bootstrap Modal - Invoking JS

Trying to implement the bootstrap-datepicker in conjunction with Vue, and not quite sure why my solution won't work.
I am using the code example at https://eonasdan.github.io/bootstrap-datetimepicker/
I added a v-on:click on the INPUT that then ties to a method.
TEMPLATE CODE:
<div class="container">
<div class="row">
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input v-on:click="displayCal" type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</div>
</div>
VUE
import jquery from 'jquery';
....
methods: {
displayCal: function () {
jquery('#datetimepicker1').datetimepicker();
}
}
Will that help with what I'm trying to do?
Not exactly, I misunderstood and thought that the datepicker is a bootstrap component. Unfortunately it is not, and so while vue implementation of bootstrap could be helpful, it would leave you still with quite a bit to implement yourself.
Option 1
Use a Vue component that has the functionality out of the box
const app = new Vue({
el: '#app',
components: {
vuejsDatepicker
}
})
<div id="app">
<vuejs-datepicker></vuejs-datepicker>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuejs-datepicker"></script>
Demo: https://codesandbox.io/s/mpklq49wp
If that does what you need then vuejs-datepicker component may be better for you to implement.
Option 2
Get jquery and Vue to talk
This is not ideal, because the two libraries will compete for DOM control. Vue mounts and unmounts of DOM elements are data driven. That means if your data changes, your DOM may replace an element that jquery may be relying on. SO you may be able to get it to work, but based on all the other stuff going on in the app, you may find some odd things happening, that said, here is a way you can do it...
<div id="app">
<div class="container">
<p>
TIMEDATE: {{timedate}}
</p>
<div class="row">
<div class='col-sm-6'>
<input type='text' class="form-control" id='datetimepicker4' />
</div>
</div>
</div>
</div>
const app = new Vue({
el: '#app',
data(){
return{
timedate: new Date(),
}
},
methods:{
onUpdate(e){
this.timedate=e.date;
}
},
mounted() {
const dp = $('#datetimepicker4')
dp.datetimepicker({
defaultDate: this.timedate,
});
dp.on('dp.change', this.onUpdate )
}
})
demo: https://jsfiddle.net/fjk6cLo8/7/
This code will allow you to add the datetime picker with a preset date. Upon change of the date, using the datetime picker, the data will be updated in the vue component (using dp.change listener)
The datetime picker is mounted once right after the component mounts, and the <input type='text' class="form-control" id='datetimepicker4' /> element is available.

VueJS Modal component inside component

I have a component like this:
<test></test>
I declare this as follows:
Vue.component('test', {
data: {
showModal: true
},
methods: {
displayComponentModalDialog: function() {
this.showModal = true;
}
},
template: `<button #click='displayComponentModalDialog'>test</button>`
});
The <test></test> component is then placed somewhere inside the <div id="#app"> wrapper.
var app = new Vue({
router,
el: '#app',
// etc.
})
Now, I want to display another component inside the test component. So in this case I want a dialog to appear after I click the button in test component. I am not able to achieve this.
What I did is adding a new component:
Vue.component('dialog', {
template: '#dialog-template'
});
And then the following code, although I do not know for sure where to put it.
<!-- template for the modal component -->
<script type="text/x-template" id="dialog-template">
<transition name="dialog">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="btn btn-primary" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<!-- use the modal component, pass in the prop -->
<dialog v-if="showModal" #close="showModal = false">
<h3 slot="header">header</h3>
<p slot="body">
test
</p>
</dialog>
I tried putting this code inside the <test></test> but doesn't work. If I put it inside the template attribute in the component structure, it complains about only one root element.
So it is clear I miss some basic conception how this actually works in VueJS. Someone can help me clarify? Thanks.
As far as I can see your component indeed doesn't have a root tag. Templates have to have a root tag.
This is NOT a valid Vue template:
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
This IS a valid Vue template:
<div>
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
</div>
Note that in the second version we have a single root element for the template, a <div>, whereas in the first one we do not.
You have both a <script></script> and a <dialog></dialog> in your component template.
if you want to add another component in your test component . you can use slot on it.
You can refer to this documentation: https://v2.vuejs.org/v2/guide/components-slots.html
Example:
//component 1
<template>
<div id="modal">
// do something for your modal here.
<slot></slot> // reserve area for your another html or component.
</div>
</template>
// component 2
<template>
<your-modal-component>
<another-component>
</your-modal-component>
</template>