Add id element on Vue template - vue.js

I would like to add id elements to the next VUE templates. So, I can identify these html elements by their ids.
First scenario, I would like to add an id to the submit (ok) button
<core-dialog
v-if="deleteDialog.display"
v-model="deleteDialog.display"
type="confirmation"
width="500px"
:ok-button-text="$t('common.delete')"
#click:ok="
deleteDialog.display = false;
deleteDialog.rfqToDelete.remove({ shouldShowNotification: true });"
#click:cancel="cancelDelete"
>
On this second scenario, I would like to add an id on the footer element
<v-data-table
expand-icon="mdi-chevron-right"
style="border: solid 1px #e2e2e2; border-radius: 5px; margin: 0!important;min-width:900px "
data-cy="rfqs-table"
:headers="groupedByQuoteHeaders"
:items="loadedRfqs"
:item-class="itemRowBackground"
:loading="(isRfqsFindPending || isSearchPending )"
show-expand
:expanded.sync="expendRow"
item-key="_id"
:footer-props="{ 'items-per-page-text': $t('common.rowPerPageText'),
'page-text': `{0}-{1} ${$t('common.of')} {2}`}"
:no-results-text="$t('common.noDataAvailable')"
:no-data-text="$t('common.noDataAvailable')"
:loading-text="$t('common.loadingItems')"
#current-items="getFiltered"
#click:row="(item, slot) => slot.expand(!slot.isExpanded)"
#item-expanded="loadPart"
>

