Creating a complicated panel using Bootstrap-Vue - javascript

Based on my previous question on Vue-Bootstrap panel I started using the following code to create a panel:
<b-card no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button block disabled href="#" v-b-toggle.accordion-1 variant="info">Search:</b-button>
</b-card-header>
<b-collapse id="accordion-1" visible accordion="my-accordion" role="tabpanel">
<b-card-body>
<search-form :fieldList="fieldList" :customs-max-num="customsMaxNum" :data-types="dataTypes" />
</b-card-body>
</b-collapse>
</b-card>
As you can see, I a button as a header. But what If I want to do something more complicated?
For example I want to create the following header:
As you can see, this header contains a title and a button. If I do it as I did before, I will have a button and text on a button? Does not feels right. What I currently have:
<b-card no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab">
<div class="title align-left" height="100px">
<button class="pull-right btn btn-info" #click="goBack()">Go Back</button>
<strong>Data run:</strong>
{{ title() }} <br> {{ subtitle() }}
</div>
</b-card-header>
<!-- BODY -->
</b-card>
How it looks like:
How do I create such panel?

You can achieve this look by using display: flex on your header.
Add the class d-flex to your header and wrapping your button in a div and giving it the class ml-auto, this class applies the style margin-left: auto;
Using margin-left: auto inside display:flex will fill up the empty space with a margin, pushing the content in the opposite direction.
<b-card no-body class="mb-1">
<b-card-header header-tag="header" role="tab" class="d-flex">
<div class="title align-left" height="100px">
<strong>Data run:</strong> Title<br>
Subtitle
</div>
<div class="ml-auto">
<button class="btn btn-info">Go Back</button>
</div>
</b-card-header>
</b-card>
new Vue({
el: "#app"
});
<link href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="//unpkg.com/bootstrap-vue#2.7.0/dist/bootstrap-vue.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="//unpkg.com/bootstrap-vue#2.7.0/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-card no-body class="mb-1">
<b-card-header header-tag="header" role="tab" class="d-flex">
<div class="title align-left" height="100px">
<strong>Data run:</strong> Title<br>
Subtitle
</div>
<div class="ml-auto">
<button class="btn btn-info">Go Back</button>
</div>
</b-card-header>
</b-card>
</div>

Related

Vue/Nuxt app is rendering content (not components, just content) twice on every page

I am very new to Vue/Nuxt programming and followed a "add a blog" tutorial which I then modified for my site. It all works perfectly except the actual it is rendering content twice. It renders
NavPage (component) > content > FooterDiv(component) then content again. See image:
Image of the page showing duplicated content
This happens on every page.
I am including my blogpage code ecasue in testing it seems to be where the problem lives :
<template>
<div>
<div class="home-page">
<h2>Latest Posts</h2>
<div class="articles">
<div class="article" v-for="article of articles" :key="article.slug">
<nuxt-link :to="{ name: 'slug', params: { slug: article.slug } }">
<div class="article-inner">
<img :src="require(`~/assets/resources/${article.img}`)" alt="" />
<div class="detail">
<h3>{{ article.title }}</h3>
<p>{{ article.description }}</p>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "BlogPage",
data() {
return {
name: ''
}
},
mounted() {
let user = localStorage.getItem('user-info');
if (!user) {
this.$router.push({ name: "BlogPage" })
}
},
async asyncData({ $content, params }) {
const articles = await $content('articles', params.slug)
.only(['title', 'description', 'img', 'slug'])
.sortBy('createdAt', 'asc')
.fetch()
return {
articles
}
}
}
I have also included the structure being rendered by Vue per the Vue Dev Tools
This image is what I see in the dev tools when the page is rendered
I have spent hours troubleshooting this and can find no other info on the issue.
Thank you for any help, and your patience with a newbie. Let me know if you need to see any other code.
As requested here is my NavPage component code:
<template>
<!-- Navigation-->
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="#page-top">Denise Pedro</a>
<button class="navbar-toggler text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto">
<li class="navbar-brand"> <NuxtLink to="/">Home</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/PortfolioPage">Portfolio</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/ResumePage">Resume</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/ContactPage">Contact</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/BlogPage">Blog</NuxtLink></li>
</ul>
</div>
</div>
</nav>
</template>
and my FooterDiv component
<template>
<!-- Footer-->
<footer class="footer text-center">
<div class="container">
<div class="row">
<!-- Footer Location-->
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">Location</h4>
<p class="lead mb-0">
Seattle through Olympia, WA
<br />
</p>
</div>
<!-- Footer Social Icons-->
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">Around the Web</h4>
<!-- <a class="btn btn-outline-light btn-social mx-1" href="#!"><font-awesome-icon icon="fa-brands fa-facebook" /></a> -->
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/facebook-brands.svg" alt="facebook icon" /></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/twitter-brands.svg" alt="twitter icon"/></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/linkedin-in-brands.svg" alt="linkedin icon"/></a>
</div>
<!-- Footer About Text-->
<div class="col-lg-4">
<h4 class="text-uppercase mb-4">Denise Pedro</h4>
<p class="lead mb-0">
desiraes#gmail.com
<!-- Start Bootstrap -->
</p>
</div>
</div>
</div>
</footer>
</template>
and lastly, my layout code
<template>
<div>
<NavPage />
<Nuxt />
<FooterDiv />
<Nuxt />
</div>
</template>
<script>
import NavPage from '../src/components/NavPage.vue';
import FooterDiv from '../src/components/FooterDiv.vue'
export default {
components: {
NavPage,
FooterDiv
},
}
</script>
Thank you
In your layout, you've put </Nuxt> twice, that's why the page content is duplicated, you should remove it.
your layout.vue should look like that:
<template>
<div>
<NavPage />
<Nuxt />
<FooterDiv />
</div>
</template>
<script>
import NavPage from '../src/components/NavPage.vue';
import FooterDiv from '../src/components/FooterDiv.vue'
export default {
components: {
NavPage,
FooterDiv
},
}
</script>

