Vuetify expand click event - vuejs2

I am using Vuetify Expansion-Panels and I would like to do something every time a user clicks on the Headline.
My Problem is that the head item has some margin around it. So once you click on the margin, the event wont fire. I tried putting the click event on the parent without any success. Is it possible to implement such click listener without rewriting the vuetify styles?
The following css will do the trick, but it seems a little bit dirty to me. (scoping does not work)
.v-expansion-panel__header {
padding: 0px;
}
.v-expansion-panel__header div {
padding: 12px 24px;
width: 100%;
height: 100%;
}
.v-expansion-panel__header .header__icon {
display: none;
}
https://codepen.io/anon/pen/wxmpyy?&editors=101

I think your CSS solution would be considerable.
There is a javascript-based solution which in my opinion is much more dirtier than CSS.
new Vue({
el: '#app',
methods: {
doSomething (e) {
let $target = $(e.target), $header = $('.v-expansion-panel__header');
if ($target.is($header) || $target.parents($header).is($header)) {
alert('Hello World')
}
}
}
})
Full pen: https://codepen.io/WisdomSky/pen/EpEqjr?editors=1010

You can watch the panel index and act on it.
Check this other answer about a similar issue.
https://stackoverflow.com/a/51253018/617395

I just posted my solution for this problem here.
The gist:
<v-expansion-panel #click="onExpansionPanelClick">
...
</v-expansion-panel>
onExpansionPanelClick(event) {
if(event.target.classList.contains('v-expansion-panel-header--active')) {
console.log("Panel is closing/now closed.")
} else {
console.log("Panel is opening/now open.")
}
}

Related

Fire event on Scrolling Vue.js overflow:auto height:100vh

Hi I have problem firing event when I scroll. I want event to fire when I scroll menu and not whole page. If you look at console, and disable overflow and height in CSS for #app, event will fire. Please check link.
Assign id of inner div element. Let's say longlist here.
<div id="app">
<div id="longlist" class="some-long-list">
<ul>
...
</ul>
</div>
</div>
Add scroll event to the longlist element. Here you should use mounted() instead of created()
new Vue({
el: "#app",
data: {
list: null
},
methods: {
handleScroll (event) {
// Any code to be executed when the window is scrolled
console.log(event)
console.log("metallica")
}
},
mounted () {
this.list = document.getElementById('longlist')
this.list.addEventListener('scroll', this.handleScroll);
},
destroyed () {
this.list.removeEventListener('scroll', this.handleScroll);
}
})
Also, change css to enable scrolling only inside inner div.
#app {
background: #fff;
border-radius: 4px;
/* padding: 20px; */
transition: all 0.2s;
height: 100vh;
/* overflow: auto; */
}
.some-long-list {
background:red;
width: 300px;
margin:0px auto;
overflow: auto;
height: 100%;
}
Hope this could help.
You currently have this in your pen:
...
created () {
window.addEventListener('scroll', this.handleScroll);
},
...
...so your event listener is attached to the whole window. Try selecting the relevant element first with something like document.getElementsByClassName('my-list')[0] or similar to attach the event listener to the element itself.
e.g.
...
created () {
const list = document.getElementsByClassName('my-list')[0]
list.addEventListener('scroll', this.handleScroll);
}
...

Vue router in-out page transition: transition in a new route while old route remains visible