You could use a custom footer as the respective slot in the table component:
let tmpl = document.getElementById('tmpl-app')
new Vue({
el: '#app',
template: tmpl.content.cloneNode(true).innerHTML
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template id="tmpl-app">
<v-data-table
expand-icon="mdi-chevron-right"
style="border: solid 1px #e2e2e2; border-radius: 5px; margin: 0!important;min-width:900px "
data-cy="rfqs-table"
:headers="groupedByQuoteHeaders"
:items="loadedRfqs"
:item-class="itemRowBackground"
:loading="(isRfqsFindPending || isSearchPending )"
show-expand
:expanded.sync="expendRow"
item-key="_id"
:footer-props="{ 'items-per-page-text': $t('common.rowPerPageText'),
'page-text': `{0}-{1} ${$t('common.of')} {2}`}"
:no-results-text="$t('common.noDataAvailable')"
:no-data-text="$t('common.noDataAvailable')"
:loading-text="$t('common.loadingItems')"
#current-items="getFiltered"
#click:row="(item, slot) => slot.expand(!slot.isExpanded)"
#item-expanded="loadPart"
>
<div v-slot="footer" id="your-custom-id">
</div>
</v-data-table>
</template>
<div id="app"></div>

Related

Put ellipsis ... on v-data-table

I have a v-data-table with 5 columns, which some have predefined widths, and some don't.
I'd like only one line of text maximum for each item and display "..." when the text exceeds 1 line.
<v-data-table
dark
:footer-props="{ 'items-per-page-options': [10, 25, -1] }"
dense
calculate-widths
fixed-header
height="498"
:headers="headers"
hide-default-header
:items="res"
sort-by="publicationDate"
:sortDesc="sortVal"
>
<template v-slot:header="{ props: { headers } }">
<thead>
<tr>
<th v-for="h in headers" :class="h.class"
:key="h.text">
<span>{{h.text}}</span>
</th>
</tr>
</thead>
</template>
<template #item.video="{ item }">
<a
target="_blank"
v-if="item.video != ''"
class="links1 video-icon"
:href="item.video"
>
<v-btn dark icon>
<v-icon class="ic1">mdi-movie</v-icon>
</v-btn>
</a>
</template>
<template #item.title2="{ item }">
<a
target="_blank"
v-if="item.file != ''"
class="links1"
:href="item.file"
>
<span style="color:white"> {{ item.title }} </span>
</a>
</template>
</v-data-table>
I looked through the CSS properties to do so and I found things like :
text-overflow: ellipsis;
white-space: nowrap;
But it doesn't add the ... at the end of the lines and it also takes place beyond the widths applied to each columns so not all 5 columns are displayed on my panel.
Here's the headers in the data section
headers: [
{ text: "Source", value: "dataSource", width: "120px", class:"source-field"},
{ text: "News", value: "title2", width: "214px", class:"news-field"},
{ text: "Actors", value: "concernedActors", width: "242px" },
{ text: "Video", value: "video", width: "58px" },
{ text: "Publication", value: "publicationDate", width: "80px" },
],
And I tried this css but it won't work, the column news just goes bigger so that the entire text fits on 1 line.
th.news-field{
max-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
I would also love to make the hover darker on each line in the table
Here's a solution:
<template #item.foo="{ item }">
<div class="ellipsis-wrapper">{{ item.foo }}</div>
</template>
#your-table td {
position: relative;
}
#your-table td .ellipsis-wrapper {
position: absolute;
max-width: calc(100% - 1rem);
line-height: calc(3rem - 1px); /* change this if needed */
top: 0;
left: 1rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
But it creates another problem (easier to solve, IMHO): it takes the cell content out of the flow, therefore the table no longer calculates column width based on cells content (from the table's perspective, that column has no content) - so it relies on its header content (or on the provided width) to calculate the column width.
However, I believe making an "empty" column have a particular width (or a proportion from the table's width) is an easier to solve problem than your current one.
Demo: https://codepen.io/andrei-gheorghiu/pen/wvjoQXR

Change v-data-table's header's color

I'd like to change the color of the header in my v-data-table but didn't find any way in the Vuetify documentation. Does anyone know how to do it ?
I can change the rest of the colors on the table but no the header...
<v-card-text>
<v-data-table
dark
:footer-props="{ 'items-per-page-options': [10, 25, -1] }"
dense
calculate-widths
fixed-header
height="498"
:headers="headers"
:items="res"
sort-by="publicationDate"
:sortDesc="sortVal"
>
<template #item.video="{ item }">
<a
target="_blank"
v-if="item.video != ''"
class="links1 video-icon"
:href="item.video"
>
<v-btn dark icon>
<v-icon class="ic1">mdi-movie</v-icon>
</v-btn>
</a>
</template>
<template #item.title2="{ item }">
<!-- NEWS column -->
<a
target="_blank"
v-if="item.file != ''"
class="links1"
:href="item.file"
>
<span style="color:white"> {{ item.title }} </span>
</a>
</template>
</v-data-table>
</v-card-text>
You can achieve this by hide default header by adding hide-default-header attribute in <v-data-table> element and then create custom header by using v-slot.
<template v-slot:header="{ props: { headers } }">
<thead>
<tr>
<th v-for="h in headers" :class="h.class">
<span>{{h.text}}</span>
</th>
</tr>
</thead>
</template>
In headers array, add class property in each object which will contain the class name.
Sample structure of headers array :
headers: [
{ text: 'Title', value: 'title', class: 'my-header-style' }
...
...
]
Finally, In CSS you can just add the style to my-header-style class.
.my-header-style {
background: #666fff;
}
Live Demo :
new Vue({
el: '#app',
data: () => ({
headers: [
{ text: 'ID', value: 'id', class: 'my-header-style' },
{ text: 'Name', value: 'name', class: 'my-header-style' },
{ text: 'Age', value: 'age', class: 'my-header-style' }
],
movies: []
})
})
.my-header-style {
background: #666fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.2.5/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#1.2.5/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"/>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="items"
hide-default-header>
<template v-slot:header="{ props: { headers } }">
<thead>
<tr>
<th v-for="h in headers" :class="h.class">
<span>{{h.text}}</span>
</th>
</tr>
</thead>
</template>
</v-data-table>
</v-app>
</div>
One option to modify the default Vuetify CSS is to target the inner elements/sub-components using deep selectors. Target the root node of the component, in this case you can select the v-data-table classname, then deep select the classname on the header sub-component:
<style scoped>
.v-data-table >>> .v-data-table-header {
background-color: red !important;
}
</style>
or if not using scoped styling, you can just target the desired class
<style>
.v-data-table-header {
background-color: red !important;
}
</style>
codesandbox example
Also note that if you're using Sass you may need to use ::v-deep or /deep/ instead of >>>

How to make modal popup window in Vuejs?

<style src="./LoginButton.scss" lang="scss"></style>
<i18n src="./LoginButton.txt"></i18n>
<script src="./LoginButton.js"></script>
<template>
<div class="header-login component-same ml-10">
<span v-if="showLoggedIn">
<router-link :to="{ name: 'user' }" data-test="login-info-name">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{
$t('myAccount')
}}</span>
</router-link>
</span>
<!-- <span v-if="showLoggedIn" class="hidden-xs">
<a #click="logout" data-test="logout-button">
<span>{{ $t("signOut") }}</span>
</a>
</span>-->
<span v-else data-test="login-button">
<router-link :to="{ name: 'login' }">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{ $t('Register') }}</span>
</router-link>
</span>
</div>
</template>
I have written the above code for login, Where in this particular line
User has a register button, As soon as the user clicks on the register button, the User will be redirected to another page where he can fill up the basic details, So Instead of redirecting into another page, I want the Register button as a Popup, wherein the popup user can enter details.
also, I tried bootstarp-vue but I wasn't able to find the solution.
It's easier than what you think and mostly you won't need a special CSS lib for that, so the thing to do is just to make another component and call it whatever you want(but modal.vue makes sense here):
//inside modal.vue:
<template>
<div className="modal__wrapper">
<div className="modal">
<slot/>
</div>
</div>
</template>
<style lang="scss" scoped>
.modal{
width: 300px;
height: 100px;
border-radius: 10px;
background-color: white;
padding: 20px 20px;
z-index: 1200;
&__wrapper{
background-color: rgba(0,0,0,0.4);
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
position: absolute;
top: o;
}
}
</style>
in its simplest form, it's just a component with some styling to make it look like a modal (a transparent background(to make it look it's over the previous page) and an absolute position for its wrapper(the transparent one) and some centering techniques for its actual content),I didn't put any script in it(because it's just a simple modal I'm showing you to give the idea how to make yours) and then there is this slot part meaning you can pass your registration form to this modal component, from your parent component and use a boolean flag to just show it on register click
(sure you might need to add some more CSS to the .modal class):
<i18n src="./LoginButton.txt"></i18n>
<script src="./LoginButton.js"></script> <!-- the cleaner thing would
be to import them in your script section somehow -->
<template>
<div class="header-login component-same ml-10">
<span v-if="showLoggedIn">
<router-link :to="{ name: 'user' }" data-test="login-info-name">
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{
$t('myAccount')
}}</span>
</router-link>
</span>
<span v-else data-test="login-button">
<!-- no need to rerouting to another path -->
<Modal>
<!--your template for registration will go here-->
<i class="dl-icon-user12"></i>
<span class="target-text hidden-xs hidden-sm">{{ $t('Register') }}</span>
</Modal>
</span>
</div>
</template>
//you gotta import the modal component so in your script section you have sth like this(BTW what type of structure are you using for your project? are you using vue-cli's scaffold or what? Are you using babel? cuz I'm gonna assume you are!)
<script>
import Modal from 'The_Relative_Path_to_the_Modal_you_just_created';
export default {
components:{
Modal
},
data(){
return{
showLoggedIn: false
}
}
}
</script>
<style src="./LoginButton.scss" lang="scss"></style>

