Vue.js how to use tabs to load different components - javascript

I am trying to use a click event on my tabs to set the value of a variable inside data() I then use this variable in an if statement on my components to test the value and display the component if true. But this isn't working and I'm getting no errors. I assume that the value of the variable isn't being set when the click event on the tabs fires. Can I not achieve the functionality with this method?
<template>
<div id="settings_page" class="page_body">
<h1>Settings</h1>
<div id="user_info" v-if="user">
<div id="tabs">
<div v-on:click="selected_tab == 'account'">Account Details</div>
<div v-on:click="selected_tab == 'divisions'">Divisions</div>
<div v-on:click="selected_tab == 'users'">Users</div>
<div v-on:click="selected_tab == 'columns'">Columns</div>
</div>
<div class="content">
<div v-if="selected_tab == 'account'">
<h2>Profile</h2>
</div>
<div v-if="selected_tab == 'divisions'">
divisions
</div>
<div v-if="selected_tab == 'users'">
users
</div>
<div v-if="selected_tab == 'columns'">
columns
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
data() {
return {
selected_tab: 'account'
}
},
computed:mapGetters(['user']),
methods: {
...mapActions(['getProfile'])
},
created() {
this.getProfile();
}
}
</script>

You're doing a comparison in the click event handler :
v-on:click="selected_tab == 'account'"
You should use assignment like :
v-on:click="selected_tab = 'account'"

Related

pass component according to v-if - Vue.JS

I am trying to create a parent component with all kinds of graphics, and depending on what I need to pass on a specific graphic (raise a child) to another component, but I don't necessarily know how I would dynamically do it for the user.
my html charts (chart.vue)
<template>
<div >
<bars v-if="type == 'bar'">
<div class="row gutter-sm">
<div class="col-md-3">
<apexchart ref="chart1" type="bar" :options="options" :series="updatedData"></apexchart>
</div>
</div>
<div class="col-md-3">
<apexchart ref="chart3" type="bar" :options="options3" :series="updatedData"></apexchart>
</div>
</bars>
<lines v-if="type == 'line'">
<div class="row gutter-sm">
<div class="col-md-3">
<apexchart ref="chart4" type="line" :options="options4" :series="updatedData"></apexchart>
</div>
</div>
</lines>
</div>
<template>
If I wanted to pass on bar graphics to my menu.vue, would it be like this?
my html menu
<template>
<div >
<table class="data-table-2" style="min-width: 800px">
<charts type="bar"/>
</table>
</div>
<template>
scripts menu
<script>
import charts from "./charts.vue"
export default {
name: 'menu',
components: {
charts
}
}
</script>
The way you pass values from the parent component to the child component is wrong
<template>
<div >
<table class="data-table-2" style="min-width: 800px">
<charts :type='bar'/>
<charts :type='line'/>
<charts />
</table>
</div>
<template>
child component receiving value, and you can set a default value:
// init in child component
props: {
type: {
type: String,
default: 'bar' // set a default value
}
},
data(){
...
}
then you can use type in child component
<template>
<div >
<bars v-if"type == 'bar'">
<div class="row gutter-sm">
<div class="col-md-3">
<apexchart ref="chart1" type="bar" :options="options" :series="updatedData"></apexchart>
</div>
</div>
<div class="col-md-3">
<apexchart ref="chart3" type="bar" :options="options3" :series="updatedData"></apexchart>
</div>
</bars>
<lines v-if"type == 'line'">
<div class="row gutter-sm">
<div class="col-md-3">
<apexchart ref="chart4" type="line" :options="options4" :series="updatedData"></apexchart>
</div>
</div>
</lines>
</div>
<template>
You need to define a Props in child component.
//Child Component Script
export default ChildComponent {
data() {
return {}
},
props: {
type: string,
}
}
In parent component you need to call child component and pass type data like this
//parent component
<template>
<div>
<child-component :type="line"/>
</div>
</template>

Vue JS, Modal Window through components

I need to make the modal visible on click, I work through components, new Vue constructs do not work
I've never worked with Vue, now I'm asking for help
Error:
64:4 error 'showModal:' is defined but never used no-unused-labels
<template>
<modalPhoto v-if="showModal == 'true'"></modalPhoto>
<div class="block-inputs">
<div class="input-header">
<h3>Photos</h3>
</div>
<div class="photos">
<div class="photo-block">
<img src="../assets/photo.jpg" class="photo modal-img" v-on:click="viewPhoto('true')">
</div>
</div>
</div>
<div class="save-changes">
<div style="margin: 0 auto;">
<button class="button-add button-save">Save</button>
</div>
</div>
<script>
import modalPhoto from './modal/modalPhoto.vue';
export default {
name: 'Photos',
data() {
showModal: false
},
methods: {
viewPhoto() {
this.showModal = true;
}
},
components: {
modalPhoto,
}
}

