How to Upload Info Vue Login Signup

Look for the 🛠️️ emoji if you'd like to skim through the content while focusing on the build steps.

In this commodity, yous'll learn how to build a Vue website that will showcase events hosted by an organization. Users will sign in to view the details page of an event, and so you'll also add authentication to the website. You'll learn some Vue background, Vue awarding construction, creating components, setting upwardly routing, and styling with Bulma.

You can find the final lawmaking in this GitHub repository if you'd like to run across the end upshot now.

❗ If you already accept a Vue application and but want to add together hallmark, bound to this section to larn how.

Vue events authentication app

⚡️ This is a two-part tutorial! Part one does not cover authorization. You will set the stage for part two by building the website and integrating user login. So in part two, you'll larn how to but show certain information if a user is signed in and has been authorized to admission that data.

Requirements

This application is using the latest versions (at the fourth dimension of writing — 8/8/2020) of the following:

  • Vue.js ( 2.half-dozen .11 )
  • Node.js ( 12.18 .two )

Note: This tutorial uses Vue 2. The release for Vue 3 is scheduled for the third quarter of 2020, only that doesn't mean you shouldn't outset with Vue two! This tutorial lays down the foundations of Vue that will carry over into the next release besides.

You tin can download Node.js hither, which automatically installs npm, a Node package managing director, as well.

Npm allows you to quickly install millions of libraries and hands manage any dependencies you take in your applications. You'll come across how beneficial this is presently.

This tutorial will walk you through how to create everything from scratch, then you don't need to have any prior knowledge of Vue or Node to follow along! You will, even so, need a lawmaking editor (VS Code is my favorite) and admission to the final to follow this tutorial.

Permit's become started!

Why Larn Vue?

Vue history and popularity

Vue.js is a JavaScript framework created by Evan You that has diddled upward in popularity over the last few years.

Vue State of JS Survey - Popularity Source: 2018 State of JS Survey Involvement in Vue.js has nigh tripled from 2016 to 2018 with an increase in those who are interested in learning information technology and those who would use it again.

Vue State of JS Survey - Framework comparison Source: 2018 Country of JS Survey In 2018, the majority of people surveyed have heard of Vue.js and would like to learn it or take already used it and would employ it again.

Evan You launched the projection after having worked on several AngularJS projects when he worked for Google. Vue isn't backed by huge companies like Google (Angular) or Facebook (React), merely as you tin see in the charts higher up, Vue is still able to stand up on its own amidst the top JavaScript frameworks.

Because of Evan Y'all's history at Google, you might even detect some similarities betwixt Vue and AngularJS (old Angular).

I figured, what if I could but extract the part that I really liked near Angular and build something really lightweight.

— Evan You on creating Vue.js

Vue vs. Angular vs. React

One of the best things about Vue is the low barrier to entry.

Vue State of JS Survey - Most liked Source: 2018 State of JS Survey For developers who chose "would use again", their favorite Vue.js features were the easy learning curve, elegant programming manner, and good documentation.

A lot of other frameworks may require (or strongly suggest) that yous acquire their ain syntax or integrate other technologies (e.chiliad., TypeScript for Athwart or JSX for React). Of course, there's nothing wrong with this, but it does go far a picayune harder for a beginner to get started when they have to know all the things right away. Vue allows you lot to use TypeScript or even JSX if you'd like, but information technology's not required. This isn't to say one method is better than the other, but this HTML-like syntax is 1 possible caption equally to why developers find Vue easier to learn initially.

Once again, when information technology comes to comparing the popular frameworks, none of them are ameliorate than the others. At the end of the twenty-four hour period, it comes down to what you feel most comfortable using.

Vue is a keen selection if you're looking to get something up and running quickly. It has great community support, robust documentation in several languages, and it'due south just fun to utilise!

Setting Up

Alright, allow'south get started with some code.

First, open your terminal and switch to the directory that you want to shop the project in.

You're going to create this new project using the Vue CLI.

🛠️️ The Vue CLI tool helps get up and running with Vue quickly by letting yous choose from pre-configured build setups. To utilize the CLI, run the following in your terminal:

          npx @vue/cli create events-app        

This creates a new binder called events-app and starts the installation procedure in that folder.

Annotation: npx allows you to utilize the Vue CLI without installing it globally. Information technology's available in versions of npm >= five.2.0.

The CLI volition at present ask you a few questions then that it can gear up the app correctly. The options that this tutorial uses are listed below. Press ENTER to select.

🛠️️ Step 1: Pick a preset — Manually select features

          ? Please selection a preset:   default            (boom-boom, eslint)            >            Manually            select            features        

🛠️️ Step 2: Check the features needed — Babel, Router, CSS Pre-processors, Linter/Formatter

Press Infinite to select multiple features and ENTER once you lot have all features selected.

          ? Cheque the features needed            for            your projection:            (Printing            <infinite>            to select,            <a>            to toggle all,            <i>            to invert pick)            ◉ Babel  ◯ TypeScript  ◯ Progressive Web App            (PWA)            Support  ◉ Router  ◯ Vuex  ◉ CSS Pre-processors  ◉ Linter / Formatter  ◯ Unit of measurement Testing  ◯ E2E Testing        

🛠️️ Stride 3: History way — Y

          ? Use            history            mode            for            router?            (Requires proper server setup            for            alphabetize fallback            in            production)            (Y/n)            Y        