To illustrate what I'm trying to achieve but also discuss and learn about each mechanism separately, I split the issue into two independent challenges:
1. Keep previous route visible until new route has transitioned in
Whether the transition is sliding, what I'm trying here, or just fading; mode in-out doesn't work as I would expect it, namely that the existing route stays visible until the next route has finished its transition (e.g. overlaid itself over the previous one), exactly as illustrated here in the last example of this section https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes, showing two buttons with in-out mode. Instead no transition is happening but it just flips the routes statically at half of the given transition time.
Is there any caveat with routes and an obvious reason why this wouldn't work the same way, e.g. that a single router-view can only hold one at the time and therefore in-out is not possible?
EDIT 1:
I figured out that in-out would actually only work with position:absolute on both elements, otherwise they will not overlay. Any idea how I could elegantly include such a behavior, potentially setting that absolute position during router-transition only?
Current hack that has the visual slide-up modal effect (mode: in-out) I'm looking for: adding style="position:absolute; z-index:2100" to the dialog route. Then I would need to change the underlying transition once it's shown in order to have the reverse hide effect (mode: out-in).
Also see EDIT 2 below.
2. Creating a modal-like page (route) which opens above another existing page when navigated to
I tried to hack that behavior by adding a second router-view in App.vue
<router-view />
<router-view name="dialog" />
The particular component is added to my routes like this
{
path: 'records/new',
components: {
dialog: () => import('layouts/NewRecord.vue')
},
children: [
{
name: 'new-record',
path: '',
component: () =>
import('src/pages/NewRecord.vue')
}
]
}
I'm not sure whether this approach even makes sense but I couldn't make it work properly. The aim would be to just overlay another router-view name="dialog whenever a "dialog"-path is pushed, so while it can be animated (slide-up) the other router-view stays visible below. In the end I guess I'm facing the same issue here: once the route changes, the initial router-view discards its component because the path does not match the current location anymore.
Either way, there are people out there with more experience and expertise so I hope I could illustrate what I'm trying to achieve and I'm just curious and thankful to read your inputs.
EDIT 2
I could make it work the way I wanted with simply one , wrapped in a custom page-transition component. It is quite a hack though AND I needed to add position: absolute to may page-layouts, to all of them actually (both the "leaving" and the "entering" component need position: absolute) when showing the dialog component. I'm sure there's a better way but I haven't found it so far.
Custom page-transition component:
<template>
<transition :name="name" :mode="mode">
<slot/>
</transition>
</template>
<script lang="ts">
import { Component, Watch } from 'vue-property-decorator'
import Vue from 'vue'
import { Route } from 'vue-router'
#Component({
components: {}
})
export default class PageTransition extends Vue {
NAME_FADE = 'fade'
NAME_SLIDE_UP = 'slide-up'
NAME_SLIDE_DOWN = 'slide-down'
MODE_OUT_IN = ''
MODE_IN_OUT = 'in-out'
name = this.NAME_FADE
mode = this.MODE_OUT_IN
#Watch('$route', { immediate: true, deep: true })
onRouteChanged(newVal: Route, oldVal: Route) {
if (newVal.meta.transition === 'dialog') {
this.name = this.NAME_SLIDE_UP
this.mode = this.MODE_IN_OUT
} else if (oldVal && oldVal.meta.transition === 'dialog') {
this.name = this.NAME_SLIDE_DOWN
// shift next page in immediately below dialog
this.mode = this.MODE_IN_OUT
} else {
// default
this.name = this.NAME_FADE
this.mode = this.MODE_OUT_IN
}
}
}
</script>
<style lang="scss" scoped>
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: all 0.1s ease;
}
// start of enter element
.slide-up-enter {
transform: translateY(60%);
opacity: 0;
}
.slide-up-enter-active {
transition: all 0.3s ease-out;
z-index: 2100;
}
// start of leave element
.slide-up-leave, .slide-up-leave-active {
opacity: 0;
}
// start of leave element
.slide-down-leave {
z-index: 2100;
}
.slide-down-leave-to {
transform: translateY(60%);
opacity: 0;
z-index: 2100;
}
.slide-down-leave-active {
transition: all 0.3s ease-in;
}
// start of enter element
.slide-down-enter {
opacity: 0;
}
.slide-down-enter-active {
/* show immediately behind existing page (lower z-index) */
transition: all 0s;
}
</style>
I have a similar task. I was able to complete it using fixed containers and z-index shuffle. I met a number of issues related to scroll and vertical alignment, and, in my case, solving it using absolute position during router-transition only was not possible.
Here's the demo: https://kasheftin.github.io/vue-router-in-out-slide-scroll.
Also, I had to use localStorage to keep & restore page scroll position.
In my case page content has to be vertically aligned. That's why I could not use one global scrollable container (e.g. <body>). In-out mode transition works rather simple - it just appends the content, adds some classes and then removes the first child. That means in the middle there're two page containers side by side, and if one of them is tall (and forces the body to have scroll), then the other one appears in the middle of the body and has wrong vertical alignment.
So I just wrapped every page with fixed scrollable container. Assume we have a List and an Item pages, and the last should slide from the right and overlay the list. Then, the right-to-left animation is very simple:
.slide-right-enter-active {
transition: transform 1s ease;
.slide-right-enter {
transform: translateX(100%);
}
Left-to-right animation (overlay disappearing) has the wrong z-index. During the animation we have the following in the DOM:
<transition>
<Item />
<List />
</transition>
By default List will be shown over the Item, but it has to be below. So there're the rules:
.slideable-page {
position: fixed;
overflow: auto;
z-index: 2;
}
.slide-left-enter {
z-index: 1;
}
.slide-left-enter-active {
z-index: 1;
}
.slide-left-leave-active {
transition: transform 1s ease;
z-index: 3;
}
.slide-left-leave-to {
transform: translateX(100%);
}
For question 1: Have you added the CSS with it? The transition by itself only handles timing, you need to add the CSS for the transition to work (example: https://v2.vuejs.org/v2/guide/transitions.html#Transitioning-Single-Elements-Components).
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
For question 2:
I don't know if I understood correctly your situation, but if I did, here is what I would do, using nested routes.
layouts/NewRecord.vue
<template>
<router-view name="dialog"></dialog>
</template>
Routes
const routes = {
path: 'records/new',
component: () => import('layouts/NewRecord.vue'),
children: [
{
path: 'dialog',
components: {
dialog: () => import('src/pages/NewRecord.vue'),
},
},
],
}

Why should I use v-bind for style

I just started learning Vue and I was wondering, why should I use v-bind for style and not write it regularly in html/css file
Let's say you need to create a progress bar that is not static. You will then need to update the style attribute width for-example.
To accomplish this, we need to programatically edit the width of the element. We 'cannot' to this in plain css, therefore the :style attribute comes in handy.
Let's create an example:
Codepen
HTML
<div id="vue">
<div class="progress-bar">
<div :style="{'width':progress + '%'}" class="progress" />
</div>
<button #click="fakeProgress">Init fake progress</button>
</div>
Css;
.progress-bar, .progress {
border-radius: 20px;
height: 20px;
}
.progress-bar {
width: 250px;
background-color: gray;
}
.progress {
background-color: blue;
width: 0;
transition: all 1s ease;
}
Javascript
new Vue({
el: '#vue',
data: {
progress: 0
},
methods: {
fakeProgress() {
let progress = setInterval(() => {
if(this.progress == 100) {
clearInterval(progress)
} else {
this.progress += 1;
}
}, 50)
}
}
})
As you see here, we bind the progress data attribute to the width value on the fake progress bar. This is just a simple example, but I hope this makes you see its potential. (You could achieve this same effect using the <progress> tag, but that would ruin the explanation.
EDIT; Also want to point out that you are supposed to write all your css as normal as you point out in your question. However, :style is used in cases that you cannot normally use css for. Like the example above where we need css to change from a variable.

Bootstrap datatable: search filter, clear icon issue

datatables.min.css datatables.min.js 2.1.4 jquery, 3.3.5 bootstrap, 1.10.8 datatables
Clear icon does not appear on search filter input for chrome, firefox, but it appears in IE10 and later. Can be easily reproduced in bootstrap sample (https://www.datatables.net/manual/styling/bootstrap ).
When I add my implementation of clear icon the default one also appears in IE.
Is there a simple workaround to turn off extra clear icon for some browsers?
Bootstrap's styling removes the clear icon from the search input from bootstrap datatable. This is part of Bootstrap's default behaviour.
Add this to your CSS:
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: searchfield-cancel-button;
}
It will override Bootstrap's hiding of the clear button.
This is html5 issue:
/* Disable browser close icon for IE */
input[type="search"]::-ms-clear { display: none; width : 0; height: 0; }
input[type="search"]::-ms-reveal { display: none; width : 0; height: 0; }
/* Disable browser close icon for Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
Here is an article for more details on html5 input[type="search"] disabling
This solution worked for me:
<script>
$(document).ready(function() {
$('.dataTables_filter input').addClass('searchinput');
$('.dataTables_filter input').attr('placeholder', 'Buscar');
$(".searchinput").keyup(function () {
$(this).next().toggle(Boolean($(this).val()));
});
$(".searchclear").toggle(Boolean($(".searchinput").val()));
$(".searchclear").click(function () {
$(this).prev().val('').focus();
$(this).hide();
var table = $('#dt_basic').DataTable();
//clear datatable
table
.search('')
.columns().search('')
.draw();
});
});
</script>
css:
.searchclear {
float:left;
right:22px;
top: 8px;
margin: auto;
font-size: 18px;
cursor: pointer;
color: #ccc;
}
and in jquery.dataTables.min.js you need add the icon remove-circle after input:
original code
'<input type="search" '+c.sFilterInput+'"/>'
new code
<input type="search" '+c.sFilterInput+'"/><span id="searchclear" class="searchclear glyphicon glyphicon-remove-circle"></span>'
example image

animate toggle only woking one way

what I am trying to do is on open, menu 1, showing 'Click me to start'. Menu 2, which currently says 'This is menu 2', just for building purposes, is hidden. Then, on first click, menu 1 hides and menu 2 shows, then toggles back on second click. The problem is that once menu 2 is showing and menu 1 is hidden, it won't toggle back.
<div id="nav" class="nav">
<div id="whiteboardtext1" class="whiteboardtext1"><p>Click here to start</p></div>
<div id="whiteboardtext2" class="whiteboardtext2"><p>this is menu number 2</p></div>
</div>​
.nav{
width:700px;
float:left;
}
.whiteboardtext1{
position:absolute;
margin-top:110px;
margin-left:215px;
width:300px;
height:100px;
font-size:30px;
font-family:whiteboard;
text-align:center;
border:1px solid #fff;
cursor:pointer;
}
.whiteboardtext2{
z-index:1;
position:absolute;
margin-top:50px;
margin-left:50px;
width:650px;
height:350px;
font-size:30px;
cursor:pointer;
font-size:30px;
font-family:whiteboard;
text-align:center;
border:1px solid #fff;
cursor:pointer;
}
​$(document).ready(function(){
$('#whiteboardtext2').hide();
$('#whiteboardtext1').toggle(
function() {
$('#whiteboardtext1').stop().animate({
'opasity':'0'
}, 'fast');
$('#whiteboardtext2').stop().animate({
'opasity':'1'
}, 'fast');
$('#whiteboardtext1').fadeOut();
$('#whiteboardtext2').fadeIn();
},
function() {
$('#whiteboardtext1').stop().animate({
'opasity':'1'
}, 'fast');
$('#whiteboardtext2').stop().animate({
'opasity':'0'
}, 'fast');
$('#whiteboardtext2').fadeOut();
$('#whiteboardtext1').fadeIn();
})
});
​
I pretty sure the code is correct, but I just can't get it to work.
If anyone can help, I would really appreciate it.
Thank in advance
me
If I understand you correctly - http://jsfiddle.net/M8Tgx/
I changed CSS rules for .whiteboardtext2 just added display:none; by default.
I rewrite your JavaScript to this:
$(document).ready(function(){
$('#whiteboardtext1').click(function(){
$('#whiteboardtext1').fadeOut();
$('#whiteboardtext2').fadeIn();
});
$('#whiteboardtext2').click(function(){
$('#whiteboardtext1').fadeIn();
$('#whiteboardtext2').fadeOut();
});
});​
You code is not correct, because you are applying toggle #whiteboardtext1 element, but when it first call, it hide and the #whiteboardtext2 get displayed, and you dint apply any event on that, so it is not working as you are expecting. and opacity is correct css property.
You can try this to work
$(document).ready(function(){
$('#whiteboardtext2').hide();
$('#whiteboardtext1').show();
$('.nav').on('click', 'div', function() {
var _this =$(this);
_this.stop().animate({
'opacity':'0'
}, 'fast', function(){_this.hide();})
_this.siblings().stop().animate({
'opacity':'1'
}, 'fast').show();
});
});
This is because the toggle handler is bound to the #whiteboardtext1 element. Whenever #whiteboardtext1 is clicked, one text will fade out and the other will fade in, but #whiteboardtext2 has no click handler, so clicking it has no effect.
Also, opasity is not a valid CSS attribute, so animating it has no effect except to delay the subsequent animations. Assuming you wanted to fade the texts in/out, not a delayed sudden change.
Use this:
var $text1=$('#whiteboardtext1');
var $text2=$('#whiteboardtext2');
$text1.click(function(){
$text1.stop().fadeOut("fast");
$text2.stop().fadeIn("fast");
}
$text2.click(function(){
$text2.stop().fadeOut("fast");
$text1.stop().fadeIn("fast");
}