vuetify transition of v-flex

I'm trying to implement transition like here codepen example but using the Vuetify.
I've noticed that adding transition tag before v-flex component destroyed a v-flex order. In this example codesandbox, there are two routes one with transition another one without.
Components have the structure:
<v-container>
<v-layout row wrap pb-2 pt-2>
<!-- is transition group -->
<transition-group name="cards" >
<v-flex xs3
v-for="card in items"
:key="card"
>
<v-layout>
<v-card>
.....
</v-card>
</v-layout>
</v-flex>
</transition-group>
</v-layout>
</v-container>
transition-group renders an actual element: a <span> by default. So there's an extra span between v-layout and v-flex. This cause the flexbox to malfunction.
transition-group has to render something. You could set it to render v-layout instead of span.
BUT, transition-group has a limitation. It can set tag but cannot set props. So, for the row wrap pb-2 pt-2, you gotta add it manually using CSS.
change
<template>
...
<v-layout row wrap pb-2 pt-2>
<transition-group name="cards">
...
</transition-group>
</v-layout>
...
</template>
to
<template>
...
<transition-group name="cards" tag="v-layout" class="manual-v-layout">
...
</transition-group>
...
</template>
<style>
.manual-v-layout {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
padding-bottom: 8px !important;
padding-top: 8px !important;
}
</style>
and it would work.
Demo: https://codesandbox.io/s/z2z5yoopol
I couldn't get Jacob Goh's answer to work, so i made some adjustments with his answer as inspiration and came up with this as the solution.
<template>
...
<transition-group name="cards" tag="div" class="layout row wrap">
...
</transition-group>
...
</template>
Set the transition-group tag to div and assign the appropriate classes to it.

