building forum with vuejs and firebase

Building a Simple Forum With Vue-js, Vuex and Firebase Part2: Forum and Topic CRUD

We will continue our tutorial of building a simple forum using Vuejs and Firebase. In this part we will implement how to add and edit forums and topics. Also display the user forums and ability to add replies.

 

 

Series Topics:

 

Creating and Editing Forums

We will add functions to add, edit and delete a forum from firebase so open helper/api.js and modify it like this:

import firebase from "firebase";

// add your own config params, get them from 
// https://console.firebase.google.com/project/<project-name>/settings/general/
var config = {
  apiKey: "<your api key>",
  authDomain: "<your auth domain>",
  databaseURL: "<your database url>",
  storageBucket: "<your storage bucket>",
};

firebase.initializeApp(config);

var db = firebase.database();

export default {

	authenticate(email, password, successcallback, errorcallback) {
		firebase.auth().signInWithEmailAndPassword(email, password).then(successcallback).catch(errorcallback);
	},
	logout(successcallback, errorcallback) {
		firebase.auth().signOut().then(successcallback).catch(errorcallback);
	},
	getCurrentUser(callback) {
		firebase.auth().onAuthStateChanged(callback);

	},
	register(email, password, successcallback, errorcallback) {
		firebase.auth().createUserWithEmailAndPassword(email, password).then(successcallback).catch(errorcallback);
	},
	updateUserDisplayname(name) {
		var user = firebase.auth().currentUser;

		user.updateProfile({
  			displayName: name,
		}).then(function() {
  			// Update successful.
		}).catch(function(error) {
  			// An error happened.
		});
	},
	addUser(name, email, uid) {
		var usersRef = db.ref('users');
		var usersPush = usersRef.push();

		const key = usersPush.getKey();

		usersPush.set({
			name: name,
			email: email,
			uid: uid, 
			created_at: (new Date()).toLocaleString()
		});

		return key;
	},
        getUserByUID(UID, callback) {
		var userRef = db.ref('users').orderByChild("uid").equalTo(UID);

		userRef.on('value', function(snapshot) {
			if(snapshot.val() != null) {
				callback(Object.keys(snapshot.val())[0], snapshot.val());
			} else {
				callback(null, null);
			}
		});
	},
        addForum(title, content, user_id) {
		var forumRef = db.ref('forums');
		var forumPush = forumRef.push();

		forumPush.set({
			title: title,
			content: content, 
			user_id: user_id,
			created_at: (new Date()).toLocaleString()
		});
	},
	updateForum(title, content, key) {

		db.ref("forums/" + key).update({ title: title, content: content });
	},
	deleteForum(key) {
		db.ref("forums/" + key).remove();
	},
	userForums(user_id, callback) {
		var forumRef = db.ref('forums').orderByChild("user_id").equalTo(user_id);

		forumRef.on('value', function(snapshot) {
			callback(snapshot.val());
		});
	}

}

In the above code we added four new functions using the firebase api which are:

  • addForum
  • updateForum
  • deleteForum
  • userForums: This will return the user forums when he is login.

Now let’s modify our store so open store.js and modify it like shown below:

import Vue from 'vue'
import Vuex from 'vuex'
import api from './helper/api'

Vue.use(Vuex);

export default new Vuex.Store(
	{
		state: {
			auth: {
				email: "",
				password: "",
				name: ""
			},
			currentUser: {
				id: "",       // this id is the datebase key for this record
				name: "",
				email: "",
				uid: "",      // this is is the user authenticated object
				status: 0   // 0=logout 1=login
			},
			forum: {         // this object will be used when adding and editing forum
				title: "",
				content: ""
			},
			userForums: []     // user forums in case he is login
		},
		mutations: {
			setAuthEmail(state, data) {
				state.auth.email = data
			},
			setAuthPassword(state, data) {
				state.auth.password = data
			},
			setAuthName(state, data) {
				state.auth.name = data
			},
			setCurrUserId(state, data) {
				state.currentUser.id = data
			},
			setCurrUserName(state, data) {
				state.currentUser.name = data
			},
			setCurrUserEmail(state, data) {
				state.currentUser.email = data
			},
			setCurrUserUid(state, data) {
				state.currentUser.uid = data
			},
			setCurrUserStatus(state, data) {
				state.currentUser.status = data
			},
			setForumTitle(state, data) {
				state.forum.title = data
			},
			setForumContent(state, data) {
				state.forum.content = data
			},
			setUserForums(state, data) {
				state.userForums = data
			}
		},
		actions: {
			getCurrentUser({commit}) {
				api.getCurrentUser(function(user) {
					if(user) {

						api.getUserByUID(user.uid, function(key, val) {
							if(key != null && val != null) {
								commit('setCurrUserId', key);
								commit('setCurrUserName', user.displayName);
								commit('setCurrUserEmail', user.email);
								commit('setCurrUserUid', user.uid);
								commit('setCurrUserStatus', 1);
							}
						})
					} 
				}); 
			},
			clearUserData({commit}) {
				commit('setCurrUserId', '');
				commit('setCurrUserName', '');
				commit('setCurrUserEmail', '');
				commit('setCurrUserUid', '');
				commit('setCurrUserStatus', 0);

				commit('setAuthEmail', '');
				commit('setAuthPassword', '');
				commit('setAuthName', '');
			},
			getUserForums({commit}, user) {
				api.userForums(user.id, function(response) {
					if(response) {
						commit('setUserForums', response); 
					} else {
						commit('setUserForums', []);
					}
				});
			}
		}
	}
)

In the above code we added some state variables that will be used when adding and updating the forums such as the forum title and forum content and also we added some mutations and actions.

 

Add Forum Component

Open components/pages/AddForum.vue and insert the below code:

<template>
	
	<div>
		<section class="row panel-body">
			<div class="col-md-12">
				<form method="post" v-on:submit.prevent="addForum">

					<div class="alert alert-danger" v-if="this.errors.length > 0">
						<ul>
							<li v-for="(error, index) in this.errors" :key="index">{{ error }}</li>
						</ul>
					</div>

					<div class="alert alert-success" v-if="this.msg != ''">
						{{ this.msg}}
					</div>

					<div class="form-group">
		    			<label for="title">Title</label>
		    			<input type="text" class="form-control" id="title" placeholder="Title" v-model="title">
		  			</div>
		  			<div class="form-group">
		  				<label for="content">Content</label>
		  				<textarea name="content" class="form-control" placeholder="Content" v-model="content"></textarea>
		  			</div>

		  			<button type="submit" class="btn btn-success"><i v-show="isLoading" class="fa fa-refresh fa-lg fa-spin btn-load-indicator"></i> Save</button>
				</form>
			</div>
		</section>
	</div>

</template>

<script>
	import api from '../../helper/api'

	export default {
		data() {
			return {
				errors: [],
				msg: "",
				isLoading: false,
			}
		},
		computed: {
			title: {
				get() {
					return this.$store.state.forum.title
				}, 
				set(value) {
					this.$store.commit('setForumTitle', value)
				}
			},
			content: {
				get() {
					return this.$store.state.forum.content
				}, 
				set(value) {
					this.$store.commit('setForumContent', value)
				}
			}
		},
		methods: {
			addForum() {
				this.errors = [];
				
				var self = this;

				if(this.$store.state.forum.title == "") {
					this.errors.push('Title required')
				}

				if(this.$store.state.forum.content == "") {
					this.errors.push('Content required')
				}

				if(this.errors.length > 0) {
					return false;
				}

				this.isLoading = true;

				// else save forum
				api.addForum(this.$store.state.forum.title, this.$store.state.forum.content, this.$store.state.currentUser.id)

				setTimeout(
						() => { 

							self.isLoading = false;

							self.msg = "Forum saved successfully!"

							self.$store.commit('setForumTitle', "")
							self.$store.commit('setForumContent', "")

							self.$store.dispatch('getUserForums', self.$store.state.currentUser);

							self.$router.push('/my-forums/');
					},
						2500
					)
			}
		},
		created() {
			if(this.$store.state.currentUser.status != 1) {
				this.$router.push('/login/');
			}
		}
	}
</script>

Here we created a simple form and then bind it to computed properties that read and write to the store then we added a function that submit the form, and then save the forum to firebase after that we fetch the user forums and add it to the store to be display later in a dedicated page.

 

Modify components/pages/Login.vue inside the login method locate this line:

self.$store.commit('setCurrUserStatus', 1);

and add this code below it:

// load user forums after successful login
api.userForums(user.user.uid, function(response) {
   self.$store.commit('setUserForums', response);
});