Note: This will remove the default hash (#) from URLs.

🛠️️ Step four: CSS pre-processor — Sass/ SCSS ( with sprint-sass)

          ? Pick a CSS pre-processor            (PostCSS, Autoprefixer and CSS Modules are supported by default):            (Apply arrow keys)            ❯ Sass/SCSS            (with dart-sass)            Sass/SCSS            (with node-sass)            Less   Stylus        

Annotation: Dart Sass is the primary implementation of Sass.

🛠️️ Pace 5: Option a linter/formatter —ESLint with error prevention only

          ? Pick a linter / formatter config:            (Use pointer keys)            ❯ ESLint with error prevention simply   ESLint + Airbnb config   ESLint + Standard config   ESLint + Prettier        

🛠️️ Step 6: Additional lint features — Lint and fix on commit

          ? Pick boosted lint features:   ◯ Lint on save ❯ ◉ Lint and ready on commit        

🛠️️ Step 7: Config location — In defended config files

          ? Where            do            you prefer placing config            for            Babel, PostCSS, ESLint, etc.?            (Use pointer keys)            ❯ In dedicated config files   In package.json        

🛠️️ Pace 8: Relieve equally preset — N

          ? Relieve this every bit a preset            for            future projects?            (y/Due north)            Northward        

At present the CLI will configure your application. It will likewise install the dependencies, so give it a little fourth dimension (~30 seconds).

🛠️️ Once it's finished, y'all can showtime the application past running npm run serve or yarn serve:

                      cd            events-app            npm            run serve        

Run across it in activity at http: / / localhost:8080 / ! Get alee and go along this running in the background so that you tin can see the app's progress as you lot go through the tutorial.

"The Vue CLI helps you lot become up and running with Vue.js in seconds!"

Tweet

Tweet This

Vue App Architecture

At present open your project in your code editor, and you'll see some default files that the CLI created. Allow'due south clean some of this upwardly.

🛠️️ Delete these files:

src/components/HelloWorld.vue

src/avails/logo.png

🛠️️ At present open up up src/views/Abode.vue and replace it with the following:

                                                    <template              >                                                      <div              class                              =                "home"                            >                                                      </div              >                                                      </template              >                                                      <script              >                                                      export                default                {                name:                'habitation'                ,                components:                {                }                ,                }                ;                                                                    </script              >                              

This volition leave yous with a blank homepage and a nav bar with 2 links: Home and About.

Vue CLI starter

Let's take a quick look at the important remaining files and so that you can run across how they piece of work together.

main.js

The first file to notation is the src/main.js file. This will be the entry point for your Vue application.

                      import            Vue            from            'vue'            ;            import            App            from            './App.vue'            ;            import            router            from            './router'            ;            Vue.config.productionTip            =            imitation            ;            new            Vue            (            {            router,            return            :            (            h            )            =>            h            (App)            ,            }            )            .            $mount            (            '#app'            )            ;                  

You take your imports at the top of the file:

  • Vue itself
  • The App component (which we'll become over in a moment)
  • The router (created past the CLI).

Next, you lot have Vue.config.productionTip = simulated , which sets the app in development mode.

And finally, you're creating a new Vue instance at the bottom.

A Vue instance is required for every Vue application. The Vue instance will take an options object that contains information almost your awarding, such as the DOM chemical element that the Vue example will exist mounted on, data the case volition use, functions that run at some point during the instance's lifecycle, and more.

In this case, the Vue example is using the router, rendering the app with the App template (more on this soon), and then mounting it to the DOM element with the id of app.

index.html

Next, open upward public /index.html, and you lot'll see a adequately standard index HTML file.

                                    <!              DOCTYPE              html              >                                                      <html              lang                              =                "en"                            >                                                      <head              >                                                      <meta              charset                              =                "utf-viii"                            />                                                      <meta              http-equiv                              =                "X-UA-Compatible"                            content                              =                "IE=border"                            />                                                      <meta              proper name                              =                "viewport"                            content                              =                "width=device-width,initial-scale=1.0"                            />                                                      <link              rel                              =                "icon"                            href                              =                "<%= BASE_URL %>favicon.ico"                            />                                                      <title              >            <%= htmlWebpackPlugin.options.title %>                              </title              >                                                      </head              >                                                      <body              >                                                      <noscript              >                                                      <strong              >            Nosotros're sorry but <%= htmlWebpackPlugin.options.championship %> doesn't work         properly without JavaScript enabled. Please enable it to         continue.                              </potent              >                                                      </noscript              >                                                      <div              id                              =                "app"                            >                                                      </div              >                        <!-- built files volition be auto injected -->                                          </body              >                                                      </html              >                              

If you lot look toward the lesser of the file, you'll see where that mysterious #app in the src/main.js file comes into play. That div is where the Vue instance volition be injected.

App.vue

The next of import file is src/App.vue. This is your first component!

Y'all don't need to know all of the details of this file yet, but know that this is the adjacent "edifice block" of your Vue application. When you reviewed the src/master.js file, you saw it was importing and rendering a template called App, which is what this file is.

Before diving into the details of this file, let's first learn virtually what a component even is past reviewing Vue's component system.

Using Components in Vue

The concept of components, in general, is sometimes over-complicated, but in reality, it'due south quite simple. A component is a modular and reusable cake of code. Information technology contains all of the HTML, JavaScript, and CSS that it requires for its functionality.

Imagine you lot accept a simple website that has two pages: a home page and a portfolio folio.

  • Home page — Contains some images, bones information, and a carousel with some testimonials
  • Portfolio page — Contains some images and descriptions of your piece of work

You decide that y'all want your Portfolio folio to include all of the testimonials that are on your homepage as well.

In this scenario, you can copy/paste all of the code required for the testimonials onto both pages, but and then you'd be breaking the golden Dry out ("Don't Echo Yourself") rule.

This is where the idea of components starts to brand sense. Instead of creating duplicate code, you can pull that testimonial lawmaking out and package information technology into its ain file. This standalone chunk of code will contain the HTML, the styles, and whatever JS needed to brand the carousel work.

Now, whenever you want to insert that testimonial "component" somewhere, all you lot take to do is import that component!

Your application volition begin to take on a sort of tree structure. You'll have your "root" component, which in this case is src/App.vue, and that component will import other components. All of these small chunks of lawmaking come together to build your application.

Vue component tree structure

Source: Vuejs.org

Now that you lot have the idea of components downwards, permit's see what a Vue component looks like.

Vue components

There are a lot of means to structure components in Vue. Let's look at the most pop style: Single file components.

Unmarried file components package up the template, logic, and styles used past a component into one file with a .vue extension. This method requires a build setup, which the CLI has already fix up for you. Let'due south take a look at an example component.

                                                    <template              >                                                      <div              class                              =                "our-component"                            >                                                      <h1              >            I'm a component!                              </h1              >                                                      <ChildComponent              />                                                      </div              >                                                      </template              >                                                      <script              >                                                      import                ChildComponent                from                '@/components/ChildComponent'                ;                export                default                {                proper name:                'MyComponent'                ,                components:                {                ChildComponent,                }                ,                }                ;                                                                    </script              >                                                      <way              lang                              =                "scss"                            scoped              >                                                      .our-component                {                text-align                :                middle;                }                                                                    </style              >                              

The HTML is enclosed in a <template> < /template> tag. Within, yous'll see <ChildComponent / > . This is an case of how you can utilise another component within of this one.

Annotation: Y'all must ever have a parent <div> element that encloses the rest of the HTML subsequently the template tag.

Adjacent, there is a script tag, which includes:

  • An import statement that allows you to import and use other components inside this component.
  • An consign object that allows y'all to define and export this named component to reuse information technology across your application.
  • A components object inside the export where you tin can list all of the child components used in this component.

Annotation: This is a pretty basic example, just at that place are loads of other component options you lot tin can include in your component object.

Next, there is the <mode> tag. The styles defined here apply to this component and all of its children. In this case, even so, at that place is a scoped belongings added, which restricts these styles to only this component. And finally, you're also specifying that you're using SCSS equally the stylesheet language.

Let's take a look at that App.vue file once more now that you have a little more than background most component structure.

App.vue

Open upwards src/App.vue.

                                                    <template              >                                                      <div              id                              =                "app"                            >                                                      <div              id                              =                "nav"                            >                                                      <router-link              to                              =                "/"                            >            Home                              </router-link              >                        |                                          <router-link              to                              =                "/nearly"                            >            About                              </router-link              >                                                      </div              >                                                      <router-view              />                                                      </div              >                                                      </template              >                                                      <manner              lang                              =                "scss"                            >                                                      #app                {                font-family                :                'Avenir'                ,                Helvetica,                Arial,                sans-serif;                -webkit-font-smoothing                :                antialiased;                -moz-osx-font-smoothing                :                grayscale;                text-marshal                :                center;                color                :                #2c3e50;                }                #nav                {                padding                :                30px;     a                {                font-weight                :                bold;                color                :                #2c3e50;       &.router-link-exact-active                {                color                :                #42b983;                }                }                }                                                                    </style              >                              

This is the first view template to be rendered in your application. The rest of the components will start from here.

Take a await at <router-link> and <router-view> . This is how your application will handle routing. If you chose to have the router born using the CLI, you already have a nice template here to apply!

We'll go more in-depth on routing before long, but just know that when you click on one of those links, this same template will still be rendered, but <router-view / > will be replaced with whatever route is agile. In this case, either the Home or About component. This is how you lot'll exist able to reuse this same layout and navbar beyond the entire application.

Try clicking those links to see for yourself!

Building Application Components

Now that y'all know the anatomy of a Vue application and how to build a component, it's time to kickoff edifice!

🛠️️ Brand certain y'all're still in the events-app folder in the last and then create these files/folders:

                      cd            src/views            touch            EventSingle.vue        

Notation: If yous're on Windows, the bear upon command may not work, depending on your setup. You tin always create the file manually instead.

🛠️️ Now brand the components that will exist shared among these pages:

                      cd            ../components            touch            EventsList.vue            touch            EventCard.vue            mkdir            partials            affect            partials/Nav.vue        

That should exercise it for at present! Let's start filling these files in and go over the purpose of each file.

Using Bulma for Styling

To make styling a little easier, you lot're going to use Bulma, which is an open-source CSS framework.

🛠️️ Switch to the events-app binder and then enter the control below to install Bulma:

                      cd            ../..            npm            install            bulma        

🛠️️ Now open up src/main.js in your editor and import Bulma by calculation this to the top of the file afterwards all of the other imports:

                      // ...            import            'bulma/css/bulma.css'            ;            // ...                  

🛠️️ Outset the app up one more time so that y'all tin can meet your work in progress equally yous continue edifice in the next section.

                      npm            run serve        

You lot can but leave this running in the background for the rest of this tutorial, and you'll always be able to view it in the browser at http: / /localhost: 8080 .

Domicile Component

Now let's start working on the components.

🛠️️ Open up the Abode Component in src/views/Home.vue and paste in the following:

                                                    <template              >                                                      <div              form                              =                "home"                            >                                                      <section              class                              =                "hero is-nighttime"                            >                                                      <div              course                              =                "hero-trunk"                            >                                                      <div              class                              =                "container"                            >                                                      <h1              class                              =                "title"                            >            Welcome to the Fauna Rescue League                              </h1              >                                                      <h2              course                              =                "subtitle"                            >                        Make certain yous cheque out our upcoming events beneath                                          </h2              >                                                      <div              class                              =                "button-block"                            >                                                      <button              class                              =                "button is-twoscore is-dark"                            >                        Sign Up to Browse Events                                          </button              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </department              >                                                      </div              >                                                      </template              >                                                      <script              >                                                      export                default                {                name:                'home'                ,                components:                {                }                ,                }                ;                                                                    </script              >                                                      <style              lang                              =                "scss"                            scoped              >                                                      .hero                {                text-marshal                :                center;                background-paradigm                :                                  url                  (                  'https://cdn.auth0.com/weblog/vue-meetup/result-imprint.png'                  )                                ;                background-size                :                embrace;                background-position                :                eye;                background-echo                :                no-repeat;                tiptop                :                400px;                }                .hero-body .title                {                text-shadow                :                4px 4px 4px                rgba                (0,                0,                0,                0.6)                ;                padding                :                40px 0 20px 0;                font-size                :                60px;                }                .subtitle                {                text-shadow                :                4px 4px 4px                rgba                (0,                0,                0,                0.7)                ;                font-size                :                30px;                }                .button-block                {                text-align                :                center;                margin-left                :                machine;                margin-correct                :                auto;                width                :                100%;                position                :                accented;                bottom                :                -150px;     .button                {                margin-right                :                50px;                padding-left                :                50px;                padding-right                :                50px;                }                .welcome                {                width                :                400px;                padding                :                10px;                margin-left                :                auto;                margin-correct                :                auto;                }                }                .is-xl                {                font-size                :                i.7rem;                }                                                                    </style              >                              

This will requite you lot a big banner and button at the summit of the page. The button will lead to the signup form, which you'll wire up later.

About Component

The Nigh component comes default with the Vue install, just allow'due south just spruce it upward a picayune.

🛠️️ Open up up src/views/Almost.vue, and supervene upon all of it with this:

                                                    <template              >                                                      <div              form                              =                "well-nigh"                            >                                                      <div              grade                              =                "hero is-primary"                            >                                                      <div              grade                              =                "hero-trunk"                            >                                                      <div              class                              =                "container"                            >                                                      <h1              course                              =                "championship is-size-1"                            >            About Fauna Rescue League                              </h1              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      <div              class                              =                "container"                            >                                                      <p              form                              =                "org-description is-size-4"                            >                        Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius quia         aperiam eligendi dolorum reprehenderit ea amet, aliquid dolorem beatae,         iste aliquam ullam. Sequi ab eligendi consectetur neque laudantium,         libero asperiores.                                          </p              >                                                      <p              class                              =                "org-description is-size-iv"                            >                        Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius quia         aperiam eligendi dolorum reprehenderit ea amet, aliquid dolorem beatae,         iste aliquam ullam. Sequi ab eligendi consectetur neque laudantium,         libero asperiores.                                          </p              >                                                      </div              >                                                      </div              >                                                      </template              >                                                      <mode              lang                              =                "scss"                            scoped              >                                                      .org-description                {                margin-top                :                50px;                }                                                                    </style              >                              

Nav Component

🛠️️ At present fix up the nav. Open src/components/partials/Nav.vue and paste this in:

                                                    <template              >                                                      <nav              class                              =                "navbar container"                            role                              =                "navigation"                            aria-label                              =                "main navigation"                            >                                                      <div              course                              =                "navbar-brand"                            >                                                      <a              form                              =                "navbar-item"                            href                              =                "/"                            >                                                      <strong              form                              =                "is-size-four"                            >            Animal Rescue League                              </strong              >                                                      </a              >                                                      <a              role                              =                "push"                            class                              =                "navbar-burger burger"                            aria-label                              =                "carte du jour"                            aria-expanded                              =                "fake"                            data-target                              =                "navbarBasicExample"                            >                                                      <bridge              aria-hidden                              =                "true"                            >                                                      </span              >                                                      <span              aria-hidden                              =                "true"                            >                                                      </span              >                                                      <span              aria-hidden                              =                "truthful"                            >                                                      </span              >                                                      </a              >                                                      </div              >                                                      <div              id                              =                "navbar"                            class                              =                "navbar-menu"                            >                                                      <div              course                              =                "navbar-start"                            >                                                      <router-link              to                              =                "/"                            class                              =                "navbar-particular"                            >            Home                              </router-link              >                                                      <router-link              to                              =                "/virtually"                            class                              =                "navbar-particular"                            >            About                              </router-link              >                                                      </div              >                                                      <div              class                              =                "navbar-end"                            >                                                      <div              course                              =                "navbar-item"                            >                                                      <div              class                              =                "buttons"                            >                                                      <a              class                              =                "push is-dark"                            >                                                      <strong              >            Sign In                              </strong              >                                                      </a              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </nav              >                                                      </template              >                                                      <script              >                                                      export                default                {                proper name:                'Nav'                ,                }                ;                                                                    </script              >                                                      <mode              lang                              =                "scss"                            scoped              >                                                      nav                {                margin-top                :                25px;                margin-lesser                :                30px;     a                {                font-weight                :                bold;                color                :                #2c3e50;       &.router-link-exact-active                {                color                :                #d88d00;                }                }                }                                                                    </style              >                              

If you lot refresh, y'all'll observe the nav doesn't change. That's considering you're not really using this component anywhere.

🛠️️ Open up src/App.vue and supplant it with this:

                                                    <template              >                                                      <div              id                              =                "app"                            >                                                      <nav              />                                                      <router-view              />                                                      </div              >                                                      </template              >                                                      <script              >                                                      import                Nav                from                './components/partials/Nav.vue'                ;                export                default                {                name:                'app'                ,                components:                {                Nav,                }                ,                }                ;                                                                    </script              >                                                      <way              lang                              =                "scss"                            >                                                      #app                {                font-family                :                'Avenir'                ,                Helvetica,                Arial,                sans-serif;                -webkit-font-smoothing                :                antialiased;                -moz-osx-font-smoothing                :                grayscale;                colour                :                #2c3e50;                }                                                                    </fashion              >                              

Since yous're defining the router links in the Nav component now, yous can get rid of them in this file. All you demand to practise is import the Nav component. The old #nav styles have as well been deleted since the Nav component has its own styles.

At present, if you lot refresh, you should see your new nav! Yous can even click around, and information technology'll open up upwards the unlike routes you've specified in the Nav component.

Adjacent upwardly, you'll add a component to your Home page.

EventsList Component

🛠️️ Open up src/components/EventsList.vue and paste this in:

                                                    <template              >                                                      <div              class                              =                "events container"                            >                                                      <h2              class                              =                "subtitle is-iii"                            >            Bank check out our upcoming events                              </h2              >                                                      <div              class                              =                "columns is-multiline"                            >                                                      <div              class                              =                "column is-one-quarter"                            >                                                      <EventCard              />                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                                                      <script              >                                                      import                EventCard                from                '@/components/EventCard'                ;                consign                default                {                name:                'EventsList'                ,                components:                {                EventCard,                }                ,                }                ;                                                                    </script              >                                                      <style              lang                              =                "scss"                            scoped              >                                                      .events                {                margin-top                :                100px;                text-marshal                :                center;                }                                                                    </style              >                              

This volition create a cake of cards that takes upwards 1/four of the row (by using Bulma's column with is-1-quarter). Each of those 1/4 slots will exist filled with the EventCard component.

🛠️️ For now, simply echo that carte lawmaking a couple of times and so that you can see how the structure volition look.

                                                    <div              class                              =                "columns is-multiline"                            >                                                      <div              class                              =                "column is-one-quarter"                            >                                                      <EventCard              />                                                      </div              >                                                      <div              course                              =                "column is-one-quarter"                            >                                                      <EventCard              />                                                      </div              >                                                      </div              >                              

Next you need to:

  1. Import this into the Home component
  2. Add together information technology to the list of components that Home uses in export default { }
  3. Slot information technology into the appropriate place in the Dwelling template

🛠️️ Open up src/views/Home.vue and supercede the script section with this:

                                                    <script              >                                                      import                EventsList                from                '../components/EventsList'                ;                export                default                {                name:                'domicile'                ,                components:                {                EventsList,                }                ,                }                ;                                                                    </script              >                              

🛠️️ Now in the template department, call the component with <EventsList / > .

                                                    <template              >                                                      <div              course                              =                "home"                            >                                                      <section              class                              =                "hero is-dark"                            >                        <!-- ... -->                                          </section              >                                                      <EventsList              />                                                      </div              >                                                      </template              >                              

You should now see the subtitle text, "Check out our upcoming events", rendered below the homepage banner. However, none of the individual cards are showing all the same. That's because you haven't created them.

Vue and auth app partial homepage

Event Menu Component

🛠️️ Open up src/components/EventCard.vue and paste in:

                                                    <template              >                                                      <div              form                              =                "event-card"                            >                                                      <div              class                              =                "carte du jour"                            >                                                      <div              class                              =                "card-content"                            >                                                      <h2              class                              =                "is-size-4 has-text-weight-assuming"                            >            Event name                              </h2              >                                                      <minor              class                              =                "effect-date"                            >            Event date                              </modest              >                                                      <span              >            Issue location                              </span              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                                                      <script              >                                                      export                default                {                }                ;                                                                    </script              >                                                      <style              lang                              =                "scss"                            scoped              >                                                      .carte                {                background-prototype                :                                  url                  (                  'https://placekitten.com/400/400'                  )                                ;                meridian                :                200px;                background-position                :                middle;                groundwork-size                :                cover;                text-align                :                eye;                }                .card-content                {                padding-top                :                50px;                position                :                absolute;                colour                :                #fff;                groundwork-color                :                rgba                (0,                0,                0,                0.35)                ;                top                :                0;                padding                :                10px;                pinnacle                :                200px;                width                :                100%;     span                {                font-size                :                18px;                text-align                :                center;                width                :                100%;                position                :                absolute;                bottom                :                10px;                right                :                0;                }                h2                {                margin-top                :                10px;                }                }                .outcome-date                {                background-color                :                #151515;                colour                :                #fff;                font-size                :                0.75em;                padding                :                2px 10px;                position                :                absolute;                top                :                0;                right                :                0;                }                                                                    </mode              >                              

You lot should now run into the ii cards filled in with some mock content.

Vue events card component

Of course, you're going to want each bill of fare to be unique and correspond an bodily event. You lot'll come back to this component presently to see how y'all can feed data in and accomplish this.

For now, finish setting up the rest of your components.

Event Single Component

🛠️️ Open up src/views/EventSingle.vue and paste this in:

                                                    <template              >                                                      <div              form                              =                "event-single"                            >                                                      <section              class                              =                "hero is-primary"                            >                                                      <div              class                              =                "hero-body"                            >                                                      <div              class                              =                "container"                            >                                                      <h1              course                              =                "title"                            >            Issue name                              </h1              >                                                      <h2              class                              =                "subtitle                "                            >            Event date                              </h2              >                                                      </div              >                                                      </div              >                                                      </section              >                                                      <section              class                              =                "event-content"                            >                                                      <div              class                              =                "container"                            >                                                      <p              class                              =                "is-size-4 description"                            >            Event description                              </p              >                                                      <p              class                              =                "is-size-four"                            >            Location:                              </p              >                                                      <p              form                              =                "is-size-4"                            >            Category:                              </p              >                                                      <div              class                              =                "outcome-images columns is-multiline has-text-centered"                            >                                                      <div              grade                              =                "column is-i-third"                            >            Image PLACEHOLDER                              </div              >                                                      </div              >                                                      </div              >                                                      </section              >                                                      </div              >                                                      </template              >                                                      <script              >                                                      consign                default                {                }                ;                                                                    </script              >                                                      <style              lang                              =                "scss"                            scoped              >                                                      .result-single                {                margin-summit                :                30px;                }                .hero                {                margin-bottom                :                70px;                }                .event-images                {                margin-top                :                50px;                }                .description                {                margin-bottom                :                30px;                }                                                                    </fashion              >                              

This will be the page that appears when a user clicks on an event from the list on the homepage. Considering this page doesn't actually exist even so, this is a bully time to revisit your router.

Router paths

🛠️️ Open upward src/router/index.js and replace the contents with this:

                      import            Vue            from            'vue'            ;            import            Router            from            'vue-router'            ;            import            Home            from            '../views/Home.vue'            ;            Vue.            apply            (Router)            ;            export            default            new            Router            (            {            mode:            'history'            ,            base:            procedure.env.            BASE_URL            ,            routes:            [            {            path:            '/'            ,            name:            'domicile'            ,            component:            Habitation,            }            ,            {            path:            '/about'            ,            name:            'about'            ,            component            :            (            )            =>            import            (            '../views/Nearly.vue'            )            ,            }            ,            {            path:            '/result/:id'            ,            name:            'eventSingle'            ,            component            :            (            )            =>            import            (            '../views/EventSingle.vue'            )            ,            }            ,            ]            ,            }            )            ;                  

Press save and navigate to http: / /localhost: 8080 /event/ 1 . You should at present encounter the contents of the EventSingle component!

Event single page placeholder

If you look under path in the router, you lot'll see a route parameter, :id. This is how you'll create split pages for every event. Once yous add in the data, you can navigate to any event by appending its id to the end of / event / .

Let'south work on adding data now.

Calculation Data to your Vue App

To keep this tutorial focused on the basics of Vue, y'all're just going to create an array of objects (where each object is an effect) and store it in the component that needs it.

Ideally, you would want to pull information from an API to dynamically fill in the cake of cards, but that's a little outside the scope of this tutorial. If you're interested in making calls to an API using Vue and securing any data you have, make sure you lot read part ii of this tutorial where you'll do just that!

Allow's revisit those three components that were missing dynamic data and see how to fill them in.

EventsList Component

🛠️️ Head back to the EventsList component in src/components/EventsList.vue and roll down to the bottom where the <script> tag starts. Supercede the entirety of <script> < /script> with this:

                                                    <script              >                                                      import                EventCard                from                '@/components/EventCard'                ;                export                default                {                proper name:                'EventsList'                ,                components:                {                EventCard,                }                ,                data                (                )                {                return                {                event:                {                }                ,                events:                [                {                id:                1                ,                name:                'Charity Brawl'                ,                category:                'Fundraising'                ,                clarification:                'Spend an elegant night of dinner and dancing with us every bit we raise money for our new rescue farm.'                ,                featuredImage:                'https://placekitten.com/500/500'                ,                images:                [                'https://placekitten.com/500/500'                ,                'https://placekitten.com/500/500'                ,                'https://placekitten.com/500/500'                ,                ]                ,                location:                '1234 Fancy Ave'                ,                date:                '12-25-2019'                ,                fourth dimension:                '11:30'                ,                }                ,                {                id:                2                ,                proper name:                'Rescue Center Goods Drive'                ,                category:                'Adoptions'                ,                description:                'Come to our donation bulldoze to help us replenish our stock of pet food, toys, bedding, etc. Nosotros will have live bands, games, nutrient trucks, and much more.'                ,                featuredImage:                'https://placekitten.com/500/500'                ,                images:                [                'https://placekitten.com/500/500'                ]                ,                location:                '1234 Dog Aisle'                ,                date:                '11-21-2019'                ,                fourth dimension:                '12:00'                ,                }                ,                ]                ,                }                ;                }                ,                }                ;                                                                    </script              >                              

The but thing that'due south changing here is the addition of a data ( ) function that returns an empty object chosen upshot and an array called events.

  • The events array holds 2 objects that each correspond to a different outcome
  • The result object will hold a single event to be passed to the child component, EventCard

Next, you lot need to change the HTML portion of this file to loop through these events and so send each one down the chain to be rendered by the kid component, EventCard.

🛠️️ Supplant everything between the <template> < /template> tags with:

                                                    <template              >                                                      <div              course                              =                "events container"                            >                                                      <h2              course                              =                "subtitle is-3"                            >            Check out our upcoming events                              </h2              >                                                      <div              form                              =                "columns is-multiline"                            >                                                      <div              five-for                              =                "consequence in events"                            :consequence                              =                "upshot"                            :cardinal                              =                "event.id"                            form                              =                "column is-one-quarter"                            >                                                      <router-link              :to                              =                "                '/event/'                + event.id"                            >                                                      <EventCard              :event                              =                "event"                            />                                                      </router-link              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                              

Allow's take a closer look at the block of code that changed (spaced out for better readability).

                                                    <div              v-for                              =                "outcome in events"                            :upshot                              =                "result"                            :key                              =                "event.id"                            class                              =                "cavalcade is-ane-quarter"                            >                                                      <router-link              :to                              =                "                '/event/'                + issue.id"                            >                                                      <EventCard              :issue                              =                "consequence"                            />                                                      </router-link              >                                                      </div              >                              

You tin can loop over the events in the events array using the Vue directive v- for . This acts equally a for loop and pulls out each issue individually then that it tin exist rendered separately past the EventCard component.

This is also the first time you're seeing a directive!

A directive is a special type of markup that you can utilise to do something to a DOM element. In Vue, these all begin with v- . Then, in this case, you're using the shorthand 5- for to create a for loop. Another common instance is v- if , which creates a conditional inside the template. You tin can run across a total listing of Vue directives here.

Here, you're using Vue'south :key aspect to bind a unique key (in this instance, id) to each upshot.

Annotation: In Vue, : is shorthand for 5-bind.

Y'all're besides binding the value of the electric current event in the for loop to the event object you created earlier with :outcome= "issue" . This volition allow y'all to transport this object downwards to the child component to be rendered separately.

Next, you're using <router-link> to make each card into a clickable link. Back in the router.js file, you created the road / outcome / :id with a route parameter of id. This route uses the EventSingle component, which will render the page for each specific effect. You're using the id from each event to make sure it links to the right outcome page.

Go alee and click one, and yous'll run into that it links to the single result page that you lot created.

Finally, you're calling the EventCard component to fill in each individual card. You're sending a variable chosen outcome downwardly to the card and then passing in the current outcome from the for loop.

Right now, the EventCard component isn't prepared to accept information, then let's prepare that.

EventCard Component

🛠️️ Open the EventCard component in src/components/EventCard.vue. Curl down to where you have the <script> < /script> tags and replace information technology with this:

                                                    <script              >                                                      consign                default                {                props:                [                'event'                ]                ,                }                ;                                                                    </script              >                              

This component has something new: props.

Whenever your component is expecting information, y'all should add that data'due south variable name to the props choice. props is kind of a funny give-and-take, only it actually but ways property.

A prop is a property on a component.

This is where you define the information that the component should be expecting from its parent component.

This event prop was passed to the current component from the parent component. This allows you to brandish it in the HTML template using curly braces:

          {{ event }}        

This is known as interpolation. Using string interpolation, yous're able to display the value of consequence in your template. This is a course of data-bounden, which ways that whenever the value of result in data changes, the displayed value in the template will also change.

🛠️️ To come across this in action, go alee and update the template section of EventCard.vue with this:

                                                    <template              >                                                      <div              form                              =                "result-card"                            >                                                      <div              class                              =                "card"                            >                                                      <div              class                              =                "carte-content"                            >                                                      <h2              class                              =                "is-size-iv has-text-weight-bold"                            >            {{ event.name }}                              </h2              >                                                      <modest              class                              =                "event-date"                            >            {{ outcome.date }}                              </small-scale              >                                                      <bridge              >            {{ event.location }}                              </span              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                              

If yous become back to the homepage in your browser, you'll see the cards at present accept the correct data!

Just to summarize, the parent component, EventsList, sent the event information downwards from the for loop two separate times. Each fourth dimension the EventCard component was called, it received the event data into props, which immune you to render the name, date, and location.

EventSingle Component

The last office of the application that needs updated data is the EventSingle component. Open up up src/views/EventSingle.vue.

You can run across the current state of this component in the browser at http: / /localhost: 8080 /event/ one . Everything is still difficult-coded in and waiting for data.

Vue single page placeholder

This component is a great example of how passing data starts to get tricky.

Think back to how the link to this page was gear up in EventsList.vue:

                                                    <router-link              :to                              =                "                '/event/'                + event.id"                            >                                                      <EventCard              :event                              =                "event"                            />                                                      </router-link              >                              

It uses the event.id from the for loop to create the link for each card/event, but how exercise y'all send the actual data through?

You can employ a method similar to the one you lot used earlier to make full in the data from EventCard and send some data down into a prop on EventSingle. Simply then you'd be using the router to manage data, which is a little foreign.

You lot also accept to consider what would happen if instead of clicking on the link, someone went directly to http: / /localhost: 8080 /outcome/ ane . How would information technology receive the props that it's expecting if that specific <router-link> code was never fired?

It wouldn't.

So for this application, your best selection is to just pull the information again.

Here's the gist of what needs to happen:

  1. Take hold of the id from the route parameter (in the URL)
  2. Utilise that to pull out the correct upshot from the list of all events
  3. Make full in the template with data from that specific event

🛠️️ To exercise this, open up EventSingle.vue and replace it entirely with:

                                                    <template              >                                                      <div              class                              =                "issue-single"                            >                                                      <department              class                              =                "hero is-chief"                            >                                                      <div              class                              =                "hero-body"                            >                                                      <div              grade                              =                "container"                            >                                                      <h1              class                              =                "title"                            >            {{ event.name }}                              </h1              >                                                      <h2              class                              =                "subtitle                "                            >                                                      <potent              >            Date:                              </strong              >                        {{ issue.engagement }}                                          <br              />                                                      <strong              >            Time:                              </stiff              >                        {{ event.fourth dimension }}                                          </h2              >                                                      </div              >                                                      </div              >                                                      </section              >                                                      <department              course                              =                "event-content"                            >                                                      <div              class                              =                "container"                            >                                                      <p              class                              =                "is-size-4 clarification"                            >            {{ event.description }}                              </p              >                                                      <p              class                              =                "is-size-5"                            >                                                      <potent              >            Location:                              </stiff              >                        {{ event.location }}                              </p              >                                                      <p              class                              =                "is-size-5"                            >                                                      <strong              >            Category:                              </strong              >                        {{ consequence.category }}                              </p              >                                                      <div              class                              =                "event-images columns is-multiline has-text-centered"                            >                                                      <div              v-for                              =                "image in consequence.images"                            :key                              =                "paradigm.id"                            class                              =                "column is-one-tertiary"                            >                                                      <img              :src                              =                "image"                            :alt                              =                "outcome.proper name"                            />                                                      </div              >                                                      </div              >                                                      </div              >                                                      </section              >                                                      </div              >                                                      </template              >                                                      <script              >                                                      export                default                {                name:                'EventSingle'                ,                information                (                )                {                return                {                events:                [                {                id:                one                ,                proper name:                'Clemency Ball'                ,                category:                'Fundraising'                ,                description:                'Spend an elegant night of dinner and dancing with us as nosotros raise coin for our new rescue farm.'                ,                featuredImage:                'https://placekitten.com/500/500'                ,                images:                [                'https://placekitten.com/500/500'                ,                'https://placekitten.com/500/500'                ,                'https://placekitten.com/500/500'                ,                ]                ,                location:                '1234 Fancy Ave'                ,                date:                '12-25-2019'                ,                fourth dimension:                'eleven:30'                ,                }                ,                {                id:                ii                ,                proper name:                'Rescue Heart Appurtenances Bulldoze'                ,                category:                'Adoptions'                ,                description:                'Come up to our donation drive to assistance united states of america furnish our stock of pet food, toys, bedding, etc. We will have live bands, games, nutrient trucks, and much more.'                ,                featuredImage:                'https://placekitten.com/500/500'                ,                images:                [                'https://placekitten.com/500/500'                ]                ,                location:                '1234 Dog Alley'                ,                engagement:                '11-21-2019'                ,                time:                '12:00'                ,                }                ,                ]                ,                consequence:                {                }                ,                }                ;                }                ,                created                (                )                {                const                ID                =                Number                (                this                .$route.params.id)                ;                allow                event                =                this                .events.                discover                (                (                event                )                =>                event.id                ===                ID                )                ;                this                .event                =                issue;                }                ,                }                ;                                                                    </script              >                              

Scroll down to the <script> section and you'll run across that the data you've been using has too been added to this component. But this fourth dimension, at that place's a new chunk of code:

                      created            (            )            {            const            ID            =            Number            (            this            .$route.params.id)            ;            const            event            =            this            .events.            find            (            event            =>            upshot.id            ===            ID            )            ;            this            .event            =            event;            }                  

First, permit'south go over what created ( ) is used for.

The Vue case goes through many steps when it'south created. Information technology sets up information ascertainment, compiles the template, mounts the Vue instance to the DOM, and updates the DOM when changes are detected.

But what if you need to spring in at some point betwixt these steps and run some lawmaking? Vue offers functions chosen lifecycle hooks that let you lot do just that.

The created ( ) claw lets you run some code right after the instance is created.

There are quite a few lifecycle hooks available, as you tin see in the image beneath.

Vue lifecycle hooks

Image Source: Vue.js Guide - Example

Then right afterward the instance is created, the created ( ) function runs.

                      created            (            )            {            const            ID            =            Number            (            this            .$route.params.id)            ;            const            upshot            =            this            .events.            find            (            effect            =>            event.id            ===            ID            )            ;            this            .effect            =            event;            }                  

This function creates a variable called ID that will hold the id of the event yous want to render. You're able to pull this id from the road parameter id that yous fix earlier in src/router/alphabetize.js.

Next, yous're creating a variable called event, which will concur the outcome object. It uses the JavaScript function discover ( ) on the events array, which will loop through the assortment until it finds an upshot with the id of ID (the road parameter).

And so you lot're setting the consequence variable to the result of this. And at present, you have the data needed to render this specific event!

Ideally, you'd want to pull this data from an API. In a case like this, you would merely hit the endpoint that returns the specific outcome that you want by sending over the route parameter, just since you don't have an API yet, this method is fine. In the follow up of this tutorial, y'all'll refactor this code to use an bodily API.

Another absurd affair you're doing is looping over the images in the specific consequence. Let's accept a closer await at the block of code that displays the images.

                                                    <div              class                              =                "result-images columns is-multiline has-text-centered"                            >                                                      <div              v-for                              =                "paradigm in event.images"                            :key                              =                "image.id"                            class                              =                "column is-1-third"                            >                                                      <img              :src                              =                "`${image}`"                            :alt                              =                "`${outcome.name}`"                            />                                                      </div              >                                                      </div              >                              

This uses Vue's v- for directive once again to loop through the images. Once it grabs a unmarried image, it binds the image URL, img, to the :src aspect. It's good practice to always set an alt aspect, and then you can bind the value for event.proper name to the alt attribute of these images.

Vue single event page

At present head back to the homepage and click around. All of the components are rendering the right information, so it's time to add together authentication!

Vue auth app homepage

Adding Hallmark to your Vue App

The concluding thing left to do is add login functionality to the application. Yous're going to use Auth0's hallmark service to do this.

Once you're registered, you'll be taken to the Auth0 management dashboard.

  • Click on "Applications" in the left sidebar
  • Click on the big cherry push that says "Create Application"
  • Name it "Vue Events" (or anything yous'd like)
  • Click on "Single Folio Web Applications" for "application type"
  • Click "Create"

Auth0 Dashboard

🛠️️ Next, click into "Settings" to fill up in some information that Auth0 needs to configure authentication for your awarding.

Allowed Callback URLshttp: / /localhost: 8080

This is where Auth0 volition redirect the user after they take authenticated.

Allowed Logout URLshttp: / /localhost: 8080

This is the URL that users will return to after they log out of your application.

Immune Spider web Originshttp: / /localhost: 8080

This is the URL that Auth0 uses for Cross-origin Authentication.

Scroll downwards and click the "Save Changes" push.

That'southward all you need from the dashboard for now, but don't click out yet. Y'all'll need to pull some of these values from the dashboard into your application soon.

Install Auth0 SPA package

🛠️️ Head dorsum to the last and install Auth0's auth0-spa-js package in the application'south root directory.

                      npm            install            @auth0/auth0-spa-js        

Create an authentication wrapper

Next, you're going to create a reusable wrapper Vue object around the Auth0 SDK. You'll too create a Vue plugin that exposes this wrapper to the remainder of the application.

🛠️️ Create a new file and folder for this. Make sure you're still in the events-app root directory and enter:

                      mkdir            src/auth            bear on            src/auth/index.js        

🛠️️ Now open up up the newly created src/auth/alphabetize.js file and paste in the following:

                      import            Vue            from            'vue'            ;            import            createAuth0Client            from            '@auth0/auth0-spa-js'            ;            /** Define a default action to perform after authentication */            const            DEFAULT_REDIRECT_CALLBACK            =            (            )            =>            window.history.            replaceState            (            {            }            ,            document.championship,            window.location.pathname)            ;            let            instance;            /** Returns the current example of the SDK */            export            const            getInstance            =            (            )            =>            instance;            /** Creates an instance of the Auth0 SDK. If one has already been created, it returns that instance */            export            const            useAuth0            =            (                          {              onRedirectCallback              =              DEFAULT_REDIRECT_CALLBACK              ,              redirectUri              =              window.location.origin,              ...options              }                        )            =>            {            if            (instance)            return            instance;            // The 'case' is but a Vue object            instance            =            new            Vue            (            {            data            (            )            {            render            {            loading:            true            ,            isAuthenticated:            simulated            ,            user:            {            }            ,            auth0Client:            nix            ,            popupOpen:            false            ,            error:            null            ,            }            ;            }            ,            methods:            {            /** Authenticates the user using a popup window */            async            loginWithPopup            (            o            )            {            this            .popupOpen            =            true            ;            try            {            wait            this            .auth0Client.            loginWithPopup            (o)            ;            }            catch            (east)            {            // eslint-disable-next-line            panel.            error            (eastward)            ;            }            finally            {            this            .popupOpen            =            false            ;            }            this            .user            =            await            this            .auth0Client.            getUser            (            )            ;            this            .isAuthenticated            =            true            ;            }            ,            /** Handles the callback when logging in using a redirect */            async            handleRedirectCallback            (            )            {            this            .loading            =            true            ;            try            {            expect            this            .auth0Client.            handleRedirectCallback            (            )            ;            this            .user            =            await            this            .auth0Client.            getUser            (            )            ;            this            .isAuthenticated            =            true            ;            }            catch            (e)            {            this            .error            =            e;            }            finally            {            this            .loading            =            false            ;            }            }            ,            /** Authenticates the user using the redirect method */            loginWithRedirect            (            o            )            {            render            this            .auth0Client.            loginWithRedirect            (o)            ;            }            ,            /** Returns all the claims present in the ID token */            getIdTokenClaims            (            o            )            {            return            this            .auth0Client.            getIdTokenClaims            (o)            ;            }            ,            /** Returns the access token. If the token is invalid or missing, a new one is retrieved */            getTokenSilently            (            o            )            {            return            this            .auth0Client.            getTokenSilently            (o)            ;            }            ,            /** Gets the admission token using a popup window */            getTokenWithPopup            (            o            )            {            return            this            .auth0Client.            getTokenWithPopup            (o)            ;            }            ,            /** Logs the user out and removes their session on the authorization server */            logout            (            o            )            {            return            this            .auth0Client.            logout            (o)            ;            }            ,            }            ,            /** Utilize this lifecycle method to instantiate the SDK client */            async            created            (            )            {            // Create a new instance of the SDK client using members of the given options object            this            .auth0Client            =            await            createAuth0Client            (            {            domain:            options.domain,            client_id:            options.clientId,            audience:            options.audience,            redirect_uri:            redirectUri,            }            )            ;            try            {            // If the user is returning to the app after authentication..            if            (            window.location.search.            includes            (            'code='            )            &&            window.location.search.            includes            (            'state='            )            )            {            // handle the redirect and retrieve tokens            const            {            appState            }            =            expect            this            .auth0Client.            handleRedirectCallback            (            )            ;            // Notify subscribers that the redirect callback has happened, passing the appState            // (useful for retrieving any pre-hallmark state)            onRedirectCallback            (appState)            ;            }            }            catch            (eastward)            {            this            .error            =            east;            }            finally            {            // Initialize the internal authentication state            this            .isAuthenticated            =            await            this            .auth0Client.            isAuthenticated            (            )            ;            this            .user            =            await            this            .auth0Client.            getUser            (            )            ;            this            .loading            =            false            ;            }            }            ,            }            )            ;            return            instance;            }            ;            // Create a unproblematic Vue plugin to expose the wrapper object throughout the application            export            const            Auth0Plugin            =            {            install            (            Vue,              options            )            {            Vue            .prototype.$auth            =            useAuth0            (options)            ;            }            ,            }            ;                  

The comments in this file cover the details of what's happening, but to summarize, you are kickoff creating (or returning) an instance of the Auth0 SDK. The instance is just a Vue object.

  • The instance contains the following data: loading, isAuthenticated, user, auth0Client, popupOpen, and error
  • It also includes several methods that volition be chosen afterwards, but take note of them now: loginWithPopup, handleRedirectCallback, loginWithRedirect, getIdTokenClaims, getTokenSilently, getTokenWithPopup, and logout

During the created ( ) lifecycle hook, y'all're creating an case of the SDK.

When a user clicks "Log in", they're redirected to the Auth0 Universal Login page (more than on this later). They will enter their credentials there and and then be redirected back to the application. This is where the "Allowed Callback URLs" from the Auth0 dashboard come into play. handleRedirectCallback ( ) will run, which will get the authenticated user data, retrieve tokens, and update isAuthenticated to true.

This instance too contains an options object (pulled out and pasted below). This object will hold the values for the Auth0 clientId, domain, and audience from the Auth0 dashboard.

                      // Create a new case of the SDK client using members of the given options object            this            .auth0Client            =            await            createAuth0Client            (            {            domain:            options.domain,            client_id:            options.clientId,            audience:            options.audition,            redirect_uri:            redirectUri,            }            )            ;                  

These values aren't particularly sensitive, but it'southward nonetheless a good practice to get out them out of your source control (due east.g. GitHub). Then permit'southward create a file that tin be added to .gitignore so that Git will ignore it.

🛠️️ Make certain yous're still in the events-app directory and run:

                      touch            auth_config.json        

If you're using Git or another version control, open up up .gitignore or its equivalent. Paste in auth_config.json on any line. Now this file will exist ignored the next fourth dimension yous push to your repo.

🛠️️ Next, open auth_config.json and paste in the following:

                      {            "domain"            :            "your-domain.auth0.com"            ,            "clientId"            :            "yourclientid"            }                  

Finding your auth_config values:

  • Head to the Auth0 dashboard
  • Click on "Applications" and select your application
  • Click on "Settings"
  • Copy the value for "Domain" and paste it into domain in auth_config.json
  • Copy the value for "Client ID" and paste it into clientId in auth_config.json

Next, open src/primary.js and install the plugin with Vue.use. This plugin will let you to access the authentication state globally (from anywhere in the application). Vue.utilise is a global method used to call plugins, and it must be placed before new Vue ( ) .

🛠️️ Replace all of src/chief.js with the following:

                      import            Vue            from            'vue'            ;            import            App            from            './App.vue'            ;            import            router            from            './router'            ;            import            'bulma/css/bulma.css'            ;            // Import the Auth0 configuration            import            {            domain,            clientId            }            from            '../auth_config.json'            ;            // Import the plugin here            import            {            Auth0Plugin            }            from            './auth'            ;            // Install the authentication plugin hither            Vue.            use            (Auth0Plugin,            {            domain,            clientId,            onRedirectCallback            :            (            appState            )            =>            {            router.            push            (            appState            &&            appState.targetUrl            ?            appState.targetUrl            :            window.location.pathname,            )            ;            }            ,            }            )            ;            Vue.config.productionTip            =            false            ;            new            Vue            (            {            router,            render            :            (            h            )            =>            h            (App)            ,            }            )            .            $mountain            (            '#app'            )            ;                  

Here you lot're but importing the Auth0 configuration file that you created to become access to the domain and clientId values. Adjacent, you're importing the Auth0Plugin that was created before.

Finally, you install and configure the plugin.

Wiring up login and logout buttons

Now that you take the Auth0 authentication plugin configured, it'southward time to fix up the "Sign in" button so that it really does something.

🛠️️ Open up up src/components/partials/Nav.vue. Find the block of code that starts with <div grade = "navbar-finish" > and replace it with this:

                                                    <div              class                              =                "navbar-end"                            >                                                      <div              course                              =                "navbar-detail"                            >                                                      <div              class                              =                "buttons"                            >                        <!-- Check that the SDK client is not currently loading before accessing is methods -->                                          <div              v-if                              =                "!$auth.loading"                            >                        <!-- show login when non authenticated -->                                          <a              v-if                              =                "!$auth.isAuthenticated"                            @click                              =                "login"                            class                              =                "push is-nighttime"                            >                                                      <strong              >            Sign in                              </strong              >                                                      </a              >                        <!-- show logout when authenticated -->                                          <a              v-if                              =                "$auth.isAuthenticated"                            @click                              =                "logout"                            class                              =                "button is-nighttime"                            >                                                      <stiff              >            Log out                              </strong              >                                                      </a              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </div              >                              

The buttons are now wrapped in !$auth.loading to make sure that the SDK customer has finished loading earlier yous to try access the user's state. Next, you're using @click, which will handle the click effect by calling the login or logout methods when a user clicks on the respective push button.

🛠️️ Allow's create those methods at present. In that aforementioned file, coil down to the <script> tag and replace information technology with this:

                      <script>            export            default            {            name:            'Nav'            ,            methods:            {            // Log the user in            login            (            )            {            this            .$auth.            loginWithRedirect            (            )            ;            }            ,            // Log the user out            logout            (            )            {            this            .$auth.            logout            (            {            returnTo:            window.location.origin            }            )            ;            }            }            }            <            /script>                  

Now head back to the application and click "Sign In" and yous should exist redirected to the Auth0 Universal Login folio.

If y'all run into an effect, double-check that your values in auth_config.json are right. If y'all're even so having issues, go out a comment below, and I'll assist you work through it.

Once you've hit the Auth0 Universal Login page, sign up with a mock user business relationship. You'll and then see a screen telling you that the application is requesting access to your profile and email.

Auth0 Vue login permissions

Click the checkmark, and you'll be redirected back to the "Allowed Callback URL" you specified in the dashboard, which is your application homepage. At present instead of the "Sign in" button, you should encounter a "Log out" button.

Optional: Auth0 offers social login options straight from the dashboard! Google is activated by default, and yous tin plough more than on individually in the Auth0 management dashboard.

Click on "Connections" > "Social" in the sidebar. Be certain to use your own dev keys if you'd like to integrate social sign-on. The default Auth0 dev keys are fine for testing, but may cause unexpected errors (such every bit beingness signed out on refresh), so we still recommend using your ain.

Accessing user information

Auth0 lets you access the information of the logged-in user in your templates with the post-obit:

                      {            {            $auth.user;            }            }                  

The contents of $auth.user look something like this:

                      {            "nickname"            :            "hollylloyd"            ,            "proper name"            :            "Holly Lloyd"            ,            "motion picture"            :            "https://gravatar.com/somefancyimage.png"            ,            "updated_at"            :            "2019-10-09T15:49:28.181Z"            ,            "email"            :            "holly-lloyd@example.com"            ,            "email_verified"            :            imitation            ,            "sub"            :            "auth0|xxxxxxxxxxxxxxx"            }                  

So if you want to add a profile folio in the time to come, yous accept access to this data (and more) to display.

Now that you know how to add a login button, let'south wire up that second button on the homepage.

🛠️️ Open up src/views/Home.vue and replace everything between <div class = "button-cake" > < /div> with the following:

                      <div            form            =            "button-block"            >            <button v-            if            =            "!$auth.isAuthenticated"            @click=            "login"            class            =            "button is-xl is-night"            >Sign Upward to Browse Events<            /button>            <h3 5-            if            =            "$auth.isAuthenticated"            class            =            "is-size-3 has-background-night welcome"            >Welcome,            {            {            $auth.user.proper name            }            }            !            <            /h3>            <            /div>                  

🛠️️ Now you but need to add the methods section with the login ( ) function. Scroll downward to where the <script> tag is and supersede export default { } with this:

                      export            default            {            name:            'home'            ,            components:            {            EventsList,            }            ,            methods:            {            // Log the user in            login            (            )            {            this            .$auth.            loginWithRedirect            (            )            ;            }            ,            }            ,            }            ;                  

Now a user can sign in with this push button as well, and in one case they're signed in, it will be replaced with a welcome message with their name using $auth.user.proper name.

Vue homepage logged in message

Gear up a Road Guard

So now, the final thing you need to practise is redirect unauthenticated users abroad from the Single Consequence folio. This means they should be able to view the homepage with the list of cards/events, but every bit soon equally they click through to the event detail folio, they should exist kicked to a login folio.

⚡️ Of import ⚡️ This only prevents the page from loading; it doesn't preclude the data from loading. You lot should NEVER rely on the frontend to protect your data.

Since yous haven't created a backend API yet, yous're just storing all of the data in the component on the frontend. Fifty-fifty though you're going to prepare a route baby-sit to redirect an unauthenticated user away from a unmarried event page, they tin can still read through the JavaScript files and observe it! I'll show you how in a moment.

{% if page.url contains '/amp/' %} In part 2, you'll build out the API and so that this data is stored and protected on the backend instead and only pulled into the frontend if the user is authenticated. {% else %} In office 2, you'll build out the API then that this data is stored and protected on the backend instead and only pulled into the frontend if the user is authenticated. {% endif %}

Permit'due south set up the route guard now so that when the data is coming from the backend, the UI for kicking the user to the login folio is already in identify.

🛠️️ Create a file called authGuard.js in the src/auth directory.

{% prism bash %} touch src/auth/authGuard.js {% endprism %}

🛠️️ Open that upwardly in your editor and paste in the following:

                      import            {            getInstance            }            from            './index'            ;            export            const            authGuard            =            (            to,              from              ,              next            )            =>            {            const            authService            =            getInstance            (            )            ;            const            fn            =            (            )            =>            {            // If the user is authenticated, continue with the road            if            (authService.isAuthenticated)            {            return            next            (            )            ;            }            // Otherwise, log in            authService.            loginWithRedirect            (            {            appState:            {            targetUrl:            to.fullPath            }            }            )            ;            }            ;            // If loading has already finished, check the auth land using `fn()`            if            (            !authService.loading)            {            return            fn            (            )            ;            }            // Sentry for the loading property to modify earlier checking isAuthenticated            authService.            $watch            (            'loading'            ,            (            loading            )            =>            {            if            (loading            ===            faux            )            {            render            fn            (            )            ;            }            }            )            ;            }            ;                  

This uses the getInstance method from the src/auth/index.js file, which will implement the part that prevents a route from being accessed if a user is not logged in.

If the user is authenticated, side by side ( ) is returned, which allows the user to go along to the clicked route. If the user isn't authenticated, they're redirected to the Auth0 Universal Login page.

Next, yous need to add this auth guard to the router and then that this runs earlier whatever view is returned.

You'll only cheque if the user is authenticated. If they are, let them through, if not, send them to the login page.

🛠️️ Open upward the router file in src/router/alphabetize.js and add together supervene upon it with:

                      import            Vue            from            'vue'            ;            import            Router            from            'vue-router'            ;            import            Dwelling            from            '../views/Home.vue'            ;            import            {            authGuard            }            from            '../auth/authGuard'            ;            Vue.            use            (Router)            ;            consign            default            new            Router            (            {            mode:            'history'            ,            base:            process.env.            BASE_URL            ,            routes:            [            {            path:            '/'            ,            proper name:            'domicile'            ,            component:            Home,            }            ,            {            path:            '/about'            ,            name:            'about'            ,            component            :            (            )            =>            import            (            '../views/Virtually.vue'            )            ,            }            ,            {            path:            '/event/:id'            ,            proper noun:            'eventSingle'            ,            component            :            (            )            =>            import            (            '../views/EventSingle.vue'            )            ,            beforeEnter:            authGuard,            }            ,            ]            ,            }            )            ;                  

The authGuard is imported at the top. Since you only want to require hallmark for the issue details route, beforeEnter: authGuard has been added to that road.

Now, if yous've already logged in previously, y'all can click on one of those event cards and you should yet be able to see the consequence unmarried folio.

Simply if you open an incognito window and try to access that same route, you'll be kicked to the login page, which is exactly what's expected!

Vue Auth0 login page

Equally discussed before, this doesn't prevent a user from finding the data for that page.

If you're curious how this is possible, sign out or open up an incognito window, and so go to http: / /localhost: 8080 /js/app.js in your browser. Now search for one of the event descriptions similar "Spend an elegant night of dinner and dancing with us every bit nosotros raise money for our new rescue farm.", and certain enough, there is the data!

So at this point, yous may be request, "Holly, then what is the point of the redirect?"

I'grand glad you asked! This is mostly meant for user experience! Imagine that the data is protected on the backend. You're going to want to signal that a user should be signed in to view that specific page. If you lot simply merely don't render any data on that page, the user will be faced with an empty page and recollect something is cleaved. In this scenario, redirecting them to the sign-in folio will easily signal that they demand to log in to view it!

In part two of this tutorial, you'll learn how to create an API in Express and pull the data into your Vue application from in that location. It uses the same Vue application that you just built, so if you lot're interested, you can hit the basis running!

Wrap Up

If this was your first fourth dimension working with Vue.js, hopefully this helped you empathise how everything comes together in a small-scale awarding. Just to recap, here are some of the topics that were covered in this tutorial:

  • Using the Vue CLI
  • Creating reusable components
  • Setting up routing with Vue Router
  • Styling with Bulma
  • Using props and data
  • Adding authentication to a Vue.js app
  • Protecting routes with Vue navigation guards

Check out the side by side tutorial on this topic where you can have this existing Vue application, connect information technology to an Express API, and learn how to secure those API endpoints to protect the data. Thanks for reading!

scottwhavin.blogspot.com

Source: https://auth0.com/blog/beginner-vuejs-tutorial-with-user-login/

0 Response to "How to Upload Info Vue Login Signup"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel