In #vue/cli 4.1.1 app I use bootstrap-vue and I have a form with 2 tabs :
on 1st tab several fields and clicking Enter key on any
control my form is submitted as expected, but I have
the second tab with listing of meta keywords and single input control I want clicking
on this control
v-on:keyup.enter.prevent="addMetaKeyword()"
to run update method, but without form submitted, but failed as my form is submitted.
I do like :
<template>
<b-card class="backend_editor_container">
<b-card-header>
<h3 class="row_content_left_aligned p-2" v-show="is_page_loaded">
<i :class="'info_link '+getHeaderIcon('page')"></i>{{ getHeaderTitle }}
</h3>
<div v-show="!is_page_loaded">
<h3>
<b-spinner variant="success" label="Page loading"></b-spinner> Page loading...
</h3>
</div>
</b-card-header>
<b-card-body v-show="is_page_loaded">
<div>
<b-tabs content-class="mt-3" justified>
<b-tab
title="Details"
>
<ValidationObserver
ref="pageObserverForm"
v-slot="{handleSubmit}"
>
<b-form #submit.prevent="handleSubmit(onSubmit)">
<b-row class="editor_row" v-if="!is_insert">
<b-col md="4">
<label for="id" class="pt-2 ">Id:</label>
</b-col>
<b-col md="8">
<b-form-input
id="id"
v-model="pageForm.id"
readonly
class="text-right"
></b-form-input>
</b-col>
</b-row>
...
</b-tab>
<b-tab
title="Meta"
active
>
<fieldset class="bordered text-muted p-0 m-0 mb-4">
<legend class="bordered">Add meta keyword</legend>
<b-row class="editor_row">
<b-col md="4">
<label for="new_meta_keyword" class="pt-2 ">New meta keyword:</label>
</b-col>
<b-col md="8">
<b-form-input
id="id"
v-model="new_meta_keyword"
class="text-left"
v-on:keyup.enter.prevent="addMetaKeyword()"
></b-form-input>
</b-col>
</b-row>
<div class="buttons_container">
<b-button type="button" variant="primary" size="sm" #click.prevent="addMetaKeyword()" class="m-1 ml-4">
<i :class="'info_link '+getHeaderIcon('save')"></i>Add
</b-button>
</div>
</fieldset>
How correct ?
"bootstrap-vue": "^2.3.0",
"vue": "^2.6.11",
Modified BLOCK #1 :
addMetaKeyword() {
this.new_meta_keyword = this.trim(this.new_meta_keyword)
if (this.isEmpty(this.new_meta_keyword)) {
this.showPopupMessage('Page editor', 'Meta keyword can not be empty !', 'warn')
return
}
let l = this.metaKeywordsList.length
for (let i = 0; i < l; i++) {
if (this.metaKeywordsList[i] === this.new_meta_keyword) {
this.showPopupMessage('Page editor', 'This Meta keyword is already defined !', 'warn')
return
}
}
this.metaKeywordsList[this.metaKeywordsList.length] = this.new_meta_keyword
this.new_meta_keyword = null
this.showPopupMessage("Page editor", 'You need to save changes in meta keyword mby clicking on "Update" button !', 'success');
},
Thanks!
The problem is that the keyup event is not preventable. Instead use the keydown event like so <b-input #keydown.enter.prevent="yourMethod"></b-input>, this will run yourMethod without submitting the form.
new Vue({
el: "#app",
methods: {
onSubmit() {
console.log('Form submitted')
},
doOtherStuff(){
console.log('Doing other stuff')
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.4.2/dist/bootstrap-vue.css" rel="stylesheet"/>
<div id='app'>
<b-form #submit.prevent="onSubmit">
<h1>This will submit your form</h1>
<b-input></b-input>
<h1>This wont submit your form</h1>
<b-input #keydown.enter.prevent="doOtherStuff"></b-input>
<!-- Needs the button to handle submit, I'm hiding it in this case -->
<b-btn type="submit" class="d-none"></b-btn>
</b-form>
</div>
Related
I just started learning Vue2.
I use bootstrap accordion.
I want to be able to click the 'hello button' without triggering the 'collapse' event.
How to do this?
<template>
<div class="accordion" id="accordionExample">
<div class="accordion-item" v-for="i in 3" :key="i">
<h2 class="accordion-header" :id="`headingOne${i}`">
<button class="accordion-button"
type="button" data-bs-toggle="collapse"
:data-bs-target="`#collapseOne${1}`"
aria-expanded="true"
:aria-controls="`collapseOne${1}`"
>
Accordion Item #{{ i }}
<button class="btn-primary" #click=test>hello button</button>
</button>
</h2>
<div :id="`collapseOne${i}`" class="accordion-collapse show"
:aria-labelledby="`headingOne${i}`">
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Learn',
methods: {
test () {
console.log('hello')
}
}
}
</script>
You have to make sure that your hello-button is not nested inside the accordion-button. Just put both buttons right next to eachother. You might have to adjust the css to position them properly.
<template>
<div class="accordion" id="accordionExample">
<div class="accordion-item" v-for="i in 3" :key="i">
<h2 class="accordion-header" :id="`headingOne${i}`">
<button class="accordion-button"
type="button" data-bs-toggle="collapse"
:data-bs-target="`#collapseOne${1}`"
aria-expanded="true"
:aria-controls="`collapseOne${1}`"
>
Accordion Item #{{ i }}
</button>
<button class="btn-primary" #click=test>hello button</button>
</h2>
<div :id="`collapseOne${i}`" class="accordion-collapse show"
:aria-labelledby="`headingOne${i}`">
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Learn',
methods: {
test () {
console.log('hello')
}
}
}
</script>
I have a card with form/ I want to place in the center of the page.
Here my layout 'empty':
<template>
<nuxt />
</template>
<script>
export default {
name: 'Empty'
}
</script>
<style></style>
I have next page with form:
<template>
<b-card>
<b-form #submit.stop.prevent="onSubmit">
...
</b-form>
</b-card>
</template>
I get next result:
<body data-gr-c-s-loaded="true">
<div id="__nuxt">
<!---->
<!---->
<div id="__layout">
<div class="card">
<!---->
<!---->
<div class="card-body">
<!---->
<!---->
<form class="">
...
</form>
</div>
<!---->
<!---->
</div>
</div>
</div>
...
</body>
On the screen, it looks like:
But I want to it looks like:
I can't find how to do it. Can you help me?
You can use a combination of bootstrap v4.3 flex utility classes and position utility classes with a sprinkling of custom styling:
<div
class="fixed-top d-flex align-items-center justify-content-center"
style="bottom: 0; overflow-y: auto"
>
<b-card style="max-width: 400px;">
<form>
<b-form-input class="mb-2"></b-form-input>
<b-form-input class="mb-2"></b-form-input>
<b-form-input class="mb-2"></b-form-input>
<b-form-input class="mb-2"></b-form-input>
</form>
</b-card>
</div>
You may need to tweak the above styles a bit.
I'm very new to VueJS and trying to re-engineer an old site into VueJS 2.
My first issue is how to replicate what I did in JQuery, where by:
if component X 'display' is true, then component Y 'display' is false, and vice versa.
Essentially, if I click a button to expand the b-collapse "cccollapse" element, then I want the "szcollapse" element to collapse (if it is expanded) and vice versa, so only one of those collapsible elements is "extended" at a given point in time.
I'm using bootstrap-vue in my Vue project and this is what the current template looks like this:
<template>
<div>
<b-container fluid class="button-row">
<fieldset>
<legend class="scheduler-border">
<span class="legend-label">YOU : MANAGE YOUR KEYS</span>
</legend>
<b-row class="menu-row">
<b-col>
<b-button variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-plus-circle"></i>REQUEST A KEY</b-button>
</b-col>
</b-row>
<b-row class="menu-row">
<b-col>
<b-button v-b-toggle.szcollapse v-on:click="collapseCCCollapse" variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-share-square"></i>ISSUE A KEY</b-button>
<b-collapse ref="szcollapse" id="szcollapse" class="mt-2">
<b-container class="container-sz-login">
<b-row class="cred-dropdown">
<b-col>
<b-input-group>
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-user-circle fa-fw"></i>
</span>
<b-form-input id="txtUsername" />
</b-input-group>
</b-col>
</b-row>
<b-row class="cred-dropdown">
<b-col>
<b-input-group>
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-lock fa-fw"></i>
</span>
<b-form-input type="password" id="txtPassword" />
</b-input-group>
</b-col>
</b-row>
<b-row class="cred-dropdown">
<b-col cols="2"/>
<b-col cols="8">
<b-button variant="primary" id="szlogin" size="lg" block >LOGIN<i style="padding-left:5px;" class="fas fa-sign-in-alt"></i></b-button>
</b-col>
<b-col cols="2"/>
</b-row>
</b-container>
</b-collapse>
</b-col>
</b-row>
<b-row class="menu-row">
<b-col>
<b-button v-b-toggle.cccollapse v-on:click="collapseSZCollapse" variant="primary" size="lg" block class="text-left button-custom"><i style="padding-right:10px;padding-left:30%;" class="fas fa-network-wired"></i>MANAGE YOUR KEYS</b-button>
<b-collapse ref="cccollapse" id="cccollapse" class="mt-2" v-model="showCollapse">
<b-container class="container-sz-login">
<b-row class="cred-dropdown">
<b-col>
<b-input-group>
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-user-circle fa-fw"></i>
</span>
<b-form-input id="txtCorpId"/>
</b-input-group>
</b-col>
</b-row>
<b-row class="cred-dropdown">
<b-col>
<b-input-group>
<span class="input-group-text" id="basic-addon1">
<i class="fas fa-lock fa-fw"></i>
</span>
<b-form-input type="password" id="txtCorpPwd"/>
</b-input-group>
</b-col>
</b-row>
<b-row class="cred-dropdown">
<b-col cols="2"/>
<b-col cols="8">
<b-button variant="primary" id="ccLogin" size="lg" block >LOGIN<i style="padding-left:5px;" class="fas fa-sign-in-alt"></i></b-button>
</b-col>
<b-col cols="2"/>
</b-row>
</b-container>
</b-collapse>
</b-col>
</b-row>
</fieldset>
</b-container>
</div>
</template>
And this is the script:
<script>
export default {
name: "Menu",
props: {
msg: String
},
methods: {
collapseSZCollapse : function() {
console.log('this.$refs.szcollapse : ' + this.$refs.szcollapse.collapsed);
},
collapseCCCollapse : function() {
console.log('this.$refs.cccollapse : ' + this.$refs.cccollapse.collapsed)
}
},
data() {
return {
showCollapse: false
};
}
};
</script>
Obviously the script isnt really doing anything in the methods -- i'm just trying to see how to get the value of the current element to make a decision when v-on:click is called.
What is the correct VueJS way of doing this? I understand (sort of) that vuejs is data driven, but I'm not sure how to get the data from one element to drive the state of the other.
Sigh. If I had actually investigated properly...
https://bootstrap-vue.js.org/docs/components/collapse/#accordion-support
This does exactly what I want.
Still happy to hear other programmatic answers if there are any?
You can give your b-collapse element a v-model binding. Here's a jsfiddle showing an example.
new Vue({
el: "#app",
data: {
firstCollapsed: true,
secondCollapsed: false
},
methods: {
alternateCollapse() {
if (this.firstCollapsed) {
this.firstCollapsed = false;
this.secondCollapsed = true;
} else {
this.firstCollapsed = true;
this.secondCollapsed = false;
}
}
}
});
<div id="app">
<b-collapse v-model="firstCollapsed" id="collapse1">
<div>Inner Element 1</div>
</b-collapse>
<b-collapse v-model="secondCollapsed" id="collapse2">
<div>Inner Element 2</div>
</b-collapse>
<b-btn #click="alternateCollapse()">Alternate Collapse</b-btn>
</div>
<style scoped>
.collapse {
margin: 5px;
padding: 5px;
background-color: lightgray;
}
#collapse1 {
border: 1px solid red;
}
#collapse2 {
border: 1px solid blue;
}
</style>
in my case i create dynamic form (like todo app) in another components. i want accesibility for other actions. therefore i must set id or number each created element(div). when i add increment method console shows duplicate key error.
how can i add number or id each element?
For examples: this is 1. created element,
this is 2. created element,
this is 3. created element,
some codes:
methods: {
...mapActions(["setAdList"]),
ilanVer() {
this.alert = true;
let adListObj = {
adName: this.adName,
text: this.text,
province: this.province,
education: this.education,
solder: this.solder,
id: this.id
}
this.setAdList(adListObj);
this.id += 1;
console.log(this.id)
},
}
<template>
<!-- eslint-disable max-len -->
<div class="ad-box">
<h1 class="d-flex justify-content-center align-items-center mt-2">İlanlarım</h1>
<hr />
<div class="ilan-list">
<b-card :title=item.adName v-for="(item) in adList" :key="item.id" class="border border-info rounded w-50">
<b-badge class="ml-3">{{item.id}}</b-badge>
<p class="card-text">Aday Özellikleri: <span class="text-center">{{item.text}}</span> </p>
<p class="card-text">Şehir: {{item.province}}</p>
<p class="card-text">Eğitim: {{item.education}}</p>
<p class="card-text">Askerlik: {{item.solder}}</p>
<router-link to="/ilandetayi/:id">
<b-button class="btn-outline-success mr-2">İlanlarıma Git</b-button>
</router-link>
</b-card>
<hr />
</div>
</div>
</template>
You can use index when using v-for directive
In your case
v-for="(item, index) in adList" and then inside the block index will have values 0, 1, 2, ....
You can use Index item of v-for to define the unique id
v-for="(item, index) in adList" :key="index"
<template> <!-- eslint-disable max-len --> <div class="ad-box">
<h1 class="d-flex justify-content-center align-items-center mt-2">İlanlarım</h1>
<hr />
<div class="ilan-list">
<b-card :title=item.adName v-for="(item, index) in adList" :key="index" class="border border-info rounded w-50">
<b-badge class="ml-3">{{item.id}}</b-badge>
<p class="card-text">Aday Özellikleri: <span class="text-center">{{item.text}}</span> </p>
<p class="card-text">Şehir: {{item.province}}</p>
<p class="card-text">Eğitim: {{item.education}}</p>
<p class="card-text">Askerlik: {{item.solder}}</p>
<router-link to="/ilandetayi/:id">
<b-button class="btn-outline-success mr-2">İlanlarıma Git</b-button>
</router-link>
</b-card>
<hr />
</div> </div> </template
> Blockquote
I am creating an interactive Timeline in Vue.js and have a base code set up. What currently happens is when you select a year, content shows up but to make it disappear you need to click it again.
What I am trying to do is make the content of the previous year disappear when you click another year.
The Codepen I created is linked below:
Vue JS Timeline
As you can see, my Vue JS code has different set ups for showing the data.
var vue = new Vue({
el:"#app",
data: {
nowShowing: false,
nowShowing2: false,
nowShowing3: false,
nowShowing4: false,
isShowing:false,
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
}});
Then going into the HTML you have a button class
<button class="c-History__year" #click="isShowing ^= true">1880</button>
And the div class:
<div v-show="isShowing">
<p class="c-History__summary">
{{message}}
</p>
</div>
Is this possible to complete in Vue with transitioning or would CSS suffice?
I've bundled all the isShowing variables into just one and the divs are now looking for whether the isShowing var has a specific number and when does, the div will be shown and all others will be hidden.
JS:
const vue = new Vue({
el:"#app",
data: {
showing: -1,
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
},})
HTML:
<div id="app">
<div class="o-Container o-Container--padded">
<div class="c-History">
<div class="c-History__timeline">
<div class="c-History__years">
<span class="c-History__line"></span>
<button class="c-History__year" #click="showing = 0">1880</button>
<button class="c-History__year" #click="showing = 1">1938</button>
<button class="c-History__year" #click="showing = 2">1971</button>
<button class="c-History__year" #click="showing = 3">1982</button>
<button class="c-History__year" #click="showing = 4">2007</button>
</div>
</div>
</div>
<transition name="bounce">
<div v-show="showing == 0">
<p class="c-History__summary">
{{message}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 1">
<p class="c-History__summary">
{{message2}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 2">
<p class="c-History__summary">
{{message3}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 3">
<p class="c-History__summary">
{{message4}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 4">
<p class="c-History__summary">
{{message5}}
</p>
</div>
</transition>
</div>
</div>
</div>
You can do it with a different a simpler approach, first you can change your data structure like this:
var vue = new Vue({
el:"#app",
data: {
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
contentToShow: ''
},
methods: {
showContent(messageIndex) {
this.contentToShow = this[messageIndex]
}
}
})
the idea is to have a method where you are going to pass the index of message property, and set only one visible contentToShow
So your component updated will be
<div id="app">
<div class="o-Container o-Container--padded">
<div class="c-History">
<div class="c-History__timeline">
<div class="c-History__years">
<span class="c-History__line"></span>
<button class="c-History__year" #click="showContent('message')">1880</button>
<button class="c-History__year" #click="showContent('message2')">1938</button>
<button class="c-History__year" #click="showContent('message3')">1971</button>
<button class="c-History__year" #click="showContent('message4')">1982</button>
<button class="c-History__year" #click="showContent('message5')">2007</button>
</div>
</div>
</div>
<transition name="bounce">
<div v-show="contentToShow">
<p :key="contentToShow" class="c-History__summary">
{{contentToShow}}
</p>
</div>
</transition>
</div>
</div>
</div>