and this code fetches the user forums after successful login.

 

Modify app.js and add this code inside the mounted() lifecycle hook:

         // check for current user if he is still login
         store.dispatch('getCurrentUser')

         // if user is already login then load user forums
	    setTimeout(
	    		() => {
	    			if(store.state.currentUser.status == 1) {
	    				store.dispatch('getUserForums', store.state.currentUser);
	    			}
	    		}, 
	    		2000
	    	)

Now in the terminal run

npm run dev

Then navigate to http://localhost/project_path/ and login then click on add forum button on the header, on successful add you will be redirected to my forums page, which we will update it in the next section.

 

Display User Forums

Let’s display the user forums, we loop the forums from the store variable that we added in previous section.

So open component/pages/MyForums.vue and update it as shown:

<template>
	<div>
		<section class="row panel-body">
			<section class="col-md-12">
	          <h3> <i class="glyphicon glyphicon-th-list"> </i> My Forums</h3> 
	          <hr>
	          
	        </section>
		</section>
		<hr/>

		<div class="alert alert-success" v-if="this.msg != ''">
			{{ this.msg}}
		</div>

		<div class="container-fluid">
			<table class="table table-responsive" v-if="this.$store.state.userForums">
				<thead>
					<tr>
						<th>Title</th>
						<th>Content</th>
						<th>Forum Topic</th>
						<th>Add Topic</th>
						<th>Edit</th>
						<th>Delete</th>
					</tr>
				</thead>
				<tbody>
					<tr v-for="(value, key, index) in this.$store.state.userForums" :key="index">
						<td>{{ value.title }}</td>
						<td>{{ value.content }}</td>
						<td><router-link :to="'/forum-topics/' + key" class="btn btn-info">View</router-link></td>
						<td><router-link :to="'/add-topic/' + key" class="btn btn-info">Add Topic</router-link></td>
						<td><router-link :to="'/edit-forum/' + key" class="btn btn-success">Edit</router-link></td>
						<td><a href="javascript:void(0);" class="btn btn-danger" @click="remove(key)">Delete</a></td>
					</tr>
				</tbody>
			</table>

			<div class="text-center" v-if="!this.$store.state.userForums">
				You have no forums yet! <router-link to="/add-forum/">Add forum</router-link>
			</div>

		</div>

	</div>
</template>

<script>
	
	import api from '../../helper/api'

	export default {
		data() {
			return {
				msg: ""
			}
		},
		methods: {
			remove(key) {
				if(confirm('Are you sure?')) {

					// delete
					api.deleteForum(key);

					// reload user forums
					setTimeout(
							() => {
								this.msg = "Forum deleted successfully!";

								this.$store.dispatch('getUserForums', this.$store.state.currentUser)
							},
							1500
						)
				}
			}
		},
		mounted() {
			document.getElementById("loading").style.display = "none"
		}
	}
</script>

In the above code we looped over the forums and then displayed them in a grid view and added some buttons like viewing forum topics, add topic, edit forum, and delete forum.

Now reload the page and click on My Forums button in the header, wait for some seconds until the forums appear and try to click on delete, the other buttons will be implemented in the next sections.

 



Updating User Forums

Open helper/api.js and add this function after userForums function:

userForums(user_id, callback) {
......
},
getForumByKey(key, callback) {

     var itemRef = db.ref('forums').child(key);

     var topicsRef = db.ref('topics').orderByChild("forum_id").equalTo(key);

     itemRef.once('value', function(snapshot) {
			callback(snapshot.val(), 'forum')
	});

	topicsRef.on('value', function(snapshot) {
			callback(snapshot.val(), 'topics')
	});
}

This function will be used to retrieve specific forum by it’s unique key which will be used in the edit form below.

 

Edit Forum Component

Open components/pages/EditForum.vue and add the below code:

