Is An Id In Vue Local To The Template
A basic understanding of Vue.js and Node.js are needed to follow this tutorial.
In this tutorial, I volition walk you through getting started with a Vue.js 2.0 app, and adding realtime functionality to it with Pusher Channels. The sample app nosotros will be building is a movie review app chosen "revue".
Here is what the last app will await like:
You tin find the complete lawmaking hosted on Github.
Setting up with Vue-cli
Vue-cli is a great command line tool for scaffolding Vue.js projects, so we don't take to spend too much fourth dimension on configuration, and can jump right into writing lawmaking!
If you oasis't already, install vue-cli:
npm install -g vue-cli
Nosotros volition create a project with the webpack template, and install the dependencies with this gear up of commands:
vue init webpack revue cd revue npm install
Webpack is a build tool that helps u.s. do a agglomeration of things similar parse Vue single file components, and convert our ES6 lawmaking to ES5 so we don't accept to worry about browser compatibility. You can cheque here for more details about the webpack template.
To run the app:
npm run dev
We can as well optionally include Foundation in the alphabetize.html
file to accept advantage of some preset styling:
< ! -- . /index.html -- > < ! DOCTYPE html> <html> <head> <meta charset= "utf-8" > < ! -- import foundation -- > <link rel= "stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/foundation/six.three.1/css/foundation.min.css" > <title>revue< /title> < /head> <body> <div id= "app" > < /div> < ! -- built files will be auto injected -- > < /trunk> < /html>
Creating the moving-picture show review app
We will become started by creating the movie and review components of the app:
touch on . /src/components/Movie.vue impact . /src/components/Reviews.vue
Information technology is helpful to know that one of the things that makes Vue so powerful is its components, much like other mod JavaScript frameworks. A typical app should exist a series of components built on pinnacle of i another. This keeps our app modular, and helps make dissimilar parts of the app reusable.
Searching and retrieving a film
To bear witness the movie to be reviewed, we will create a elementary form which we will utilize to fetch a picture show from the Netflix Roulette public database API:
< ! -- . /src/components/Movie.vue -- > <template> <div course = "container" > <div class = "row" > <form @submit.prevent= "fetchMovie()" > <div class = "columns large-eight" > <input type= "text" 5-model= "title" > < /div> <div class = "columns large-4" > <button type= "submit" :disabled= "!championship" grade = "button expanded" > Search titles < /push> < /div> < /grade> < /div> < ! -- /search form row -- > < /div> < ! -- /container -- > < /template>
In the to a higher place lawmaking, we created a class, and specified a custom fetchMovie()
effect handler on class submit. Don't worry, nosotros volition ascertain this handler in a chip.
The @submit
directive is autograph for 5-on:submit
. The 5-on
directive is used to heed to DOM events and run actions (or handlers) when they're triggered. The .prevent
modifier helps us abstract the need to write effect.preventDefault()
in the handler logic… which is pretty cool.
Y'all can read more than on Vue.js result handlers here.
We also use the v-model
directive to bind the value of the text input to title
. And finally we bind the disabled
attribute of the button such that information technology is ready to truthful if title
is absent, and vice versa. :disabled
is shorthand for v-demark:disabled
.
Side by side we define the methods and data values for the component:
< ! -- . /src/components/Movie.vue -- > <script> // define the external API URL const API_URL = 'https://netflixroulette.net/api/api.php' // Helper function to help build urls to fetch picture details from title role buildUrl ( title ) { render ` ${ API_URL } ?title= ${title} ` } export default { name: 'film' , // component proper name data ( ) { return { title: '' , error_message: '' , loading: false , // to runway when app is retrieving data movie: { } } } , methods: { fetchMovie ( ) { permit title = this .title if ( !title) { alert ( 'please enter a title to search for' ) return } this .loading = true fetch ( buildUrl (title) ) . and then ( response => response. json ( ) ) . then ( information => { this .loading = false this .error_message = '' if (data.errorcode) { this .error_message = ` Sorry, movie with title ' ${title} ' not found. Effort searching for "Fairy tail" or "The boondocks" instead. ` return } this .movie = data } ) . catch ( ( e ) => { console. log (due east) } ) } } } < /script>
In the above code, after defining the external URL nosotros want to query to become movies from, we specify the key Vue options we need for the component:
-
data
: this specifies properties we'll be needing in our component. Annotation that in a regular Vue construct information technology is an object, but it has to be returned as a function in a component. -
methods
: this specifies the methods nosotros are using in the component. For now, we only define one method — thefetchMovie()
method to retrieve movies. Find we also use the Fetch API for retrieving results, to keep things simple.
Notation: The JavaScript Fetch API is smashing for making AJAX requests, although it requires a polyfill for older browsers. A keen alternative is axios.
Next, we can add together the code to brandish the pic, and prove a discover when the movie title isn't institute, inside the <template>
:
< ! -- . /src/components/Movie.vue -- > <template> < ! -- // ... --> <div v- if = "loading" class = "loader" > <img src= "https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/0.16.1/images/loader-large.gif" alt= "loader" > < /div> <div v- else - if = "error_message" > <h3> { { error_message } } < /h3> < /div> <div class = "row" v- else - if = "Object.keys(movie).length !== 0" id= "picture show" > <div class = "columns large-7" > <h4> { { movie.show_title } } < /h4> <img :src= "movie.poster" :alt= "film.show_title" > < /div> <div course = "columns big-5" > <p> { { moving picture.summary } } < /p> <small> <strong>Cast: < /potent> { { flick.show_cast } } < /pocket-size> < /div> < /div> < /template>
We use double curly braces for text interpolation. Nosotros also introduced new v-if
, 5-else-if
and v-else
directives, which we use to conditionally render elements.
We can add some optional styling at the bottom of the component:
< ! -- . /src/components/Pic.vue -- > < ! -- Add "scoped" attribute to limit CSS to this component only -- > <style scoped> #movie { margin: thirtypx 0 ; } .loader { text-align: center; } < /fashion>
The last Motion picture.vue
file will await like this.
Retrieving and writing movie reviews
Side by side, we will edit the review component, which volition contain the logic and view for reviews, using the aforementioned Single File Component arroyo.
First, we use a 5-for
directive to loop through the available reviews for a picture and display information technology in the template:
< ! -- . /src/components/Review.vue -- > <template> <div class = "container" > <h4 class = "capital" >reviews< /h4> <div class = "review" v- for = "review in reviews" > <p> { { review.content } } < /p> <div class = "row" > <div grade = "columns medium-7" > <h5> { { review.reviewer } } < /h5> < /div> <div form = "columns medium-v" > <h5 class = "pull-right" > { { review.time } } < /h5> < /div> < /div> < /div> < /div> < /template> <script> const MOCK_REVIEWS = [ { movie_id: 7128 , content: 'Great testify! I loved every unmarried scene. Defintiely a must watch!' , reviewer: 'Jane Doe' , time: new Date ( ) . toLocaleDateString ( ) } ] export default { name: 'reviews' , data ( ) { return { mockReviews: MOCK_REVIEWS , movie: null , review: { content: '' , reviewer: '' } } } , computed: { reviews ( ) { return this .mockReviews. filter ( review => { return review.movie_id === this .movie } ) } } } < /script>
We create MOCK_REVIEWS
to mock the bachelor reviews, gotten from a resource, for example, an API. And so, we use a computed property to filter out the reviews for a particular picture show. This would typically exist gotten from the API or resource.
Next, we add a form and method for adding a new review:
< ! -- . /src/components/Review.vue -- > <template> <div class = "container" > < ! -- //... --> <div class = "review-form" five- if = "motion-picture show" > <h5>add together new review. < /h5> <class @submit.prevent= "addReview" > <label> Review <textarea 5-model= "review.content" cols= "30" rows= "5" > < /textarea> < /label> <characterization> Name <input 5-model= "review.reviewer" type= "text" > < /characterization> <button :disabled= "!review.reviewer || !review.content" type= "submit" class = "button expanded" >Submit< /button> < /grade> < /div> < ! -- //... --> < /div> < /template> <script> export default { // .. methods: { addReview ( ) { if ( ! this .picture || ! this .review.reviewer || ! this .review.content) { return } let review = { movie_id: this .movie, content: this .review.content, reviewer: this .review.reviewer, time: new Date ( ) . toLocaleDateString ( ) } this .mockReviews. unshift (review) } } , //... } < /script>
Nosotros tin can add together some optional styling at the bottom of the component:
< ! -- . /src/components/Review.vue -- > < ! -- Add "scoped" attribute to limit CSS to this component only -- > <way scoped> .container { padding: 0 20px; } .review { edge: ipx solid #ddd; font-size: 0.95em; padding: 10px; margin: fifteenpx 0 vpx 0 ; } .review h5 { text-transform: majuscule; font-weight: bolder; font-size: 0.sevenem } .pull-right { float: right; } .review-form { margin-pinnacle: 30px; edge-elevation: 1px solid #ddd; padding: 15px 0 0 0 ; } < /fashion>
To fetch and post reviews, we demand to utilise the moving-picture show
identifier, which is gotten in the Movie
component. Thankfully, component-to-component advice can exist done really easily in Vue.
Component-to-component communication
As recommended in the official documentation, we can create a new Vue case and use it as a bulletin motorcoach. The message charabanc is an object that components tin can emit and listen to events on. In a larger awarding, a more than robust country management solution like Vuex is recommended.
Creating the bulletin motorcoach:
touch . /src/bus.js
// ./src/bus.js import Vue from 'vue' const bus = new Vue ( ) export default bus
To emit an event in one case a movie is found, we update the fetchMovies()
method:
< ! -- . /src/components/Pic.vue -- > import motorbus from '../bus' export default { // ... methods: { fetchMovie ( title ) { this .loading = truthful fetch ( buildUrl (title) ) . and so ( response => response. json ( ) ) . then ( data => { this .loading = simulated this .error_message = '' bus. $emit ( 'new_movie' , data.unit) // emit `new_movie` effect if (data.errorcode) { this .error_message = ` Sorry, pic with title ' ${championship} ' non found. Try searching for "Fairy tail" or "The boondocks" instead. ` return } this .movie = data } ) . take hold of ( e => { console. log (e) } ) } } }
Listening for the event in the Review
component, in the created
hook:
< ! -- . /src/components/Review.vue -- > <script> import double-decker from '../bus' export default { // ... created ( ) { coach. $on ( 'new_movie' , movieId => { this .movie = movieId } ) } , // ... } < /script>
In the higher up lawmaking, we specify that whenever the new_movie
event is fired, nosotros gear up the movie
property to be the value of the movieId
that is broadcast by the issue.
For a better understanding of the Vue lifecycle hooks, you lot can check out the official documentation on the subject.
Finally to complete our base app, we register our components in App.vue
, and display the templates:
< ! -- . /src/App.vue -- > <template> <div id= "app" > <div class = "container" > <div class = "heading" > <h2>revue. < /h2> <h6 class = "subheader" >realtime film reviews with Vue.js and Pusher. < /h6> < /div> <div grade = "row" > <div class = "columns modest-seven" > <movie> < /moving-picture show> < /div> <div class = "columns pocket-sized-v" > <reviews> < /reviews> < /div> < /div> < /div> < /div> < /template> <script> import Film from './components/Motion-picture show' import Reviews from './components/Reviews' export default { proper name: 'app' , components: { Movie, Reviews } } < /script> <style> #app .heading { font-family unit: 'Avenir' , Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #twoc3e50; margin: 60px 0 30px; border-bottom: 1px solid #eee; } < /style>
Now, we can run the app, and see the basic functionalities of retrieving movies and calculation reviews!
npm run dev
Note: To retrieve movies from the public API, the movie titles accept to be typed in full. Also, the bachelor movies are limited, so don't be too disappointed if you don't detect a title yous search for. :)
Adding realtime updates to the app with Pusher Channels
We tin add realtime functionality to our app so that whenever a review is added, it is updated in real time to all users viewing that picture.
We will set up a uncomplicated backend where we can process post requests with new reviews, and circulate an consequence via Pusher whenever a review is added.
Channels setup
Caput over to Pusher and annals for a free account, if you don't already have one. Then create a Channels app on the dashboard, and copy out the app credentials (App ID, Key, Undercover and Cluster). Information technology is super straight-forrard.
Backend setup and dissemination an event
We will build a simple server with Node.js. Let u.s. add some dependencies we will be needing to our bundle.json
and pull them in:
npm install - South express body-parser pusher
Adjacent, we create a server.js
file, where nosotros volition build an Express app:
// ./server.js /* * Initialise Express */ const express = require ( 'limited' ) ; const path = require ( 'path' ) ; const app = express ( ) ; const bodyParser = require ( 'body-parser' ) ; app. utilize (bodyParser. json ( ) ) ; app. utilise (bodyParser. urlencoded ( { extended: true } ) ) ; app. use (limited. static (path. bring together (__dirname) ) ) ; /* * Initialise Pusher */ const Pusher = require ( 'pusher' ) ; const pusher = new Pusher ( { appId: 'YOUR_PUSHER_APP_ID' , key: 'YOUR_PUSHER_APP_KEY' , secret: 'YOUR_PUSHER_SECRET' , cluster: 'YOUR_CLUSTER' } ) ; /* * Ascertain post route for creating new reviews */ app. post ( '/review' , ( req, res ) => { pusher. trigger ( 'reviews' , 'review_added' , {review: req.torso} ) ; res. status ( 200 ) . send ( ) ; } ) ; /* * Run app */ const port = 5000 ; app. heed (port, ( ) => { panel. log ( ` App listening on port ${port} ! ` ) } ) ;
Get-go we initialise an limited
app, and so we initialise Pusher with the required credentials. Think to supercede YOUR_PUSHER_APP_ID
, YOUR_PUSHER_APP_KEY
, YOUR_PUSHER_SECRET
and YOUR_CLUSTER
with your actual details from the Pusher dashboard.
Next, nosotros define a route for creating reviews: /review
. Whenever this endpoint is hit, we employ Pusher to trigger a review_added
event on the reviews
aqueduct and circulate the unabridged payload as the review.
The trigger
method has this syntax: pusher.trigger(channels, event, data, socketId, callback);
. You can read more on it here.
We are dissemination on a public aqueduct equally nosotros desire the data to be accessible to everyone. Pusher besides allows broadcasting on private (prefixed by private-
) and presence (prefixed by individual-
) channels, which require some course of authentication.
Creating an API proxy
To access our API server from the front-end server created by the Vue Webpack scaffolding, we tin create a proxy in config/index.js
, and run the dev server and the API backend side-by-side. All requests to /api
will be proxied to the actual backend:
// config/index.js module.exports = { // ... dev: { // ... proxyTable: { '/api' : { target: 'http://localhost:5000' , // y'all should modify this, depending on the port your server is running on changeOrigin: true , pathRewrite: { '^/api' : '' } } } , // ... } }
Then, we adjust our addReview
method to postal service to the API in ./src/components/Reviews.vue
:
< ! -- . /src/components/Review.vue -- > <script> // ... consign default { // ... methods: { addReview ( ) { if ( ! this .picture || ! this .review.reviewer || ! this .review.content) { alert ( 'please make sure all fields are not empty' ) return } let review = { movie_id: this .movie, content: this .review.content, reviewer: this .review.reviewer, time: new Engagement ( ) . toLocaleDateString ( ) } fetch ( '/api/review' , { method: 'post' , trunk: JSON . stringify (review) } ) . then ( ( ) => { this .review.content = this .review.reviewer = '' } ) } // ... } , // ... } < /script>
Listening for events
Finally, in our view, we tin can listen for events circulate by Pusher, and update it with details, whenever a new review is published. First we add the pusher-js
library:
npm install - Southward pusher-js
Updating Review.vue
:
< ! -- . /src/components/Review.vue -- > <script> import Pusher from 'pusher-js' // import Pusher export default { // ... created ( ) { // ... this . subscribe ( ) } , methods: { // ... subscribe ( ) { let pusher = new Pusher ( 'YOUR_PUSHER_APP_KEY' , { cluster: 'YOUR_CLUSTER' } ) pusher. subscribe ( 'reviews' ) pusher . bind ( 'review_added' , data => { this .mockReviews. unshift (data.review) } ) } } , // ... } < /script>
In the to a higher place code, starting time we import the Pusher
object from the pusher-js
library, then we create a subscribe
method that does the following:
- Subscribes to the
reviews
channel withpusher.subscribe('reviews')
- Listens for the
review_added
outcome, withpusher.bind
, which receives a callback role equally its second argument. Whenever it receives a broadcast, it triggers the callback function with the information circulate as the office parameter. We update the view in this callback function past adding the new object to themockReviews
array.
Bringing it all together
We tin add node server.js
to our app's dev/offset script so the API server starts along with the server provided by the webpack template:
{ // ... "scripts" : { "dev" : "node server.js & node build/dev-server.js" , "start" : "node server.js & node build/dev-server.js" , // ... } }
To compile and run the complete app:
npm run dev
Visit localhost:8080 to view the app in action!
Conclusion
In this tutorial, we have learned how to build a Vue.js app with the webpack template. We also learned how to work with Unmarried File Components and common Vue template directives. Finally, we learned how to make our Vue.js app realtime, utilising the simplicity and power of Pusher.
In my opinion, Vue.js is a really robust, and even so simple framework. It provides a smashing base of operations for edifice robust realtime applications. There is also another great example here of using Vue.js and Pusher for realtime applications.
Is An Id In Vue Local To The Template,
Source: https://pusher.com/tutorials/realtime-app-vuejs/
Posted by: hatchhadmingesen.blogspot.com
0 Response to "Is An Id In Vue Local To The Template"
Post a Comment