V-for iteration ruins the styles

I have a slider which consists of products.
Right now I'm getting a list of products from the server and populating that slider with the result returned from the server. For this I have the following
<div class="most_buy_slider container special_proposal">
<div v-for="product in mostBoughtProducts">
<div>
<div class="goods_item">
<img :src="product.ProductPreviewImages[0]">
<div class="name">
{{product.Name}}
<span>{{product.Manufacturer}}</span>
</div>
<div class="price">{{product.Price}} грн</div>
<div class="economy">економія складає 57% від роздрібної вартості</div>
<div class="to_cart">
<button type="button" class="btn but_blue">в кошик</button>
</div>
</div>
</div>
</div>
</div>
But this result in the following:
however, when I render simple html without v-for it loads correctly.
<div class="most_buy_slider container bigger_width special_proposal">
<div>
<div v-for="index in 10" class="goods_item">
<img src="images/samples/whiskyjackdan.png">
<div class="name">
Вологі серветки Вологі серветки Вологі серветки Вологі серветки
<span>Ruta Selecta Ruta SelectaRuta SelectaRuta Selecta</span>
</div>
<div class="price">
45,55 грн
</div>
<div class="economy">
економія складає 57% від роздрібної вартості
</div>
<div class="to_cart">
<button type="button" class="btn but_blue">в кошик</button>
</div>
</div>
</div>
<div>
<div class="goods_item">
<img src="images/samples/ruta1.png">
<div class="name">
Вологі серветки
<span>Ruta Selecta</span>
</div>
<div class="price">
45,55 грн
</div>
<div class="economy">
економія складає 57% від роздрібної вартості
</div>
<div class="to_cart">
<button type="button" class="btn but_blue">в кошик</button>
</div>
</div>
</div>
I don't know your CSS, but in first code snippet you included you use additional div for v-for directive, that can break your styles.
Try this code instead:
<div class="most_buy_slider container special_proposal">
<div v-for="product in mostBoughtProducts">
<div class="goods_item">
<img :src="product.ProductPreviewImages[0]" />
<div class="name">
{{ product.Name }}
<span>{{ product.Manufacturer }}</span>
</div>
<div class="price">{{ product.Price }} грн</div>
<div class="economy">економія складає 57% від роздрібної вартості</div>
<div class="to_cart">
<button type="button" class="btn but_blue">в кошик</button>
</div>
</div>
</div>
</div>
I finally solved the problem
I was using Slick slider to display items. While data is being loaded from the server, the slick slider already gets initialized with 0 item in it. And when items has been loaded from the server, vue.js inserts data into the slider, but the slider still assumes that it has 0 item.
So the solution is to reinitialize the slick slider when data loaded from the server.
I called the following after the data load:
reInit() {
$('.most_buy_slider').slick('unslick');
$(".most_buy_slider").slick(this.sliderSettings())
}
sliderSettings() {
return {
infinite: true,
slidesToShow: 4,
slidesToScroll: 1
}
}

Creating multiple modals on one page with VUE