Get child element on click - Vue JS

I need an equivalent of jQuery "this.find()" to get child element from this section on click.
So on click="showProd(6) I want to find "this .dropProd" inside a method ":
Image
<div class="sections" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<div class="dropProd" :class="{ activate : active_el == 6}">
<div v-for="item in shelf" :key="item.id" class="niceBox">
<p class="prod_title">{{item.title}}</p>
<p class="prod_info">{{item.product_details}}</p>
</div>
</div>
</div>
You can use $refs:
<div class="sections" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<!-- note the ref attribute below here -->
<div ref="dropProd" class="dropProd" :class="{ activate : active_el == 6}">
<div v-for="item in shelf" :key="item.id" class="niceBox">
<p class="prod_title">{{item.title}}</p>
<p class="prod_info">{{item.product_details}}</p>
</div>
</div>
</div>
Access it in <script> via this.$refs.dropProd
You could just use this.$refs with an appropriate reference name inside your function like this:
new Vue({
el: '#app',
data: function() {
return {
}
},
methods: {
showProd(){
console.log(this.$refs.referenceMe);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="sections"style="background-color: red" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<div class="dropProd" ref="referenceMe">
</div>
</div>
</div>

Vue.js toggling expanding v-for component from parent

I've got an 'Album' component that is being used on a page. I am trying to create something whereby only one album can be toggled at a given time. So if an album is already open when clicking another it would close.
Component being mounted recursively in the 'parent' app.
<album v-for="(album, index) in albums"
:key="index"
#expand="setAlbumContainerHeight"
#action="removeFromCollection"
:albumDetails="album"
page="collection">
</album>
The component itself.
<template>
<div v-on:click="toggleExpand" ref="album" class="album">
<img class="album-artwork" alt="album-artwork" :src="albumDetails.cover_url">
<div ref="expandContent" class="expanded-content">
<div class="left-block">
<div class="title">{{ albumDetails.title }}</div>
<div class="artist">{{ albumDetails.artist }}</div>
<!-- Search page specific -->
<div v-if="page === 'search'" class="info">{{ albumDetails.year }}<br> <span v-for="genre in albumDetails.genre"> {{ genre }}</span><br> {{ albumDetails.label }}</div>
<!-- Collection page specific -->
<div v-if="page === 'collection'" class="info">{{ albumDetails.year }}<br> <span v-for="genre in albumDetails.genres"> {{ genre.genre }}</span><br> {{ albumDetails.label }}</div>
<!-- Search page specific -->
<button v-if="page === 'search'" v-on:click.stop="addToCollection" class="add-collection">Add to collection</button>
<!-- Collection page specific -->
<button v-if="page === 'collection'" v-on:click.stop="removeFromCollection" class="add-collection">Remove from collection</button>
</div>
<div v-if="page === 'search'" class="right-block">
<div class="a-side">
<p v-for="track in albumDetails.track_list_one" class="track">{{ track }}</p>
</div>
<div class="b-side">
<p v-for="track in albumDetails.track_list_two" class="track">{{ track }}</p>
</div>
</div>
<div v-if="page === 'collection'" class="right-block">
<div class="a-side">
<p v-for="track in trackListOne" class="track">{{ track.track }}</p>
</div>
<div class="b-side">
<p v-for="track in trackListTwo" class="track">{{ track.track }}</p>
</div>
</div>
<img class="faded-album-artwork" alt="faded-album-artwork" :src="albumDetails.cover_url">
</div>
</div>
</template>
<script>
module.exports = {
name: 'Album',
props: ['albumDetails', 'page'],
data: function () {
return {
expanded: false,
expandedContentHeight: 0,
trackListOne: [],
trackListTwo: []
}
},
mounted() {
if (this.albumDetails.tracks) {
this.getTrackListOne(this.albumDetails.tracks);
this.getTrackListTwo(this.albumDetails.tracks);
}
},
methods: {
toggleExpand() {
if (!this.expanded) {
this.expanded = true;
this.$refs.expandContent.style.display = 'flex';
this.expandedContentHeight = this.$refs.expandContent.clientHeight;
let height = this.$refs.album.clientHeight + this.expandedContentHeight;
this.$emit('expand', height, event);
} else {
this.expanded = false;
this.$refs.expandContent.style.display = 'none';
let height = 'initial';
this.$emit('expand', height, event);
}
},
addToCollection() {
this.$emit('action', this.albumDetails.cat_no);
},
removeFromCollection() {
this.$emit('action', this.albumDetails.cat_no);
},
getTrackListOne(tracks) {
let halfWayThough = Math.floor(tracks.length / 2);
this.trackListOne = tracks.slice(0, halfWayThough);
},
getTrackListTwo(tracks) {
let halfWayThough = Math.floor(tracks.length / 2);
this.trackListTwo = tracks.slice(halfWayThough, tracks.length);
},
},
}
</script>
<style scoped lang="scss">
#import './styles/album';
</style>
The component itself is storing its state with a simple 'expanded' data attribute. Currently this means that the component works nicely when a user is opening and closing each album, however, problems occur when they are opening several at a time. Due to absolute positioning I am manually having to set the height of the container. The aim is to have only one open at a time. I am having trouble thinking of a way to store and track what album is currently open - I'm also unsure how the parent can manage the stage each album / open and closing them where. Even if I know which album is open in the parent how can I trigger individual child components methods?
I've tried to be as clear as possible, please let me know if there's anything else I can make clearer.
I'm not quite sure what you mean by recursive, as far as I can see you're not referencing the album component within itself recursively.
I'd go with this approach:
expanded is a property of your component.
On a click the component emits a this.$emit('expand', albumID).
In your parent you listen for the #expand event and assign your expandedAlbumID to the event payload.
The last remaining piece of the puzzle is now to pass your expanded property like :expanded="expandedAlbumID == album.id"
Full working example: https://codesandbox.io/s/o5p4p45m9

React.js modify child element on parent click

I have a following react component:
<li key={contact.id} class="option contact-item">
<div class="thumbnail">
<a><span>{contact.name.slice(0, 1)}</span></a>
</div>
<div class="text">
<div class="label">
<div class="name">{contact.name}</div>
<div class="status">{contact.status}</div>
</div>
<div class="select-container">
<div class="select">
<i class="icon-check"></i>
</div>
</div>
</div>
</li>
I need to toggle the color of <i class="icon-check"></i> when clicking the whole <li>
How can I do that?
Firstly, in react, you don't use class, you use className.
See this for full code: https://codepen.io/pen?editors=0010
Using state, you can change styles/classes/etc
_handleClick(key) {
let clicked = this.state.myList.filter(f => f.id === key)[0];
this.setState({ clicked: clicked });
}
_changeColor(key) {
if (this.state.clicked.id === key) {
return 'icon-checked';
}
else
return 'icon-check';
}
_renderList() {
return this.state.myList.map(contact => (
<li key={contact.id}
onClick={() => this._handleClick(contact.id)}
className="option contact-item">
<i className={this._changeColor(contact.id)}></i>
{contact.name}
</li>
));
}
render() {
return (
<div>
<h1>Hello</h1>
<ul>
{this._renderList()}
</ul>
</div>
);
}
You can set "changeColor" state on <li> click and your <i> can handle this state. If you change component state React will rerender your component.
<li onClick={this.changeColor()} key={contact.id} className="option contact-item">
<div className="thumbnail">
<a><span>{contact.name.slice(0, 1)}</span></a>
</div>
<div className="text">
<div className="label">
<div className="name">{contact.name}</div>
<div className="status">{contact.status}</div>
</div>
<div className="select-container">
<div className="select">
<i className="icon-check" style={if (this.state.colorChanged) {color: 'red'}}></i>
</div>
</div>
</div>
changeColor() {
this.setState({colorChanged: true});
}
I made a simple example for you, it works with a sinle list item Check this out.
If you have a list of items, you need to add a one more component for List itself with onToggleListItem method, which will handle the state change. The state of all list items should be store there. In ListItem component you call the onToggleListItem method with a contact id so you can identify which list item was changed.
handleButtonClick() {
this.props.onToggleListItem(this.props.contact.id);
}
Make use of a state and change the state on click of li
var Hello = React.createClass({
getInitialState() {
return {
colorClass: ''
}
},
toggleClass() {
if(this.state.colorClass == '') {
this.setState({colorClass: 'someColor'});
} else {
this.setState({colorClass: ''});
}
},
render(){
return (
<div>
<li onClick={this.toggleClass}>
Some text
<i className={"icon-check " + this.state.colorClass}>value</i>
</li>
</div>
);
}
})
ReactDOM.render(<Hello />, document.getElementById('app'));
.someColor {
color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app"></div>

Categories