<template>
	
	<div>
		<section class="row panel-body">
			<div class="col-md-12">
				<form method="post" v-on:submit.prevent="editForum">

					<div class="alert alert-danger" v-if="this.errors.length > 0">
						<ul>
							<li v-for="(error, index) in this.errors" :key="index">{{ error }}</li>
						</ul>
					</div>

					<div class="alert alert-success" v-if="this.msg != ''">
						{{ this.msg}}
					</div>

					<div class="form-group">
		    			<label for="title">Title</label>
		    			<input type="text" class="form-control" id="title" placeholder="Title" v-model="title">
		  			</div>
		  			<div class="form-group">
		  				<label for="content">Content</label>
		  				<textarea name="content" class="form-control" placeholder="Content" v-model="content"></textarea>
		  			</div>

		  			<button type="submit" class="btn btn-success"><i v-show="isLoading" class="fa fa-refresh fa-lg fa-spin btn-load-indicator"></i> Update</button>
				</form>
			</div>
		</section>
	</div>

</template>

<script>
	import api from '../../helper/api'

	export default {
		data() {
			return {
				errors: [],
				msg: "",
				isLoading: false,
			}
		},
		computed: {
			title: {
				get() {
					return this.$store.state.forum.title
				}, 
				set(value) {
					this.$store.commit('setForumTitle', value)
				}
			},
			content: {
				get() {
					return this.$store.state.forum.content
				}, 
				set(value) {
					this.$store.commit('setForumContent', value)
				}
			}
		},
		created() {
			var self = this

			api.getForumByKey(this.$route.params.id, function(response, item) {
				if(item == 'forum') {
					self.$store.commit('setForumTitle', response.title)
					self.$store.commit('setForumContent', response.content)
				}
			});
		},
		methods: {
			editForum() {
				this.errors = [];

				var self = this;

				if(this.$store.state.forum.title == "") {
					this.errors.push('Title required')
				}

				if(this.$store.state.forum.content == "") {
					this.errors.push('Content required')
				}

				if(this.errors.length > 0) {
					return false;
				}

				this.isLoading = true;

				// else save forum
				api.updateForum(this.$store.state.forum.title, this.$store.state.forum.content, this.$route.params.id)

				setTimeout(
						() => { 

							self.isLoading = false;

							self.msg = "Forum updated successfully!"

							self.$store.dispatch('getUserForums', self.$store.state.currentUser);

							self.$router.push('/my-forums/');
					},
						2500
					)
			}
		}
	}
</script>

Now if you click on the edit button you will see the edit form populated with the forum data, click Update then the forum will be updated and you will be redirected to User Forums page.

 

Handling Forum Topics

Open helper/api.js and modify it as shown:

import firebase from "firebase";

// add your own config params, get them from 
// https://console.firebase.google.com/project/<project-name>/settings/general/
var config = {
  apiKey: "<your api key>",
  authDomain: "<your auth domain>",
  databaseURL: "<your database url>",
  storageBucket: "<your storage bucket>",
};

firebase.initializeApp(config);

var db = firebase.database();