As the title implies I want to add two modal dialog's on one page.
I figured out how to create on but the second one I am having troubles with.
HTML:
<body>
<h1>-projects-</h1>
<ul id="button-container">
<li>
<a id="html-modal-button" #click="showModal = true">
<img class="htmllogo" src="images/HTMLLogo.png">
<div class="html-text-block">
<h2>HTML</h2>
<p>My web projects</p>
</div>
</a>
<htmlmodal v-if="showModal" #close="showModal = false"></htmlmodal>
</li>
<li>
<a id="cs-modal-button" #click="showModal = true">
<img class="csharplogo" src="images/CSHARPLogo.png">
<div class="cs-text-block">
<h2>C#</h2>
<p>My windows projects</p>
</div>
</a>
<csmodal v-if="showModal" #close="showModal = false"></csmodal>
</li>
</ul>
<!-- MODAL SECTION -->
<script type="text/x-template" id="html-modal-template">
<transition name="html-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">HTML HEADER</slot>
</div>
<div class="modal-body">
<slot name="body">HTML BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">HTML FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<script type="text/x-template" id="cs-modal-template">
<transition name="cs-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">CS HEAD</slot>
</div>
<div class="modal-body">
<slot name="body">CS BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">CS FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
</body>
</html>
VUE.JS:
$(window).load(function(){
// CREATE THE DOM COMPONENT
Vue.component('htmlmodal', {
template: '#html-modal-template',
});
Vue.component('csmodal', {
template: '#cs-modal-template',
});
// START THE APP
new Vue({
el:'#button-container',
data: {
showModal: false
}
})
});
**The Fiddle: ** https://jsfiddle.net/oz053uzj/
As you can see I have separated the modal section, so essentially I could simply create and edit a modal, create a vue.component and reference it.
The problem comes when I try to open the modal, it seem's to only open the second or last modal for each of the buttons, I presume its due to #click="showModal = <>" is same for both the modals, but I'm left clueless..
because their v-if is based on the same data showModal.
If showModal is true, both will be displayed. And the last one will be on top.
So how about differentiating them based on a string instead of true/false ?
<a id="html-modal-button" #click="showModal = 'html-modal'">
and
<htmlmodal v-if="showModal === 'html-modal'" ...
?
demo: https://jsfiddle.net/jacobgoh101/oz053uzj/1/
You should use two different variable for two modal.
HTML:
<body>
<ul id="button-container">
<li>
<a id="html-modal-button" #click="showModal = true">
First Modal
</a>
<htmlmodal v-if="showModal" #close="showModal = false"></htmlmodal>
</li>
<li>
<a id="cs-modal-button" #click="showCsModal = true">
Second Modal
</a>
<csmodal v-if="showCsModal" #close="showCsModal = false"></csmodal>
</li>
</ul>
<!-- MODAL SECTION -->
<script type="text/x-template" id="html-modal-template">
<transition name="html-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">HTML HEADER</slot>
</div>
<div class="modal-body">
<slot name="body">HTML BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">HTML FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<script type="text/x-template" id="cs-modal-template">
<transition name="cs-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">CS HEAD</slot>
</div>
<div class="modal-body">
<slot name="body">CS BODY</slot>
</div>
<div class="modal-footer">
<slot name="footer">CS FOOTER
<button class="modal-default-button" #click="$emit('close')">OK</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
</body>
VUE.JS:
new Vue({
el:'#button-container',
data: {
showModal: false,
showCsModal: false,
}
})
**The Fiddle: ** https://jsfiddle.net/tanvir86/od2cjtkc/

VueJS #click with anchor tags

