For this website, I have two login tabs as seen in the image below and for the selected tab it shows an icon next to it, but to make it more visible that this tab is selected I want to add some sorta box-shadow or something, but for now, it shows the box-shadow for both of the tabs and I just can't get my head around how to make it only show for the selected Tab.
This is the code that I have - I tried to add v-if statement, but it won't work as I already have v-for so If there is any way how to make this work I would be really happy if you could help me out here. Thank you in advance!
<template>
<v-main id="login">
<v-container fill-height fluid>
<v-layout align-center justify-center>
<v-flex md4 sm8 xs12>
<v-card class="elevation-12">
<v-toolbar color="primary" dark>
<v-toolbar-title>
<v-icon left> mdi-login-variant </v-icon>
{{ $t("welcome") }}
</v-toolbar-title>
</v-toolbar>
<v-divider />
<v-tabs v-model="selectedTab" grow hide-slider>
<v-tab
v-for="(tab, i) in tabs"
:key="i"
:class="{
'primary white--text': tab == selectedTab,
caption: tab != selectedTab,
}"
:href="`#${tab}`"
id="boxShadow" //This is where I added the ID
class="pa-0"
>
{{ tab }}
<v-icon id="IconPosition" v-if="tab === selectedTab"
>mdi-login-variant</v-icon
>
</v-tab>
<v-tab-item
v-for="(tab, i) in tabs"
:key="i"
:value="tab"
reverse-transition="scale-transition"
transition="scale-transition"
>
<v-divider />
<v-card-text>
<v-form #submit.prevent="login">
<v-text-field
v-model.lazy="username"
:label="$t('username')"
:prepend-inner-icon="
tab === 'Windows'
? 'mdi-microsoft-windows'
: 'mdi-account'
"
:rules="[username !== null || required]"
name="username"
outlined
placeholder=" "
type="text"
/>
<v-text-field
v-model.lazy="password"
:label="$t('password')"
:rules="[password !== null || required]"
name="password"
outlined
placeholder=" "
prepend-inner-icon="mdi-lock"
type="password"
/>
<!-- If error, rended error component -->
<error-view
v-if="error"
:error="error"
:is-login="true"
class="pa-0"
/>
<v-card-actions class="pa-0">
<v-spacer />
<v-btn :loading="loading" color="primary" type="submit">
{{ $t("submit") }}
</v-btn>
</v-card-actions>
</v-form>
</v-card-text>
</v-tab-item>
</v-tabs>
<div id="version-div">
<app-version />
</div>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-main>
</template>
<script>
import AppVersion from "#/components/version";
const errorView = () => import("#/components/errorView");
export default {
name: "Login",
components: {
errorView,
AppVersion,
},
data() {
return {
tabs: ["Windows", "Standard"],
selectedTab: "Standard",
username: null,
password: null,
loading: false,
error: null,
required: (value) => !!value || this.$t("req"),
};
},
methods: {
resetForm(value) {
this.username = this.password = value;
},
login() {
if (!this.username || !this.password) {
this.error = this.$t("warn");
this.resetForm(null);
} else {
this.loading = true;
const encodedPass = window.btoa(
unescape(encodeURIComponent(this.password))
);
this.$store
.dispatch("retrieveUser", {
username: this.username,
password: encodedPass,
outside: this.selectedTab === "Windows" ? false : true,
})
.then(() => {
this.$router.push({ name: "home" });
this.error = null;
})
.catch((error) => {
this.error = error;
})
.finally(() => {
this.resetForm("");
this.loading = false;
});
}
},
},
};
</script>
<style>
#boxShadow {
-moz-box-shadow: inset 0 0 10px #000000;
-webkit-box-shadow: inset 0 0 10px #000000;
box-shadow: inset 0 0 10px #000000;
}
</style>
the id attribute should be unique, in your case the rendered tab will have the same id, try out to name the #boxShadow to a class .boxShadow like :
<style>
.boxShadow {
-moz-box-shadow: inset 0 0 10px #000000;
-webkit-box-shadow: inset 0 0 10px #000000;
box-shadow: inset 0 0 10px #000000;
}
</style>
then bind it conditionally :
<v-tab
v-for="(tab, i) in tabs"
:key="i"
:class="{
'primary white--text': tab == selectedTab,
caption: tab != selectedTab,
boxShadow: tab === selectedTab,
}
or just :
:class="{
'primary white--text boxShadow': tab == selectedTab,
caption: tab != selectedTab,
}
Related
I am using Ant Design on my React.js application. I used Table component. I have two columns: one for an input number field, and another for input field and will be editable on hover. When I hover on each row, there is a flicker issue which does not happen if I have input number field only or an input field only. When I have them both, it is like having an extra margin top or padding. When I check the dev tools, there were no added styling. I even adjust its min-height but no effect.
Flickering issue when hovering on table row
const columns = [
{
render: (_, { id, value }, index) => {
if (editingRow === id) {
return (
<Form.Item
name="value"
style={{ margin: 0 }}
>
<div onBlur={() => setEditingRow(null)}>
<InputNumber
value={value}
onChange={numValue => {
onChange(
{ id, value: numValue },
);
}}
/>
</div>
</Form.Item>
);
} else {
return (
<Form.Item style={{ margin: 0 }}>
<Input value={value} disabled />
</Form.Item>
);
}
}
},
{
render: (_, { id, title }, index) => {
if (editingRow === id) {
return (
<Form.Item
name="value"
style={{ margin: 0 }}
>
<div onBlur={() => setEditingRow(null)}>
<Input
value={value}
onChange={event => {
event.persist();
onChange(
{ id, title: event.target.value },
);
}}
/>
</div>
</Form.Item>
);
} else {
return (
<Form.Item style={{ margin: 0 }}>
<Input value={value} disabled />
</Form.Item>
);
}
}
},
]
Here, I have setup laravel 6 project with vue and vuetify. I am trying to create crud table where I am trying to fetch data from vuex store but for some I am not able to see my action button. I can see my table with data but action coulmn is empty. I have created store folder and inside my store folder I have Store.js file.
Stage.vue
<template>
<div>
<h1 class="text-xs-center info--text mb-2">{{ message }}</h1>
<v-data-table
:headers="headers"
:items="items"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.code }}</td>
<td class="text-xs-right">{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.description }}</td>
<td class="justify-center layout px-0">
<v-btn icon class="mx-0" #click="editItem(props.item)">
<v-icon color="teal">edit</v-icon>
</v-btn>
<v-btn icon class="mx-0" #click="deleteItem(props.item)">
<v-icon color="pink">delete</v-icon>
</v-btn>
</td>
</template>
<template slot="no-data">
<v-alert :value="true" color="error" icon="warning">
Sorry, nothing to display here :(
</v-alert>
</template>
</v-data-table>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ on }">
<v-btn color="error" dark class="mb-2" v-on="on">Add New Stage</v-btn>
</template>
<v-card>
<v-card-title>
<span>{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm6 md4>
<v-text-field label="Code" v-model="editedItem.code"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field label="Name" v-model="editedItem.name"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field label="Description" v-model="editedItem.description"></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text #click.native="close">Cancel</v-btn>
<v-btn color="blue darken-1" text #click.native="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
name: 'Stage',
props: {
},
data: () => ({
dialog: false,
editedIndex: -1,
editedItem: {
code: '',
name: '',
description: ''
},
defaultItem: {
code: '',
name: '',
description: ''
}
}),
computed: {
message () {
return this.$store.getters.getMessage
},
headers () {
return this.$store.getters.getHeaders
},
items () {
return this.$store.getters.getItems
},
formTitle () {
return this.editedIndex === -1 ? 'New Stage' : 'Edit Stage'
}
},
watch: {
dialog (val) {
val || this.close()
}
},
methods: {
editItem (item) {
this.editedIndex = this.items.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.items.indexOf(item)
confirm('Are you sure you want to delete this item?') && this.$store.commit('deleteItem', index)
// Todo: Make this delete item from store
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.items[this.editedIndex], this.editedItem)
// TODO: Edit item in the store.
this.$store.commit('updateItem', this.editedItem, this.editedIndex)
} else {
this.$store.commit('newItem', this.editedItem)
}
this.close()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
msg: 'Vuetify table of Vuex state items.',
headers: [
{
text: 'Code',
align: 'left',
sortable: true,
value: 'code'
},
{ text: 'Name', value: 'name' },
{ text: 'Description', value: 'description' },
{ text: 'Actions', value: 'description', sortable: false }
],
items: [
{
value: 'false',
code: 23,
name: 'dsvdf',
description: 'Le Manns'
},
{
value: 'false',
code: 1,
name: 'ddd',
description: 'Le Manns'
}
]
},
mutations: {
newItem (state, payload) {
state.items.push(payload)
},
deleteItem (state, payload) {
state.items.splice(payload, 1)
},
updateItem (state, payload, index) {
state.items[index] = payload
}
},
actions: {
},
getters: {
getMessage (state) {
return state.msg
},
getHeaders (state) {
return state.headers
},
getItems (state) {
return state.items
}
}
})
In the state.headers property of your store, you have:
{ text: 'Actions', value: 'name', sortable: false }
This should be:
{ text: 'Actions', value: 'action', sortable: false }
The value property has the wrong value. Also, you have not assigned the imported headers and items to the v-data-table element. It should be:
<v-data-table
:headers="headers"
:items="items"
>
<!-- ... the rest of your code ... -->
Here is a working codepen.
I am trying to pass a parameter to a function by looping through an the array items with v-for.
<template>
<v-app>
<v-app-bar app>
<v-app-bar-nav-icon #click="drawer = !drawer"></v-app-bar-nav-icon>
<v-spacer></v-spacer>
<h1 ref="y"></h1>
</v-app-bar>
<v-content>
<router-view />
<v-navigation-drawer v-model="drawer" class="x">
<v-list-item
v-for="item in items"
:key="item.unidade"
:to="item.link"
:#click="change(item.method)"
>{{item.unidade}}</v-list-item>
</v-navigation-drawer>
</v-content>
</v-app>
</template>
<script>
export default {
name: "App",
data: () => ({
items: [
{ unidade: "IPE", link: "/ipe", method: "IPE" },
{ unidade: "DCSI", link: "/dcsi", method: "DCSI" },
{ unidade: "RT", link: "/rt", method: "RT" }
],
drawer: false
}),
methods: {
change(val) {
console.log(val);
this.$refs.y.innerText = val;
}
}
};
</script>
<style lang="stylus" scoped>
.x {
position: absolute;
}
</style>
I want the parameter in items arrray to be passed to change(val) method giving each v-list-item a distinct event listener.
Then I want h1 with the ref="y" to change it's text based on the v-list-item I click. But so far I am getting the browser error of "Error in render: "TypeError: Cannot set property 'innerText' of undefined""
Instead of setting the innerText of the <h1> you could instead bind the innerText to a reactive variable. You could create a variable in data that could store the selected method and then bind that to the innerText using {{}} syntax. Doing it this way would be more inline with Vue best practices. Let me show you what I mean.
<template>
<v-app>
<v-app-bar app>
<v-app-bar-nav-icon #click="drawer = !drawer"></v-app-bar-nav-icon>
<v-spacer></v-spacer>
<h1 ref="y">{{ selectedMethod }}</h1>
</v-app-bar>
<v-content>
<router-view />
<v-navigation-drawer v-model="drawer" class="x">
<v-list-item
v-for="item in items"
:key="item.unidade"
:to="item.link"
:#click="change(item.method)"
>{{item.unidade}}</v-list-item>
</v-navigation-drawer>
</v-content>
</v-app>
</template>
<script>
export default {
name: "App",
data: () => ({
items: [
{ unidade: "IPE", link: "/ipe", method: "IPE" },
{ unidade: "DCSI", link: "/dcsi", method: "DCSI" },
{ unidade: "RT", link: "/rt", method: "RT" }
],
selectedMethod: '', // Initially blank
drawer: false
}),
methods: {
change(val) {
this.selectedMethod = val; // Update the value of selectedMethod
}
}
};
</script>
<style lang="stylus" scoped>
.x {
position: absolute;
}
</style>
Hope this helps!
I'm creating a voting system. For both positive and negative votes, i use the same component - VoteButton. How to change the icon ( 'fa-thumbs-o-up' to 'fa-thumbs-up' and 'fa-thumbs-o-down' to 'fa-thumbs-down') when the button is activated? Which is the best option - via CSS (:before), vue.js logic ( IF or something), replace string via JS or something else?
Parent component:
<GridLayout columns="auto,*">
<VoteButton col="0" :buttontext=" 'fa-thumbs-o-up' | fonticon" :votes="upVotes" label="Upvote" :active="upvoted" width="33%" #click="vote(1)" />
<VoteButton col="1" :buttontext=" 'fa-thumbs-o-down' | fonticon" :votes="downVotes" label="Downvote" :active="downvoted" width="33%" #click="vote(-1)" />
</GridLayout>
Parent component CSS:
.upvote.active {
background: orangered;
color: white;
}
.downvote.active {
background: blue;
color: white;
}
VoteButton child component:
<template>
<button #tap="$emit('click')" :class="[buttonClass, { active }]">
<FormattedString>
<Span class="fa" > {{ buttontext }}</Span>
<Span> {{ votes }}</Span>
</FormattedString>
</button>
</template>
<script>
export default {
props: {
active: Boolean,
label: String,
buttontext: String,
votes: Number
},
computed: {
buttonClass() {
return this.label.toLowerCase();
}
}
};
</script>
You could use a counter in javascript to keep track of whether the button should be displaying an upvote or a downvote based on the number of times the button is pressed.
Example:
Html:
<button onclick="myFunction()">Try it</button>
<div id="myDIV">
This is a DIV element.
</div>
CSS:
<style>
.mystyle {
background: orangered;
color: white;
}
.mystyle2 {
background: blue;
color: white;
}
</style>
Javascript:
<script>
var x = 0;
function myFunction() {
var element = document.getElementById("myDIV");
if (x % 2 == 0){
element.classList.add("mystyle");
element.classList.remove("mystyle2");
x++;
}
else {
element.classList.add("mystyle2");
element.classList.remove("mystyle");
x++;
}
}
</script>
Thanks! I did it the following way:
Parent:
<VoteButton col="0" noactivefatext='fa-thumbs-o-up' activefatext='fa-thumbs-up' :votes="upVotes" label="Upvote" :active="upvoted" #click="vote(1)" />
<VoteButton col="1" noactivefatext='fa-thumbs-o-down' activefatext='fa-thumbs-down' :votes="downVotes" label="Downvote" :active="downvoted" #click="vote(-1)" />
VoteButton component:
<template>
<button #tap="$emit('click')" :class="[buttonClass, { active }]">
<FormattedString>
<Span class="fa body" :text="active ? activefatext : noactivefatext | fonticon" ></Span>
<Span> {{ votes }}</Span>
</FormattedString>
</button>
</template>
I have read through many posts/information about Z index and still have not been able to figure this out, I have a website with the navbar position fixed so it stays on the top of the page on scroll, when I get down below my header (component where the navbar is placed), all the elements appear ABOVE the navbar when scrolled over (which is obviously not desired), I am able to put a zIndex of -1 on those elements to fix this, however currently I have a form, and making its zIndex -1 makes all the form inputs and submit button disabled or unclickable (guessing it puts the form below another div/element), so I'm pretty stuck and appreciate any advice .. :)
Navbar.js
import React, { Component } from "react";
import Radium from "radium";
class NavBar extends Component {
state = {
topOfPage: true,
headerSection: true
};
componentDidMount() {
window.addEventListener("scroll", this.navBarState);
}
componentWillUnmount() {
window.removeEventListener("scroll", this.navBarState);
}
navBarState = () => {
if (window.scrollY < 58) {
this.setState({
topOfPage: true
});
}
if (window.scrollY > 58 && window.scrollY < 740) {
this.setState({
topOfPage: false,
headerSection: true
});
}
if (window.scrollY > 740) {
this.setState({
headerSection: false
});
}
};
render() {
const { topOfPage, headerSection } = this.state;
let navStyle;
let linkStyle;
if (topOfPage && headerSection) {
navStyle = {
base: {
background: "transparent",
transition: "background-color 0.7s ease"
}
};
linkStyle = {
base: {
transition: "font-size 0.8s",
":hover": {
color: "black",
fontSize: "25px",
fontWeight: "bold",
background: "white",
textTransform: "uppercase",
paddingTop: "10px",
borderRadius: "50px"
}
}
};
} else if (!topOfPage && headerSection) {
navStyle = {
base: {
background: "rgba(20, 20, 20, 0.87)",
boxShadow: "0 8px 6px -6px",
transition: "background-color 0.7s ease"
}
};
linkStyle = {
base: {
transition: "font-size 0.5s",
":hover": {
color: "white",
fontSize: "25px",
fontWeight: "bold"
}
}
};
} else {
navStyle = {
base: {
background: "rgba(20, 20, 20, 0.99)",
boxShadow: "0 8px 6px -6px"
}
};
linkStyle = {
base: {
transition: "font-size 0.5s",
":hover": {
color: "white",
fontSize: "25px",
fontWeight: "bold"
}
}
};
}
return (
<nav style={[navStyle.base]}>
<ul className="navbarWrapper">
<li>
<a href="#!" style={[linkStyle.base]} key="1">
Home
</a>
</li>
<li>
<a href="#!" style={[linkStyle.base]} key="2">
Beat Store
</a>
</li>
<li>
<a href="#!" style={[linkStyle.base]} key="3">
Licensing
</a>
</li>
<li>
<a href="#!" style={[linkStyle.base]} key="4">
Drum Kits
</a>
</li>
<li>
<a href="#!" style={[linkStyle.base]} key="5">
Contact Us
</a>
</li>
</ul>
</nav>
);
}
}
export default Radium(NavBar);
Form.js
import React from "react";
import { Form, Button, Grid, Segment, Input } from "semantic-ui-react";
const FreeBeatForm = () => {
return (
<Grid
container
style={{
marginTop: "50px",
display: "flex",
justifyContent: "center",
}}
>
<Grid.Column width={5} style={{zIndex: '-1'}}>
<Segment>
<h1>Subscribe</h1>
<Form>
<Form.Field>
<label>Name</label>
<Input placeholder="Name" />
</Form.Field>
<Form.Field>
<label>Email</label>
<Input placeholder="Email" />
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</Segment>
</Grid.Column>
</Grid>
);
};
export default FreeBeatForm;
Try to leave out the z-index for your components in the page, instead make sure your NavBar as position:fixed and it has a higher z-index, for example you could use 1000.
I'm guessing it has something to do with the semantic ui components, because changing my semantic Inputs to bootstrap inputs fixed the issue..