Posts search and gallery view app in Vuejs

Hello everyone, welcome back to justlaravel.com. Here I am going to explore some more about vuejs, in previous post, I gave some intro to vue, where we already had database connection and operations on those data and all that cool stuff. Here I will develop another simple app to see more about Vuejs.
Working Demo Project on Github
This is a simple application something like post’s gallery where different post along with its image and its link is shown and when clicked it goes to the post.

So it has a simple form, where it has 3 fields, title, its link and its image when added these will store in database and the results are shown in the view.

Search and Add forms:
I used a simple input field for typing some text, with a label which says Search Title:
<label>Search Title:</label> <input v-model="keyword" type="text" placeholder="Search anything" />
In the above snippet, the most important part is the vue directive, v-model="keyword"
, I later use this directive later to search through all the posts with the keyword provided in the input field.
Working Demo Project on Github
Next to that I placed a button, which when clicked opens up a modal as shown in image above.
<button onclick="document.getElementById('inputModal').style.display='block'" class="w3-button w3-green w3-large">ADD</button>
W3CSS Modal in vue.js
Here I used a modal with a form, which has 3 fields as shown in the image before.
<div id="inputModal" class="w3-modal" v-if="showModal"> <div class="w3-modal-content w3-card-8 w3-animate-zoom" style="max-width:600px"> <div class="w3-center"><br> <span onclick="document.getElementById('inputModal').style.display='none'" class="w3-closebtn w3-hover-red w3-container w3-padding-8 w3-display-topright" title="Close Modal">×</span> </div> <div class="w3-container"> <div class="w3-section"> <label><b>Title</b></label> <input class="w3-input w3-border w3-margin-bottom" type="text" placeholder="Post Title" v-model="newItem.title" required> <label><b>Link</b></label> <input class="w3-input w3-border w3-margin-bottom" type="text" placeholder="Post Link" v-model="newItem.link" required> <label><b>Image</b></label> <input class="w3-input w3-border w3-margin-bottom" type="text" placeholder="Post Image" v-model="newItem.image" required> <button class="w3-button w3-block w3-green w3-section w3-padding" @click.prevent="addItem()">Submit</button> </div> </div> </div> </div>
The above code for modal is similar as any modal you write, but here the 2 noticeable things are vue’s if directive v-if="showModal"
and vue’s click method @click.prevent="addItem()
.
I want to show this modal only when showModal
is set to true, I will change this value later in the js part, and when button is clicked I will call a vue method addItem()
.
Gallery View:
For showing all the posts I use a card view w3-card
, and used a vue directive, v-for
to loop all the posts.
<div class="w3-row center"> <div class="w3-card-8 w3-col m3 w3-margin w3-animate-zoom card" v-for="post in filteredList"> <a v-bind:href="post.link" target="_blank"> <img v-bind:src="post.image"/> @{{post.title}}</a> </div> </div>
The VUE part
All the Vue(js) part is written in app.js
file in /resources/assets/js
directory.
First I will create a new vue instance, and all the vue part in handled in an element with id app i.e all the HTML content is wrapped in a div with id app.
<body> .... <div id="app"> ... ... ... </div> .... </body>
Create a new vue instance
const app = new Vue({ el: "#app", data: { .... }, methods: { .... }, .... });
First I will initialize some properties in data
object.
data: { showModal: true, keyword: '', newItem: { 'title': '', 'link': '', 'image': '' }, postList: [] },
showModal
flag for showing and hiding the modal, modal is shown only when this variable is true
.
keyword
stores the text we enter in the search box, initially it is empty, later I use this variable to perform search operation.
newItem
stores the items a new item(here a post) like its title, post link, and its image.
postList
is an array which contains all the posts, initially it is empty.
Working Demo Project on Github
Next, I will use 2 methods to get all the items from database(getItems) and another method to add an item to database(addItem).
getItems Vue method:
In order to make HTTP calls, we use axios
(a promise-based HTTP client) from Vue 2 onwards. So I use the same here.
getItems: function(){ axios.get('/vueitems').then(response => { this.postList = response.data; }); }
Here I call route /vueitems
with get
http verb, the laravel function for it is as follows.
Route::get('/vueitems',function(){ $posts = Data::all(); return $posts; });
the above lines of code simply fetches all the data from the database and returns it. This data is handled in Vue by adding this data to postList
array which I defined earlier.
this.postList = response.data;
the above line adds the response to the postList
array.
addItems Vue method
Next is addItems Vue method.
addItem() { var input = this.newItem; axios.post('/vueitems', input) .then(response => { this.newItem = { 'title': '', 'link': '', 'image': '' }; this.postList.push(input), this.showModal= false }); }
Here is a post request to /vueitems is called, with an extra parameter input
, which contains the form data.
As I discussed earlier, for each of the field in the form there is an associated Vue model with it. v-model="newItem.title"
,v-model="newItem.link"
,v-model="newItem.image"
, these gets the form data and it can be passed to laravel controller which stores them in the database.
Route::post('/vueitems', function(Request $req){ $posts = new Data(); $posts->title = $req->title; $posts->link = $req->link; $posts->image = $req->image; $posts->save(); });
Next, I also used mounted
method, which will call when the js first loads. As I want to show all the posts, I will call getItems
method in the mounted, so all the post show when the page loads.
mounted : function(){ this.getItems(); },
Search functionality
As our app has a search feature, where a search box in shown earlier.
<input v-model="keyword" type="text" placeholder="Search anything" />
here Vue directive v-model
does the binding and trick for us. I used Vue’s computed property to return the data of the post when its title is entered in the search box.
computed: { filteredList() { return this.postList.filter(post=>{ return post.title.toLowerCase().includes(this.keyword.toLowerCase()); }); } }
and in the view, I loop all the items in the filtered list to display all the posts.
<div class="w3-card-8 w3-col m3 w3-margin w3-animate-zoom card" v-for="post in filteredList"> <a v-bind:href="post.link" target="_blank"> <img v-bind:src="post.image"/> @{{post.title}}</a> </div>
Awesome tutorial (y)
Glad you liked it 🙂
When you try to add second post it’s not working