I have a single page application with a side navigation bar which has a set of anchor tags in a list.
I want to show which content to show in the page depending on the value of the selectedPage variable. As well as change the value of selectedPage based on the link that is clicked in the side bar.
Even when including .prevent on the click event the code below does not change the value of the variable. Is there another condition I should be using instead
MyPage.html
#Navbar for selecting content
<div id="sidebar-wrapper">
<ul class="sidebar-nav">
<li>Foo</li>
<li>Bar</li>
</ul>
</div>
#Page content
<div id="page-content-wrapper">
<div class="main-content" id="app" v-cloak>
<div class="container-fluid" v-if="selectedPage === 'Foo'">
<h3 class="page-title">{{selectedPage}}</h3>
</div>
<div class="container-fluid" v-if="selectedPage === 'Bar'">
<h3 class="page-title">{{selectedPage}}</h3>
</div>
</div>
</div>
App.js
new Vue({
el: '#app',
data: {
selectedPage: 'Foo',
}
})
This works as I expect; is it working how you expect?
new Vue({
el: '#app',
data: {
selectedPage: 'Foo'
}
});
#app {
display: flex;
}
#sidebar-wrapper {
border-right: solid thin black;
margin-right: 15px;
padding-right: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<div id="sidebar-wrapper">
<ul class="sidebar-nav">
<li>Foo</li>
<li>Bar</li>
</ul>
</div>
#Page content
<div id="page-content-wrapper">
<div class="main-content" id="app" v-cloak>
<div class="container-fluid" v-if="selectedPage === 'Foo'">
<h3 class="page-title">{{selectedPage}}</h3>
Foo section
</div>
<div class="container-fluid" v-if="selectedPage === 'Bar'">
<h3 class="page-title">{{selectedPage}}</h3>
Bar section
</div>
</div>
</div>
</div>
I just had an interesting scenario where I was making the button work with keyboard only for a11y.
I did this and it worked great:
Clicking the button loads a popover via vue-popperjs, which needs to be dismissed when the menu item is clicked after. I will show the entire markup and discuss it after:
<template>
<v-popper trigger="click" :options="{ placement: 'bottom' }" enter-active-class="shadow-lg">
<div class="popper">
<div class="flex flex-col text-left p-2">
<span class="text-pink font-bold py-2 px-8">Download</span>
<a
:href="defaultAction"
class="no-underline text-grey-darkest hover:bg-pink-lighter py-2 px-8"
#click="$refs.downloadButton.click()"
>
CSV
</a>
<a
:href="urlsAction"
class="no-underline text-grey-darkest hover:bg-pink-lighter py-2 px-8"
#click="$refs.downloadButton.click()"
>
CSV with URLs
</a>
</div>
</div>
<button
ref="downloadButton"
slot="reference"
class="flex items-center justify-center text-center no-underline rounded-full w-8 h-8 text-grey-darker hover:text-pink active:text-pink-darker mr-2"
title="Download CSV"
>
<i class="fas fa-download"></i>
</button>
</v-popper>
</template>
There are two key things going on here:
Place a ref on the button
Fire $ref.downloadButton.click() when the <a> tag is clicked
This will close the popover when menu items are clicked, netting you some sick UX.

Why bootstrap collapse is automatically collapsing(shrinking) the element?

Hi I am using the AngularJs with HTML to have dynamic content.
I am also making use of bootstrap for collapse feature.
I have created question answer page which is similar to Stackoverflow.
When page loads, it shows up the all questions and when I click on any particular question then it expands that question and with answers but answers are again collpased and there is one anchor tag to expand all answers.
My problem is that when I am clicking on answer's anchor tag the answers are showing up for few seconds and again it is collapsing automatically.
Below is my code:
<div style="" class="row ans-txt left-margin-img">
{{ answer.a_list.as.length }} ANSWERS
<a data-target=".demo" data-parent="" data-toggle="collapse">
<img src="assets/svg/downarrow_active.svg" class="img-responsive" style="height: 24px; width: 24px; display: inline; float: right; right: 18px; position: absolute;"></img>
</a>
</div>
<div class="row " style="padding-top:14px;height:auto;" ng-repeat-start="(key, value) in answer.a_list.as">
<div class="col-xs-2 col-sm-1 col-md-1 content-padding2 collapse demo">
<div>
<button type="submit" class="searchStyle bgStyle btn-Style vote-btn-border" ng-click="vote(value.raw, 1)">
<i class="glyphicon glyphicon-chevron-up"></i>
<img src="assets/svg/uparrow.svg" class="img-responsive" style="height:24px;width:24px;"></img>
</button>
</div>
<div><button type="text" class="searchStyle bgStyle btn-txt" disabled>{{ value.raw.netvotes }}</button></div>
<div>
<button type="submit" class="searchStyle bgStyle btn-Style vote-btn-border" ng-click="vote(value.raw, 0)">
<i class="glyphicon glyphicon-chevron-down"></i>
<img src="assets/svg/downarrow_active.svg" class="img-responsive" style="height:24px;width:24px;"></img>
</button>
</div>
</div>
<div class="col-xs-11 col-sm-10 col-md-11 padding-rightPane collapse demo">
<p class="ex2">{{ value.raw.content }}</p>
<p class="bottom-margin14">
<div class="askedBy-txt">
Answered by {{ value.raw.handle ? value.raw.handle : value.raw.email }} on {{ value.raw.created * 1000 | date:'MMMM dd, yyyy'}}
</div>
<img src="assets/svg/tick_icon.svg" style="height:20px;width:20px;" class="img-responsive pull-right" title="Best answer"
ng-if="value.select_text === 'Best answer'"></img>
</p>
</div>
</div>
Try to toogle the class .collapse.in. It toogles the css state of collapse element.
<div class="...collapse..." ng-class="{'in': !isCollapsed}">
</div>

Categories