Paper-badge appears in wrong position when used with app-layout

I'm using app-layout with app-drawer / app-drawer-layout and app-header / app-header-layout (see MWE below). The paper-badge is attached to an element inside the app-header. The first time the page is loaded, it briefly appears in the correct position (issue #12), than disappears off the right of the screen, exactly 256px too far to the right, which is the exact size of the app-drawer.
When the screen is resized, it recalculates the position to the correct place. I suspect that the position is calculated before the drawer is fully loaded.
This does not happen when the app-drawer is retracted and not visible.
I tried running updatePosition() at ready but that did not help.
Here is my MWE:
<template>
<style is="custom-style">
app-drawer {
--app-drawer-content-container: {
background-color: green;
};
}
app-header {
background-color: yellow;
}
</style>
<app-drawer-layout fullbleed>
<app-drawer slot="drawer">
<div id="drawerbox">Navigation Drawer</div>
</app-drawer>
<div class="container">
<app-header-layout>
<app-header id="header" condenses reveals effects="waterfall" slot="header">
<app-toolbar id="toolbarheader">
<div main-title id="toolbartitlebox">Title Toolbar</div>
<paper-icon-button id="discoursebutton" icon="communication:forum"></paper-icon-button>
<paper-badge for="discoursebutton" label="20" title="20 results"></paper-badge>
</app-toolbar>
</app-header>
</app-header-layout>
</div>
</app-drawer-layout>
</template>
One hack that works is to set a setTimeouton the updatePosition():
ready: function() {
var self = this;
setTimeout(function(){
self.$$('paper-badge').updatePosition();
}, 100);
}
But is there a more elegant way of solving this?
Thanks for your help!
One solution is to put paper-badge outside/after app-drawer-layout :
<template>
<style>
app-drawer {
--app-drawer-content-container: {
background-color: green;
}
;
}
app-header {
background-color: yellow;
}
paper-badge {
margin-top: 10px;
}
</style>
<app-drawer-layout fullbleed>
<app-drawer id="drawer" slot="drawer">
<div id="drawerbox">Navigation Drawer</div>
</app-drawer>
<app-header-layout>
<app-header id="header" condenses reveals effects="waterfall" slot="header">
<app-toolbar id="toolbarheader">
<paper-icon-button id="toggle" on-tap="_onToggle" icon="menu"></paper-icon-button>
<div main-title id="toolbartitlebox">Title Toolbar</div>
<paper-icon-button id="discoursebutton" icon="inbox"></paper-icon-button>
<!-- <paper-badge for="discoursebutton" label="20" title="20 results"></paper-badge>-->
</app-toolbar>
</app-header>
</app-header-layout>
<div class="container">
container
</div>
</app-drawer-layout>
<paper-badge for="discoursebutton" id="pd" label="20" title="20 results"></paper-badge>
</template>
Plnkr: http://plnkr.co/edit/V7zGBpqqzRonbAYyudea?p=preview
I avoided this same issue by putting the <paper-icon-button> and <paper-badge> in a container with position: relative, and stopped using the for attribute.
<div style="position: relative">
<paper-icon-button id="notification-icon" icon="social:notifications" onclick="[[showNotifications]]">
</paper-icon-button>
<template is="dom-if" if="[[messages.length]]">
<paper-badge label="[[messages.length]]" class="red"></paper-badge>
</template>
</div>