Profile Toolbar, Vuex
Uses Vuex to maintain global state of objects
by Rob Cameron
HTML
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script type="text/x-template" id="profile-toolbar">
<div class="profile-toolbar">
<ul>
<li>Following: {{ isFollowing }}</li>
<li>Favorite: {{ isFavorited }}</li>
<li>Lists: {{ isListed }}</li>
<li>VouchedFor: {{ isVouchedFor }}</li>
<li>HasNote: {{ hasNote }}</li>
</ul>
<action-button :username="profile.username" attribute="vouches" label-on="Remove Vouch" label-off="Add Vouch" :isOn="isVouchedFor"></action-button>
<action-button :username="profile.username" attribute="following" label-on="Unfollow" label-off="Follow" :isOn="isFollowing"></action-button>
</div>
</script>
<script type="text/x-template" id="action-button">
<button @click="toggle">
<span v-if="isOn">{{ labelOn }}</span>
<span v-else>{{ labelOff }}</span>
</button>
</script>
<div id="profiles">
<div class="profile" data-id="1" data-username="rob" data-following="1,2,3" data-favorites="1,3,5" data-lists="4,5,6" data-vouches="7,8,9" data-notes="1,5,9">
<h1>Rob</h1>
<profile-toolbar :profile="profiles['rob']" :key="profiles['rob'].id"></profile-toolbar>
</div>
<div class="profile" data-id="2" data-username="joel" data-following="2,3" data-favorites="3,5" data-lists="4,5,6" data-vouches="1,8,9" data-notes="5,9">
<h1>Joel</h1>
<profile-toolbar :profile="profiles['joel']" :key="profiles['joel'].id"></profile-toolbar>
</div>
</div>
CSS
body {
font-family: 'Helvetica Neue', sans-serif;
}
h1 {
margin: 0;
padding: 0;
}
ul {
margin: 1em 0;
padding: 0;
list-style: none;
}
.profile {
display: inline-block;
border: 1px solid #cccccc;
padding: 1em;
margin: 1em;
}
JavaScript
// id of the user viewing this page
var userId = 1;
// Helper method that turns the data attributes of the profile
// into an array of integers (by default they'll be an array
// of strings)
var attributeToData = function($profile, name) {
return $profile.data(name).toString().split(',').map(function(id) {
return parseInt(id);
});
};
// build data structure for Vue
var profilesData = {};
$.map($('.profile'), function(profile) {
var $profile = $(profile);
profilesData[$profile.data('username')] = {
id: $profile.data('id'),
username: $profile.data('username'),
following: attributeToData($profile, 'following'),
favorites: attributeToData($profile, 'favorites'),
lists: attributeToData($profile, 'lists'),
vouches: attributeToData($profile, 'vouches'),
notes: attributeToData($profile, 'notes')
};
});
var store = new Vuex.Store({
strict: true,
state: {
profiles: profilesData
},
mutations: {
update: function(state, payload) {
state.profiles[payload.username][payload.attribute] = payload.data;
}
},
actions: {
update: function(context, payload) {
context.commit('update', payload);
}
}
});
Vue.component('profile-toolbar', {
template: '#profile-toolbar',
props: {
profile: {
type: Object,
required: true
}
},
store: this.$store,
computed: {
isFollowing: function() {
return this.profile.following.indexOf(userId) != -1;
},
isFavorited: function() {
return this.profile.favorites.indexOf(userId) != -1;
},
isListed: function() {
return this.profile.lists.indexOf(userId) != -1;
},
isVouchedFor: function() {
return this.profile.vouches.indexOf(userId) != -1;
},
hasNote: function() {
return this.profile.notes.indexOf(userId) != -1;
}
},
components: {
'action-button': {
template: '#action-button',
props: {
username: {
type: String,
required: true
...