We have a client requirement to implement a test automation in Power apps.
Power apps has its own Testing framework but that is still in Experimental mode and not recommended to use for production environment.
I've experience around Selenium but I'm facing issues while locating web elements for Power Apps.
I'm trying to locate a Text box and enter any value, even though the web elements are unique the selenium is not able to find those.
HTML
<div class="canvasContentDiv appmagic-control-view appmagic-content-
control-name _vst_" data-control-id="17" data-control-name="TextInput1"
style="width: 419px; height: 60px; z-index: 17; position: absolute; top:
517px; left: 105px;"><div class="appmagic-borderfill-container"
style="background-color: rgb(186, 202, 226); border-style: solid; border-
width: 2px; border-color: rgb(0, 18, 107); border-radius: 5px; margin:
-1px;"><div class="appmagic-border-inner" style="margin: -1px;"><div
class="react-knockout-control" spellcheck="false" style="position:
absolute; inset: 0px;">
<div class="appmagic-textbox" touch-action="pan-x pan-y" appmagic-
control="TextInput1">
<!-- ko if: (mode() === "multiline") --><!-- /ko -->
<!-- ko if: (mode() !== "multiline") -->
<input appmagic-control="TextInput1textbox" class="appmagic-text mousetrap
block-undo-redo" maxlength="10000" data-bind="
attr: {
type: mode() === 'password' ? 'password' : 'text',
title: properties.Tooltip() || null,
'aria-label': properties.AccessibleLabel() || null,
placeholder: properties.HintText,
readonly: viewState.displayMode() ===
AppMagic.Constants.DisplayMode.View,
contenteditable: viewState.displayMode() ===
AppMagic.Constants.DisplayMode.Edit,
'data-control-part': properties.Clear() ? 'text clearable' : 'text',
inputmode: keyboardMode
},
css: {
underline: properties.Underline,
strikethrough: properties.Strikethrough,
readonly: viewState.displayMode() ===
AppMagic.Constants.DisplayMode.View
},
value: text,
event: {
click: handleClick,
change: handleOnChange
},
style: {
fontFamily: properties.Font,
fontSize: properties.Size,
color: autoProperties.Color,
fontWeight: properties.FontWeight,
fontStyle: properties.Italic,
textAlign: properties.Align,
lineHeight: properties.LineHeight,
paddingTop: properties.PaddingTop,
paddingRight: properties.PaddingRight,
paddingBottom: properties.PaddingBottom,
paddingLeft: properties.PaddingLeft
},
disable: viewState.displayMode() ===
AppMagic.Constants.DisplayMode.Disabled" type="text" placeholder="Team
name..." contenteditable="true" data-control-part="text" inputmode="text"
tabindex="15" style="font-family: "Open Sans", sans-serif; font-
size: 21pt; color: rgb(0, 0, 0); font-weight: normal; font-style: normal;
text-align: left; line-height: 1.2; padding: 5px 5px 5px 12px;">
<div class="appmagic-text-clear-container">
<button class="appmagic-text-clear-button" data-control-part="clear" data-
bind="
visible: isFocused() && properties.Clear() &&
properties.Text() && mode() !== 'password' &&
viewState.displayMode() === AppMagic.Constants.DisplayMode.Edit,
event: {click: handleClearClick},
attr: {'aria-label': AppMagic.Strings.TextInputClearButtonLabel}" aria-
label="Clear value" tabindex="16" style="display: none;">
<svg class="appmagic-text-clear-svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 12 12" aria-hidden="true" focusable="false">
<polygon points="12,1.1 10.9,0 6,4.9 1.1,0 0,1.1 4.9,6 0,10.9 1.1,12
6,7.1 10.9,12 12,10.9 7.1,6" data-bind="style: {fill:
autoProperties.Color}" style="fill: rgb(0, 0, 0);"></polygon>
</svg>
</button>
</div>
<!-- /ko -->
</div>
</div></div></div></div>
Tried below to find the web element-
driver.findElement(By.xpath("//div[#class='appmagic-textbox']")).sendKeys("test");
driver.findElement(By.xpath("//input[#class='appmagic-text mousetrap block-undo-redo']")).sendKeys("Test");
Following is the error returned by Selenium-
Any help or suggestions around this would be very helpful.
Thanks In Advance.
Related
const app = new Vue({
el: '#app',
data: {
searchText: '',
listShow: true,
newDiv:false,
searcList:[],
list: {}
},
methods: {
handleBlur(e) {
console.log("inputOutClick");
if (this.listShow == false) {
console.log("mousedown was fired first");
}
this.listShow = false
},
selecteds(list) {
console.log("selecteds");
this.listShow = false;
this.searchText = list.name;
},
async search() {
this.listShow = true;
this.searcList = ['aeaeg', 'tdthtdht', 'srgsr'];
this.list.name = "TEST"
}
}
});
.dropdown-toggle-none::after {
content: none;
}
.select {
width: 100%;
max-height: 420px;
overflow-y: auto;
background: linear-gradient(#fdfdfd 30%, rgba(253, 253, 253, 0)), linear-gradient(rgba(253, 253, 253, 0), #fdfdfd 70%) 0 100%, linear-gradient(rgba(64, 54, 55, .1) 0, rgba(64, 54, 55, 0)) 100% 0, linear-gradient(rgba(64, 54, 55, 0) 0, rgba(64, 54, 55, .1)) 0 100%;
background-repeat: no-repeat;
background-size: 100% 50px, 100% 50px, 100% 6px, 100% 6px;
background-attachment: local, local, scroll, scroll;
border-top: 1px solid #e8e7e7;
border-bottom: 1px solid #e8e7e7;
background-color: #fdfdfd;
}
.select {
z-index: 1;
top: 50px;
padding: 3px 0;
border: 1px solid #c5c4c2;
background-color: #fdfdfd;
-webkit-box-shadow: 0 3px 6px #c5c4c2;
-moz-box-shadow: 0 3px 6px #c5c4c2;
}
.select {
position: absolute;
border-radius: .357rem !important;
box-shadow: 0 3px 6px #c5c4c2;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
line-height: 1.45;
}
.select ul {
padding: 0;
margin: 0;
}
.select li {
display: block;
cursor: pointer;
line-height: 20px;
color: #403637;
}
.select li a {
display: block;
padding: 5px 15px;
-webkit-transition-property: color, background-color;
-webkit-transition-duration: .66s;
-webkit-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
-moz-transition-duration: .66s;
-ms-transition-duration: .66s;
-ms-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
-o-transition-property: color, background-color;
-o-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
transition-property: color, background-color;
transition-duration: .66s;
transition-timing-function: cubic-bezier(.25, 1, .25, 1);
}
.select li a:hover {
color: #22c39e;
background-color: #e8e7e7;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div>
<input
type="text"
class="form-control"
v-model="searchText"
#keyup="search"
#blur="handleBlur"
/>
<div v-if="listShow" style="background:red">
<ul>
<li v-for="(list, index) in searcList">
<a #mousedown.prevent #click="selecteds(list)">{{ list}}</a>
</li>
</ul>
</div>
<div v-if="newDiv">
<p>hello</p>
</div>
</div>
</div>
I'm trying to make a call with vuejs, there is a topic I'm just stuck with. e.g; I want to navigate in the data returned from the get data with the arrow signs "with the alt key or the up key", but I haven't quite figured out how to do it.
If it is a second issue, I want the color of whichever is selected in the list to be clear.
new Vue({
el: '#app',
data: {
type: "sales_invoices",
SearcListed: {
searchText: '',
listShow: false,
searcList: [],
},
},
methods: {
selecteds(list) {
this.SearcListed.listShow = false;
this.SearcListed.searchText = list.name;
},
async search() {
if (this.SearcListed.searchText !== '') {
const res = await this.callApi('get', 'getir' + '?filter=' + this.SearcListed.searchText)
if (res.status === 200) {
this.SearcListed.searcList = res.data;
if (res.data.length > 0) {
this.SearcListed.listShow = true;
} else {
this.SearcListed.listShow = false;
}
}
} else {
this.SearcListed.listShow = false;
}
},
}
});
.dropdown-toggle-none::after {
content: none;
}
.select {
width: 100%;
max-height: 420px;
overflow-y: auto;
background: linear-gradient(#fdfdfd 30%, rgba(253, 253, 253, 0)), linear-gradient(rgba(253, 253, 253, 0), #fdfdfd 70%) 0 100%, linear-gradient(rgba(64, 54, 55, .1) 0, rgba(64, 54, 55, 0)) 100% 0, linear-gradient(rgba(64, 54, 55, 0) 0, rgba(64, 54, 55, .1)) 0 100%;
background-repeat: no-repeat;
background-size: 100% 50px, 100% 50px, 100% 6px, 100% 6px;
background-attachment: local, local, scroll, scroll;
border-top: 1px solid #e8e7e7;
border-bottom: 1px solid #e8e7e7;
background-color: #fdfdfd;
}
.select {
z-index: 1;
top: 50px;
padding: 3px 0;
border: 1px solid #c5c4c2;
background-color: #fdfdfd;
-webkit-box-shadow: 0 3px 6px #c5c4c2;
-moz-box-shadow: 0 3px 6px #c5c4c2;
}
.select {
position: absolute;
border-radius: .357rem !important;
box-shadow: 0 3px 6px #c5c4c2;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
line-height: 1.45;
}
.select ul {
padding: 0;
margin: 0;
}
.select li {
display: block;
cursor: pointer;
line-height: 20px;
color: #403637;
}
.select li a {
display: block;
padding: 5px 15px;
-webkit-transition-property: color, background-color;
-webkit-transition-duration: .66s;
-webkit-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
-moz-transition-duration: .66s;
-ms-transition-duration: .66s;
-ms-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
-o-transition-property: color, background-color;
-o-transition-timing-function: cubic-bezier(.25, 1, .25, 1);
transition-property: color, background-color;
transition-duration: .66s;
transition-timing-function: cubic-bezier(.25, 1, .25, 1);
}
.select li a:hover {
color: #22c39e;
background-color: #e8e7e7;
}
<div id="app">
<div class="container">
<div class="col-sm-6">
<div class="input-group input-group-merge mb-1">
<input type="text" class="form-control" placeholder="Search..." aria-label="Search..." aria-describedby="basic-addon-search2" v-model.trim="SearcListed.searchText" #keyup="search" autocomplete="off" />
<span class="input-group-text">
<i class="fas fa-search"></i>
</span>
<div class="select" v-if="SearcListed.listShow">
<ul>
<li v-for="(list, index) in SearcListed.searcList" :key="list.id">
<a #mousedown.prevent #click="selecteds(list)">{{ list.name }}</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
To use Arrow Keys events you can use something like:
#keyup.up="nextListItem"
#keyup.down="previousListItem"
You would probably apply it on the following div:
<div #keyup.up="nextSearchList" #keyup.down="previousSearchList" class="input-group input-group-merge mb-1">...</div>
(Note that the keypresses would only be received when the div is in focus.)
You would have to add an index or object in your data() to keep track of what the selected item in the list is and then go to the next or previous one with nextListItem and previousListItem.
You can add a :class="{ active: index == selectedItemIndex}" to each li in the v-for to give the currently selected li the active class and then you can style it however you want to, for example:
.active {
background-color: grey;
}
Also, here is more info for vue2 and vue3 key event modifiers:
https://v2.vuejs.org/v2/guide/events.html#Key-Codes
And here is info for vue3:
https://v3-migration.vuejs.org/breaking-changes/keycode-modifiers.html#_3-x-syntax
I want to add transition when the values get changes but cannot accomplish it. I need to change the background when the values get updated.
Can anyone help me out?
Codesandbox Link - Vuejs Transition
<template>
<div id="app">
<div class="box">
<div v-if="change > 0">
<transition name="increase">
<span>+ {{ amount }} </span></transition
>
</div>
<div v-else-if="change < 0">
<transition name="decrease">
<span>- {{ amount }}</span>
</transition>
</div>
<div v-else>{{ amount }}</div>
</div>
<br />
<button #click="generate">Update</button>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
change: 2,
amount: 100,
};
},
methods: {
generate() {
var amounts = [100, 110, 85, 75, 190];
let changes = [-1.2, -5, 2, 5, 1, 7];
this.amount = amounts[Math.floor(Math.random() * amounts.length)];
this.change = changes[Math.floor(Math.random() * changes.length)];
},
},
created() {},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.box {
width: 100px;
margin: 0 auto;
border: 1px solid #ddd;
padding: 1em 2em;
}
#keyframes higher {
50% {
background: rgba(50, 199, 135, 0.2);
color: #32c787;
}
}
#keyframes lower {
50% {
background: rgba(255, 86, 82, 0.2);
color: #ff5652;
}
}
.increase-enter {
animation: higher 0.5s;
}
.decrease-enter {
animation: lower 0.5s;
}
</style>
P.S - Ignore this, posted because my text is too short. IT is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
You can make use of key to inform transition there is a difference of the element so it can trigger the animation again.
Also, use the -active class to apply animation during entering phase.
https://codesandbox.io/s/transition-forked-vg5pu?file=/src/App.vue
<transition name="increase">
<span :key="amount + change">+ {{ amount }}</span>
</transition>
...
.increase-enter-active {
animation: higher 0.5s;
}
I have developed a split sidebar menu. On the left there is icons which when pressed activate the menu bar on the right side for the submenu items. The submenu contains the router-link tags which I am able to tap into the active class of the selected link to highlight it. The issue is I need to apply the active class to the left icon bar as well since that is the parent menu. Once the application is loaded when you click the icons the active class will become active if the item is selected. My issue is purely during load because if someone types in the URL the custom router link the left sidebar does not have any functionality linking it to the router since the links are in the right part of the sidebar. Any methodology built into vue to handle something like this? If not is there another method I could try?
My sidebar component code is below. The code basically creates two sides, the icon side and the menu side. The icons and menu's are developed using v-for and looping through the data set which provides the links and icons to use.
<template id="side-navigation">
<div :class="theme">
<nav :class="sidebarcontainer">
<div class="sidebar-left">
<div class="arms-icon">
</div>
<div class="main-menu-items">
<ul>
<li v-for="(item,i) in MainNavLinks"
:key="i"
:class="{'active-main-menu-item': i === activeIconIndex}"
v-on:click="selectIconItem(i)">
<a>
<i :class="item.icon"></i>
</a>
</li>
</ul>
</div>
<div class="bottom-menu-items">
<ul>
<li v-for="(item,i) in FeaturesNavLinks"
:key="i"
:class="{ 'active-main-menu-item': i+MainNavLinks.length === activeIconIndex}"
v-on:click="selectIconItem(i+MainNavLinks.length)">
<a>
<i :class="item.icon"></i>
</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-right" :class="{'active-right-sidebar' : isIconActive}">
<div class="sidebar-content">
<div class="searchbarcontent">
<div class="inputWithIcon">
<input placeholder="Search" id="sub-nav-seachbar" class="searchbar" type="text">
<i class="fas fa-search" id="searchicon-btn"></i>
</div>
</div>
<div v-for="(item,i) in MainNavLinks"
:key="i"
:class="{'active-sub-menu-item' : i === activeIconIndex}"
class="right-menu-content">
<ul>
<li v-for="(SubNavLink,i) in item.SubNavLinks"
class="sub-nav-group">
<h4 class="sub-nav-header">
{{SubNavLink.SubNavHeader}}
</h4>
<ul>
<li v-for="(SubNavMenuItem,i) in SubNavLink.SubNavMenuItems"
class="sub-nav-items">
<router-link :to="SubNavMenuItem.link"><span class="sub-menu-icons"><i :class="SubNavMenuItem.icon"></i></span>{{SubNavMenuItem.title}}</router-link>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</nav>
</div>
</template>
<script>
Vue.component('side-navigation', {
template: '#side-navigation',
methods: {
selectIconItem(i) {
if (this.activeIconIndex === i) {
if (this.isIconActive === true) {
this.isIconActive = false;
} else {
this.isIconActive = true;
}
} else {
this.activeIconIndex = i;
this.isIconActive = true;
}
},
},
data() {
return {
theme: 'color',
activeIconIndex: null,
isIconActive: false,
sidebarcontainer: 'sidebar-container',
MainNavLinks: [
{
name: 'Dashboard',
link: '/',
icon: 'fa fa-th-large fa-lg',
SubNavLinks: [
{
SubNavHeader: 'Dash Category 1',
SubNavMenuItems: [{
title: 'Item 1',
link: '/',
icon: 'fas fa-list-ul'
},
{
title: 'Item 2',
link: '/item2',
icon: 'fas fa-list-ul'
}]
},
{
SubNavHeader: 'Dash Category 2',
SubNavMenuItems: [{
title: 'Item 3',
link: '/item3',
icon: 'fas fa-list-ul'
},
{
title: 'Item 4',
link: '/item4',
icon: 'fas fa-list-ul'
}]
}
]
},
{
name: 'Reviews',
link: '/Reviews',
icon: 'far fa-clipboard fa-lg',
SubNavLinks: [
{
SubNavHeader: 'Reviews Category 1',
SubNavMenuItems: [{
title: 'Item 1',
link: '/item1',
icon: 'fas fa-list-ul'
},
{
title: 'Item 2',
link: '/item2',
icon: 'fas fa-list-ul'
}]
},
{
SubNavHeader: 'Reviews Category 2',
SubNavMenuItems: [{
title: 'Item 3',
link: '/item3',
icon: 'fas fa-list-ul'
},
{
title: 'Item 4',
link: '/item4',
icon: 'fas fa-list-ul'
}]
}
]
},
{
name: 'Upload',
link: '/Upload',
icon: 'fa fa-upload fa-lg',
SubNavLinks: [
]
},
{
name: 'Analytics',
link: '/Analytics',
icon: 'fas fa-chart-line fa-lg',
SubNavLinks: [
]
},
{
name: 'Files',
link: '/Files',
icon: 'far fa-folder-open fa-lg',
SubNavLinks: [
]
}
],
FeaturesNavLinks: [
{
name: 'Notifications',
link: '/',
icon: 'fas fa-bell fa-lg'
},
{
name: 'Chat',
link: '/',
icon: 'fas fa-comment-alt fa-lg'
},
{
name: 'Email',
link: '/',
icon: 'fas fa-envelope fa-lg'
},
{
name: 'Profile',
link: '/',
icon: 'fas fa-user fa-lg'
}
]
}
}
})
</script>
<style scoped>
.sidebar-container {
display: flex;
flex-direction: row;
box-shadow: 2px 0px 4px -1px rgb(0 0 0 / 15%);
position: sticky;
}
/*left icon section of sidebar*/
.sidebar-left {
display: flex;
flex-direction: column;
align-items: center;
width: 100px;
position: relative;
height: 100vh;
overflow-y: auto;
overflow-x: hidden;
}
.color .sidebar-left {
background-color: #ff7100;
}
.light .sidebar-left {
border-right: 1px solid #ebedf3;
}
.main-menu-items {
padding: 20px 20px;
flex-grow: 1;
}
.sidebar-left ul {
padding: 0px;
}
.sidebar-left li {
list-style-type: none;
text-align: center;
margin-bottom: 10px;
}
.sidebar-left a {
height: 50px;
width: 50px;
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
border-radius: .42rem;
}
.color .sidebar-left a:hover > *, .color .sidebar-left a:hover {
background-color: #da6000f7;
color: #fff !important;
}
.light .sidebar-left a:hover > *, .light .sidebar-left a:hover {
background-color: #f3f6f9;
color: #ff7d44 !important;
}
.color .active-main-menu-item a > *, .color .active-main-menu-item a {
background-color: #da6000f7;
color: #fff !important;
}
.light .active-main-menu-item a > *, .light .active-main-menu-item a {
background-color: #f3f6f9;
color: #ff7d44 !important;
}
.color .sidebar-left i {
color: #fff;
}
.light .sidebar-left i {
color: #a5a5a5;
}
/*right sidebar styling*/
.sidebar-right {
width: 0px;
position: relative;
transition: all 1s;
overflow: hidden;
height: 100vh;
overflow-y: auto;
}
.active-right-sidebar {
width: 325px;
transition: all 1s;
}
.sidebar-content{
padding:20px;
}
.right-menu-content {
display: none;
overflow: hidden;
white-space: nowrap;
padding: 0px 20px;
}
.active-sub-menu-item {
display: block;
}
/*sidebar searchbar*/
.searchbar {
width: 100%;
height: 40px;
border: 0px;
border-radius: 40px;
outline: none;
padding: 8px;
box-sizing: border-box;
transition: 0.3s;
letter-spacing: 2px;
background-color: #e6e6e6;
}
.inputWithIcon input[type="text"], .inputWithIcon input[type="password"] {
padding-left: 35px;
}
.inputWithIcon {
position: relative;
height: 40px;
overflow: hidden;
width: 100%;
}
.searchbarcontent {
padding: 0px 20px;
display: flex;
height: 50px;
width: 100%;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
#searchicon-btn {
padding: 9px 25px 9px 5px;
top: 4px;
color: #aaa;
position: absolute;
right: 0px;
cursor: pointer;
}
.sidebar-right ul {
padding: 0px;
}
.sidebar-right li {
list-style-type: none;
}
.sidebar-right a {
text-decoration: none;
}
.sub-nav-header {
display: flex;
align-items: center;
height: 50px;
font-size: 1rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .3px;
color: #7e8299;
}
.sub-nav-items {
display: flex;
align-items: center;
height: 45px;
font-size: .9rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .3px;
}
.sub-nav-items a {
color: #7f818d;
}
.sub-nav-group{
margin-bottom: 15px;
}
.sub-menu-icons {
width: 30px;
padding-right: 20px;
}
.router-link-exact-active {
color: #ff7100 !important;
}
/*scrollbar*/
/* custom scrollbar */
::-webkit-scrollbar {
width: 20px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #00000014;
border-radius: 20px;
border: 6px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: #0000001f;
}
</style>
Use nested routes.
Parent <router-link>'s should have the class .router-link-active.
The exact <router-link> should have .router-link-exact-active.
Check out this code for an interactive example.
Trying to implement the overlay fullscreen menu with Vue.js, html/css/js is [this solution]https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_overlay2
But stuck with how to toggle div height from 0% to 100%. I did create 2 classes,
'navbar'
'navbar_open'
but I am not sure how to toggle between them in Vue. I could see that once #click triggered, the class="navbar navbar_open"
<div id="myNav" class="navbar navbar_open">
<div class="closebtn">
<i class="fa fa-times"></i>
</div>
<div class="navbar-content">
<a>Home</a><a>Contact</a>
</div>
</div>
below is the App.vue file,
<template>
<div id="app">
<!-- Banner/Header -->
<!-- Hamburger -->
<div id="myNav" class="navbar" :class="{ navbar_open: showNavbar }">
<div class="closebtn" v-on:click="showNavbar = !showNavbar">
<i class="fa fa-times"></i>
</div>
<div class="navbar-content">
<a>Home</a>
<a>Contact</a>
</div>
</div>
<div class="openbtn">
<i class="fa fa-bars" v-on:click="showNavbar = !showNavbar"></i>
</div>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
showNavbar: false
};
},
methods: {
toggleNavbar() {
this.showNavbar = !showNavbar;
},
setHeightValue(showNavbar) {
const heightValue = this.showNavbar ? '100%' : '0%';
return heightValue;
}
},
created() {
this.setHeightValue();
}
};
</script>
<style>
#import url('https://use.fontawesome.com/releases/v5.9.0/css/all.css');
.navbar_open {
width: 100%;
height: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.9);
overflow-y: hidden;
transition: 0.5s;
background-color: #2b4c72;
}
.navbar {
width: 100%;
height: 0%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.9);
overflow-y: hidden;
transition: 0.5s;
background-color: #2b4c72;
}
.navbar-content {
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
}
.navbar a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #818181;
display: block;
transition: 0.3s;
}
.navbar a:hover,
.navbar a:focus {
color: #f1f1f1;
}
.navbar .closebtn {
position: absolute;
top: 20px;
left: 45px;
font-size: 60px;
color: white;
cursor: pointer;
}
.openbtn {
font-size: 30px;
}
#media screen and (max-height: 450px) {
.navbar {
overflow-y: auto;
}
.navbar a {
font-size: 20px;
}
.navbar .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
</style>
I see that you have unused method toggleNavbar. You call setHeightValue only when your component is created and then never again (I think you can remove this method). This menu is not 100% height probably because you embedded this component in another container (<div id="app:...) which has smaller height so height: 100% will be 100% height of parent container. Instead of 100% you can use 100vh (vh - is a viewport unit and it will always take 100% viewport height [if 50vh then 50% of total viewport height]). You should also apply only navbar_open but now you are applying bot classes if your navbar is open: navabar navbar_open so you should add this classes conditionally:
:class="{ 'navbar_open': showNavbar, 'navbar': !showNavbar }"
You have also Two different buttons responsible for two different actions:
closebtn -> close navigation
openbtn -> open navigation
So you should create two different methods openNavigation closeNavigation
<div id="app">
<!-- Banner/Header -->
<!-- Hamburger -->
<div id="myNav" :class="{ 'navbar_open': showNavbar, 'navbar': !showNavbar }">
<div class="closebtn" #click="closeNavigation">
<i class="fa fa-times"></i>
</div>
<div class="navbar-content">
<a>Home</a>
<a>Contact</a>
</div>
</div>
<div class="openbtn">
<i class="fa fa-bars" #click="showNavigation"></i>
</div>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
showNavbar: false
};
},
methods: {
openNavigation() {
this.showNavbar = true;
},
closeNaviagation() {
this.showNavbar = false;
}
}
};
</script>
<style>
...
.navbar_open {
width: 100%;
height: 100vh; // <--- 100vh instead of 100%
position: fixed;
...
</style>
I have a working calendar that can change based on the type property. I am able to display information in the calendar header but day events seem to be a problem.
My vue.js vuetify calendar does not display day events. It is set to display as type 'week'. I am working from the following example.
export default {
data: () => ({
todayDate: new Date().toISOString().substr(0, 10) /*'YYYY-MM-DD'*/ ,
type: 'week',
events: [{
title: 'Weekly Meeting',
date: '2019-02-26',
time: '09:00',
duration: 45
},
{
title: 'Mash Potatoes',
date: '2019-02-28',
time: '12:30',
duration: 180
}
]
}),
computed: {
eventsMap() {
const map = {};
this.events.forEach(e => (map[e.date] = map[e.date] || []).push(e));
return map
}
}
}
</script>
<v-calendar ref="calendar" :type="type" v-model="todayDate" :now="todayDate" :value="todayDate" color="primary">
<template slot="dayBody" slot-scope="{ date, timeToY, minutesToPixels }">
<template v-for="event in eventsMap[date]">
<div
v-if="event.time"
:key="event.title"
v-html="event.title"
></div>
</template>
</template>
</v-calendar>
You are probably missing event styles which are included in docs. Copy styling and edit your html file
.my-event {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border-radius: 2px;
background-color: #1867c0;
color: #ffffff;
border: 1px solid #1867c0;
font-size: 12px;
padding: 3px;
cursor: pointer;
margin-bottom: 1px;
left: 4px;
margin-right: 8px;
position: relative;
&.with-time {
position: absolute;
right: 4px;
margin-right: 0px;
}
}
</script>
<v-calendar ref="calendar" :type="type" v-model="todayDate" :now="todayDate" :value="todayDate" color="primary">
<template slot="dayBody" slot-scope="{ date, timeToY, minutesToPixels }">
<template v-for="event in eventsMap[date]">
<div
v-if="event.time"
:key="event.title"
:style="{ top: timeToY(event.time) + 'px', height: minutesToPixels(event.duration) + 'px' }"
class="my-event with-time"
v-html="event.title"
></div>
</template>
</template>
</v-calendar>
One of the reason could be Events are not displaying because you are missing color property in Events objects. Without color property, Events are present but not visible because by default color is white.
{
color: 'indigo',
name: 'Weekly Meeting',
date: '2019-02-26',
time: '09:00',
duration: 45
},