export default {

	authenticate(email, password, successcallback, errorcallback) {
		firebase.auth().signInWithEmailAndPassword(email, password).then(successcallback).catch(errorcallback);
	},
	logout(successcallback, errorcallback) {
		firebase.auth().signOut().then(successcallback).catch(errorcallback);
	},
	getCurrentUser(callback) {
		firebase.auth().onAuthStateChanged(callback);

	},
	register(email, password, successcallback, errorcallback) {
		firebase.auth().createUserWithEmailAndPassword(email, password).then(successcallback).catch(errorcallback);
	},
	updateUserDisplayname(name) {
		var user = firebase.auth().currentUser;

		user.updateProfile({
  			displayName: name,
		}).then(function() {
  			// Update successful.
		}).catch(function(error) {
  			// An error happened.
		});
	},
	addUser(name, email, uid) {
		var usersRef = db.ref('users');
		var usersPush = usersRef.push();

		const key = usersPush.getKey();

		usersPush.set({
			name: name,
			email: email,
			uid: uid, 
			created_at: (new Date()).toLocaleString()
		});

		return key;
	},
        getUserByUID(UID, callback) {
		var userRef = db.ref('users').orderByChild("uid").equalTo(UID);

		userRef.on('value', function(snapshot) {
			if(snapshot.val() != null) {
				callback(Object.keys(snapshot.val())[0], snapshot.val());
			} else {
				callback(null, null);
			}
		});
	},
        addForum(title, content, user_id) {
		var forumRef = db.ref('forums');
		var forumPush = forumRef.push();

		forumPush.set({
			title: title,
			content: content, 
			user_id: user_id,
			created_at: (new Date()).toLocaleString()
		});
	},
	updateForum(title, content, key) {

		db.ref("forums/" + key).update({ title: title, content: content });
	},
	deleteForum(key) {
		db.ref("forums/" + key).remove();
	},
	userForums(user_id, callback) {
		var forumRef = db.ref('forums').orderByChild("user_id").equalTo(user_id);

		forumRef.on('value', function(snapshot) {
			callback(snapshot.val());
		});
	},
        getForumByKey(key, callback) {

     var itemRef = db.ref('forums').child(key);

     var topicsRef = db.ref('topics').orderByChild("forum_id").equalTo(key);

     itemRef.once('value', function(snapshot) {
			callback(snapshot.val(), 'forum')
	});

	topicsRef.on('value', function(snapshot) {
			callback(snapshot.val(), 'topics')
	});
     },
     getMyTopics(forum_key, user_key, callback) {
		var topicsRef = db.ref('topics').orderByChild("userId_forumId").equalTo(user_key + "_" + forum_key);

		topicsRef.on('value', function(snapshot) {
			callback(snapshot.val());
		});
	},
	addTopic(title, content, forum_id, user_id) {
		var forumRef = db.ref('topics');
		var forumPush = forumRef.push();

		forumPush.set({
			title: title,
			content: content, 
			user_id: user_id,
			created_at: (new Date()).toLocaleString(),
			forum_id: forum_id,
			view_count: 0,
			userId_forumId: user_id + "_" + forum_id
		});
	},
	updateTopic(title, content, key) {

		db.ref("topics/" + key).update({ title: title, content: content });
	},
	deleteTopic(key) {
		db.ref("topics/" + key).remove();
	},
        updateTopicViewCount(key)
	{
		var topicRef = db.ref('topics').child(key).child('view_count');

		topicRef.transaction(function(views) {
  			// if (views) {
    			views = views + 1;
  			// }
  			return views;
		});
	},
        getTopicByKey(key, callback) {

		var topicRef = db.ref('topics').child(key);

		topicRef.on('value', function(snapshot) {

			var topicVal = snapshot.val()

			var userRef = db.ref('users').child(topicVal.user_id)

			userRef.on('value', function(snapshotUser) {

				var forumRef = db.ref('forums').child(topicVal.forum_id)

				forumRef.on('value', function(snapshotForum) {

					callback(topicVal, snapshotUser.val(), snapshotForum.val())
				});
			});
		});
	}

}

Also Open store.js and modify it as shown:

import Vue from 'vue'
import Vuex from 'vuex'
import api from './helper/api'

Vue.use(Vuex);

export default new Vuex.Store(
	{
		state: {
			auth: {
				email: "",
				password: "",
				name: ""
			},
			currentUser: {
				id: "",       // this id is the datebase key for this record
				name: "",
				email: "",
				uid: "",      // this is is the user authenticated object
				status: 0   // 0=logout 1=login
			},
			forum: {         // this object will be used when adding and editing forum
				title: "",
				content: ""
			},
			userForums: [],     // user forums in case he is login
			userTopics: [],
			topic: {
				title: "",
				content: ""
			}
		},
		mutations: {
			setAuthEmail(state, data) {
				state.auth.email = data
			},
			setAuthPassword(state, data) {
				state.auth.password = data
			},
			setAuthName(state, data) {
				state.auth.name = data
			},
			setCurrUserId(state, data) {
				state.currentUser.id = data
			},
			setCurrUserName(state, data) {
				state.currentUser.name = data
			},
			setCurrUserEmail(state, data) {
				state.currentUser.email = data
			},
			setCurrUserUid(state, data) {
				state.currentUser.uid = data
			},
			setCurrUserStatus(state, data) {
				state.currentUser.status = data
			},
			setForumTitle(state, data) {
				state.forum.title = data
			},
			setForumContent(state, data) {
				state.forum.content = data
			},
			setUserForums(state, data) {
				state.userForums = data
			},
			setUserTopics(state, data) {
				state.userTopics = data
			},
			setTopicTitle(state, data) {
				state.topic.title = data
			},
			setTopicContent(state, data) {
				state.topic.content = data
			}
		},
		actions: {
			getCurrentUser({commit}) {
				api.getCurrentUser(function(user) {
					if(user) {

						api.getUserByUID(user.uid, function(key, val) {
							if(key != null && val != null) {
								commit('setCurrUserId', key);
								commit('setCurrUserName', user.displayName);
								commit('setCurrUserEmail', user.email);
								commit('setCurrUserUid', user.uid);
								commit('setCurrUserStatus', 1);
							}
						})
					} 
				}); 
			},
			clearUserData({commit}) {
				commit('setCurrUserId', '');
				commit('setCurrUserName', '');
				commit('setCurrUserEmail', '');
				commit('setCurrUserUid', '');
				commit('setCurrUserStatus', 0);

				commit('setAuthEmail', '');
				commit('setAuthPassword', '');
				commit('setAuthName', '');
			},
			getUserForums({commit}, user) {
				api.userForums(user.id, function(response) {
					if(response) {
						commit('setUserForums', response); 
					} else {
						commit('setUserForums', []);
					}
				});
			}
		}
	}
)

Add Topic Component

Open components/pages/AddTopic.vue and insert the below code:

<template>
	
	<div>
		<section class="row panel-body">
			<div class="col-md-12">
				<form method="post" v-on:submit.prevent="addTopic">

					<div class="alert alert-danger" v-if="this.errors.length > 0">
						<ul>
							<li v-for="(error, index) in this.errors" :key="index">{{ error }}</li>
						</ul>
					</div>

					<div class="alert alert-success" v-if="this.msg != ''">
						{{ this.msg}}
					</div>

					<div class="form-group">
		    			<label for="title">Title</label>
		    			<input type="text" class="form-control" id="title" placeholder="Title" v-model="title">
		  			</div>
		  			<div class="form-group">
		  				<label for="content">Content</label>
		  				<textarea name="content" class="form-control" placeholder="Content" v-model="content"></textarea>
		  			</div>

		  			<button type="submit" class="btn btn-success"><i v-show="isLoading" class="fa fa-refresh fa-lg fa-spin btn-load-indicator"></i> Save</button>
				</form>
			</div>
		</section>
	</div>

</template>

<script>
	import api from '../../helper/api'

	export default {
		data() {
			return {
				errors: [],
				msg: "",
				isLoading: false
			}
		},
		computed: {
			title: {
				get() {
					return this.$store.state.topic.title
				}, 
				set(value) {
					this.$store.commit('setTopicTitle', value)
				}
			},
			content: {
				get() {
					return this.$store.state.topic.content
				}, 
				set(value) {
					this.$store.commit('setTopicContent', value)
				}
			}
		},
		methods: {
			addTopic() {
				this.errors = [];
				
				var self = this;

				if(this.$store.state.topic.title == "") {
					this.errors.push('Title required')
				}

				if(this.$store.state.topic.content == "") {
					this.errors.push('Content required')
				}

				if(this.errors.length > 0) {
					return false;
				}


				this.isLoading = true;

				// else save topic
				api.addTopic(this.$store.state.topic.title, this.$store.state.topic.content, this.$route.params.id, this.$store.state.currentUser.id)

				setTimeout(
						() => { 

							self.isLoading = false;

							self.msg = "Topic saved successfully!"

							self.$store.commit('setTopicTitle', "")
							self.$store.commit('setTopicContent', "")

							self.$router.push('/forum-topics/' + self.$route.params.id);
					},
						2500
					)
			}
		},
                created() {
			document.getElementById("loading").style.display = "none"
		}
	}
</script>

This form the same as the Add Forum form, but in this case we add a topic inside specific forum.

 



Display Topics Component

Open components/pages/ForumTopics.vue and insert the below code:

<template>
	<div>
		<section class="row panel-body">
			<section class="col-md-12">
	          <h3> <i class="glyphicon glyphicon-th-list"> </i> Forum Topics</h3> 
	          <hr>
	          
	        </section>
		</section>
		<hr/>

		<div class="alert alert-success" v-if="this.msg != ''">
			{{ this.msg}}
		</div>

		<div class="container-fluid">
			<table class="table table-responsive">
				<thead>
					<tr>
						<th>Title</th>
						<th>Content</th>
						<th>Edit</th>
						<th>Delete</th>
					</tr>
				</thead>
				<tbody>
					<tr v-for="(value, key, index) in this.topics" :key="index">
						<td>{{ value.title }}</td>
						<td>{{ value.content }}</td>
						<td><router-link :to="'/edit-topic/' + forum_id + '/' + key" class="btn btn-success">Edit</router-link></td>
						<td><a href="javascript:void(0);" class="btn btn-danger" @click="remove(key)">Delete</a></td>
					</tr>
				</tbody>
			</table>

			<div class="text-center" v-if="!this.topics">
				No topics in this forum! <router-link :to="'/add-topic/' + this.$route.params.id">Add new topic</router-link>
			</div>

		</div>

	</div>
</template>

<script>
	
	import api from '../../helper/api'

	export default {
		data() {
			return {
				msg: ""
			}
		},
		computed: {
			topics: {
				get() {
					return this.$store.state.userTopics
				}
			},
			forum_id: {
				get() {
					return this.$route.params.id
				}
			}
		},
		methods: {
			remove(key) {
				if(confirm('Are you sure?')) {

					// delete
					api.deleteTopic(key);

					// reload user forums
					setTimeout(
							() => {
								this.msg = "Topic deleted successfully!";

								api.getMyTopics(this.$route.params.id, this.$store.state.currentUser.id, function(response) {
									self.$store.commit('setUserTopics', response);
								});
							},
							1500
						)
				}
			}
		},
		mounted() {
			var self = this

			setTimeout(
					() => {
						api.getMyTopics(self.$route.params.id, self.$store.state.currentUser.id, function(response) {
									self.$store.commit('setUserTopics', response);
								});
					},
					2000
				);
		},
		created() {
			document.getElementById("loading").style.display = "none"
		}
	}
</script>

 

Update Topic Component

Open components/pages/EditTopic.vue and modify it as shown:

<template>
	
	<div>
		<section class="row panel-body">
			<div class="col-md-12">
				<form method="post" v-on:submit.prevent="editTopic">

					<div class="alert alert-danger" v-if="this.errors.length > 0">
						<ul>
							<li v-for="(error, index) in this.errors" :key="index">{{ error }}</li>
						</ul>
					</div>

					<div class="alert alert-success" v-if="this.msg != ''">
						{{ this.msg}}
					</div>

					<div class="form-group">
		    			<label for="title">Title</label>
		    			<input type="text" class="form-control" id="title" placeholder="Title" v-model="title">
		  			</div>
		  			<div class="form-group">
		  				<label for="content">Content</label>
		  				<textarea name="content" class="form-control" placeholder="Content" v-model="content"></textarea>
		  			</div>

		  			<button type="submit" class="btn btn-success"><i v-show="isLoading" class="fa fa-refresh fa-lg fa-spin btn-load-indicator"></i> Save</button>
				</form>
			</div>
		</section>
	</div>

</template>

<script>
	import api from '../../helper/api'

	export default {
		data() {
			return {
				errors: [],
				msg: "",
				isLoading: false
			}
		},
		computed: {
			title: {
				get() {
					return this.$store.state.topic.title
				}, 
				set(value) {
					this.$store.commit('setTopicTitle', value)
				}
			},
			content: {
				get() {
					return this.$store.state.topic.content
				}, 
				set(value) {
					this.$store.commit('setTopicContent', value)
				}
			}
		},
		created() {
			var self = this

			api.getTopicByKey(this.$route.params.topic_id, function(topic, user, forum) {
				self.$store.commit('setTopicTitle', topic.title)
				self.$store.commit('setTopicContent', topic.content)
			});
		},
		methods: {
			editTopic() {
				this.errors = [];
				
				var self = this;

				if(this.$store.state.topic.title == "") {
					this.errors.push('Title required')
				}

				if(this.$store.state.topic.content == "") {
					this.errors.push('Content required')
				}

				if(this.errors.length > 0) {
					return false;
				}

				this.isLoading = true;

				// else save topic
				api.updateTopic(self.$store.state.topic.title, self.$store.state.topic.content, self.$route.params.topic_id)


				self.msg = "Topic updated successfully!"

				setTimeout(
						() => { 

							self.isLoading = false;

							self.$store.commit('setTopicTitle', "")
							self.$store.commit('setTopicContent', "")

							self.$router.push('/forum-topics/' + self.$route.params.forum_id);
					},
						2500
					)
			}
		},
		created() {
			document.getElementById("loading").style.display = "none"
		}
	}
</script>

At this point we finished adding, editing, displaying and deleting topics. Try to experiment with them and we will implement the home forums and forum display in the next part.

 

Continue to the next part>>

 

0 0 vote
Article Rating
Share this: