One place for hosting & domains

      Events

      How To Create User Interactions with Events in Vue


      The author selected Open Sourcing Mental Illness to receive a donation as part of the Write for DOnations program.

      Introduction

      In Vue.js development, a client’s web browser reads HTML and JavaScript and renders web pages based off of the instructions that the developer writes for it. But the web page or application not only needs to process data; it also needs to process user interactions. To do this, developers use events in JavaScript that execute code when the user interacts with HTML elements.

      An event can capture any user interaction with a user interface button or a physical keyboard or mouse. In JavaScript, you would create event listeners that wait for that event to occur and then execute a block of code. In Vue.js, you are not required to listen for an event; that is done automatically with the v-on: directive.

      In this tutorial, you will use events in Vue to create an application of airport codes. When the user selects an airport code, the app will add that airport to a “favorites” collection. By following along with this project, you will learn what events are, how to use Vue’s built-in events, and how to create your own custom events.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Setting Up the Project

      The first step in this tutorial will be to set up a demo project with some data to display in the view. This will include an array of JavaScript objects that contain airport data and a Vue component to iterate over and render the data.

      First, generate a project using Vue CLI:

      • vue create favorite-airports

      This will create a project named favorite-airports. This tutorial will use Vue 3, so when prompted, select the option Default (Vue 3) ([Vue 3] babel, eslint):

      Output

      Vue CLI v4.5.6 ? Please pick a preset: Default ([Vue 2] babel, eslint) ❯ Default (Vue 3) ([Vue 3] babel, eslint) Manually select features

      Once you have created the project, make a directory to hold all of your local data for this project. First, make the new project folder your working directory:

      Next, make a data directory in the src directory:

      In your text editor of choice, open a file called src/data/airports.js. Add the following data to the file:

      favorite-airports/src/data/airports.js

      export default [
        {
          name: 'Cincinnati/Northern Kentucky International Airport',
          abbreviation: 'CVG',
          city: 'Hebron',
          state: 'KY',
        },
        {
          name: 'Seattle-Tacoma International Airport',
          abbreviation: 'SEA',
          city: 'Seattle',
          state: 'WA',
        },
        {
          name: 'Minneapolis-Saint Paul International Airport',
          abbreviation: 'MSP',
          city: 'Bloomington',
          state: 'MN',
        },
        {
          name: 'Louis Armstrong New Orleans International Airport',
          abbreviation: 'MSY',
          city: 'New Orleans',
          state: 'LA',
        },
        {
          name: `Chicago O'hare International Airport`,
          abbreviation: 'ORD',
          city: 'Chicago',
          state: 'IL',
        },
        {
          name: `Miami International Airport`,
          abbreviation: 'MIA',
          city: 'Miami',
          state: 'FL',
        }
      ]
      

      This data is an array of objects consisting of a few airports in the United States. Next, you are going to iterate through this data to generate cards consisting of the name, abbreviation, city, and state properties. When the user clicks on a card, the app will emit an event up to the parent, which will add that airport to a collection of data that will represent your favorite airports.

      Save and close the airport.js file.

      To render the data, create a single-file component (SFC) with the name src/components/AirportCard.vue and open it in your text editor. This component will contain all of the styles and logic for the airport card.

      Add the following contents to the file:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          airport: {
            type: Object,
            required: true
          }
        }
      }
      </script>
      
      <style scoped>
      .airport {
        border: 3px solid;
        border-radius: .5rem;
        padding: 1rem;
      }
      
      .airport p:first-child {
        font-weight: bold;
        font-size: 2.5rem;
        margin: 1rem 0;
      }
      
      .airport p:last-child {
        font-style: italic;
        font-size: .8rem;
      }
      </style>
      

      This component contains a prop, which in Vue.js is a way to pass data down from a parent component to a child component. The template section then renders this data. For more on single-file components, check out the How To Create Reusable Blocks of Code with Vue Single-File Components tutorial.

      You may notice that there is some CSS included in the code snippet. In the AirportCard.vue component, the wrapper <div> contains the class of airport. This CSS adds some styling to the generated HTML by adding borders to give each airport the appearance of a card. :first-child and :last-child are pseudo-selectors that apply different styling to the first and last p tags in the HTML inside of the div with the class of airport.

      Save the file and exit from your text editor.

      Next, modify the existing App.vue component to iterate through the airports.js data and render a series of AirportCards.vue components. Open src/App.vue in your text editor and replace the contents with the following highlighted code:

      favorite-airports/src/App.vue

      <template>
        <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" />
          </div>
        </div>
      </template>
      
      <script>
      import { ref } from 'vue'
      import allAirports from '@/data/airports.js'
      import AirportCard from '@/components/AirportCard.vue'
      
      export default {
        components: {
          AirportCard
        },
        setup() {
          const airports = ref(allAirports)
          return { airports }
        }
      }
      </script>
      
      <style>
      #app {
        font-family: Avenir, Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
      }
      
      .wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-column-gap: 1rem;
        max-width: 960px;
        margin: 0 auto;
      }
      </style>
      

      This imports the data and the SFC, then uses the v-for directive to iterate over the data, creating an airport card for each object in the airport.js array. It also adds additional CSS targeted to the wrapper class, which uses CSS grid to manage the layout of the cards.

      Save and exit the file. With the project now set up, run a local development server with the following command:

      This will start a server on your localhost, usually on port :8080. Open your web browser of choice and visit localhost:8080 to find the following:

      A view of the airport data rendered on cards, with the airport abbreviation, full name, and location rendered in black, sans-serif font.

      Now that you have your sample project set up, you’ll next explore built-in events using the v-on directive. When this event is fired, an alert pop-up box will appear with the airport code of the airport associated with that event.

      Step 2 — Listening for Events With the v-on Directive

      As stated earlier, events are a way to execute functions when the user interacts with HTML elements in the DOM (Document Object Model). When writing vanilla JavaScript, to execute a function on an event, you may write something called an event listener. An event listener is a function that waits for that interaction to occur, then executes some code. With Vue, however, you can use the v-on directive for this purpose. A directive is a piece of re-useable code that a developer can use in order to manipulate the DOM. The v-on directive is provided by Vue.js out of the box.

      In this step, you will create a function in your application that runs when a user clicks on a card. Open the src/components/AirportCard.vue component in your text editor of choice.

      Create a function that alerts the user of the airport that they clicked on by adding the following highlighted code:

      favorite-airports/src/components/AirportCard.vue

      ...
      <script>
      export default {
        props: {
          airport: {
            type: Object,
            required: true
          }
        },
        setup() {
          function selectAirport(airport) {
            alert(`You clicked on ${airport.abbreviation}. It's located in ${airport.city}, ${airport.state}.`)
          }
      
          return { selectAirport }
        }
      }
      </script>
      ...
      

      In Vue.js 3, reactive functions need to be defined and exported in the setup component method. This tells Vue that it can execute the selectAirport function in the <template>.

      With the function defined, you’ll now attach it to an event on an HTML element. As stated before, you can use the v-on directive and attach an event with the name of click; this is an event provided by Vue.js. In the AirportCard.vue component, add the v-on directive to the wrapper <div>:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" v-on:click="selectAirport(airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      ...
      

      Once you have added this code, save and exit the file.

      Now, when you click on a card, an alert will pop-up with the message provided. If you click on CVG for example, you will find the following:

      Vue site with alert pop-up that reads "localhost:8080 says You clicked on CVG. It's located in Hebron, KY."

      The click event is not the only event that is provided to you out-of-the-box by Vue.js. In fact, you can use v-on any native JavaScript event, like:

      • keyup
      • mouseover
      • focus
      • mouseenter
      • change

      Next, you will change this v-on:click listener to mouseover to illustrate how Vue.js listens for events. mouseover is an event that fires whenever a mouse cursor moves over an HTML element.

      Open up src/components/AirportCard.vue again and update your file with the following highlighted code:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" @mouseover="selectAirport(airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      

      As shown here, Vue also has shorthand syntax for v-on: events. To use the shorthand syntax, you replaced v-on with @. Save and exit the file.

      Now when you visit localhost:8080 and hover over a card, that function will execute and display a native alert.

      This functionality is good for testing purposes, but may be undesired since it displays the alert every time a user hovers over it. A better experience might be to only display it the first time a user hovers over that card. In vanilla JavaScript, you may track the amount of times a user hovers over a card, then prevent further executions. Vue.js has event modifiers that you can leverage to accomplish the same thing with less code.

      In the next section, you are going to explore event modifiers and use them for a better user experience.

      Step 3 — Using Event and Key Modifiers

      In the previous section, you executed a function on the click and mouseover events. You also learned about the Vue.js shorthand for v-on events. Now you will expand on this further by attaching a modifier to this mouseover event so your function executes only once.

      Vue.js provides a number of event modifiers for you. Some of these include:

      • .stop: stops event propagation
      • .prevent: prevents the HTML element’s default behavior
      • .capture: handles an event targeting an inner element before the selected element
      • .self: only triggers the handler if event.target is the element itself
      • .once: only executes the function once
      • .passive: enables the element’s default behavior to happen immediately instead of waiting for the event, which can be used for optimizing performance for scroll on mobile devices

      In this case, you’ll use the .once modifier. In your text editor, open the AirportCard.vue component and add the modifier to the existing mouseover event:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" @mouseover.once="selectAirport(airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      

      Save the file. Visit your application in the browser and you’ll find that the event only fires once on the first mouseover event.

      Next, you’ll continue exploring modifiers by using key modifiers. These key modifiers are associated with keystroke events, such as keyup. For this next part, imagine that you want to make this clicking action a little more explicit. One way you can do that is by adding a key modifier to the @click event on the .airport <div> in your template.

      To do that, change the @mouseover to @click and add the .shift modifier:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" @click.shift="selectAirport(airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      

      Save the changes and open the application in your browser. If you click on a card without holding the SHIFT key, the alert does nothing. Now, try holding down the SHIFT key when clicking on a card. Your function will now execute, and you will receive an alert.

      In this section, you learned about Vue’s built-in events and the modifiers associated with those events. You can get a lot done with these built-in events, but there will be times when you’ll need to have a custom event. In the next section, you’re going to use custom events to emit an action up to a parent so that it will execute a function.

      Step 4 — Creating Custom Events

      When developing applications in Vue.js, there will be times when you need to pass data up to a parent component via a custom event. Props are read-only data that are passed down to a child from the parent, but a custom action via an $emit is the opposite of that. To create the most reusable components, it’s best to think of these as functions. You pass data down through props (arguments), and emit values back up to the parent (a return value).

      To emit an event from the child component to the parent, you use the $emit function. Before implementing this, this tutorial will guide you through an example to demonstrate how this works.

      The $emit function accepts two arguments: the action name (a string), and the value to pass up to the parent. In the following example, when the user clicks on the button, you are sending the value CVG to the parent component under the action favoriteAirport:

      ChildComponent.vue

      <template>
        <button @click="$emit('favoriteAirport', 'CVG')">A button</button>
      </template>
      

      In the parent component, you would use the v-on directive and listen for the favoriteAirport event. When this custom event is fired, the code will do something with the value:

      ParentComponent.vue

      <template>
        <child-component @favoriteAirport="favoriteAirport = $event" />
      </template>
      
      <script>
      import { ref } from 'vue'
      export default {
        setup() {
          const favoriteAirport = ref('')
      
          return { favoriteAirport }
        }
      }
      </script>
      

      The value of the event will be $event. In this case, $event is actually CVG, which you then store in a reactive data property called favoriteAirport.

      Now that you know what a custom event looks like, you will put it into practice by implementing this custom event into your application.

      Open the AirportCards.vue component in your text editor. In the @click event, remove the reference to the function and replace it with $emit("favoriteAirport", airport). Remember, the first arugment is the name of the event and the second is the value that you are emitting:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" @click="$emit('favoriteAirport', airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      ...
      

      Save the file. Now, when the user clicks on the airport card, a custom event will fire and pass up that airport object.

      Next, open src/App.vue to add some HTML to the template. You will show the favorite airports list after the six cards that are already present:

      favorite-airports/src/App.vue

      <template>
        <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" />
          </div>
          <h1 v-if="favoriteAirports.length">Favorite Airports</h1>
          <div v-for="airport in favoriteAirports" :key="airport.abbreviation">
            <airport-card :airport="airport" />
         </div>
        </div>
      </template>
      
      <script>
      import { ref } from 'vue'
      import allAirports from '@/data/airports.js'
      import AirportCard from '@/components/AirportCard.vue'
      
      export default {
        components: {
          AirportCard
        },
        setup() {
          const airports = ref(allAirports)
          const favoriteAirports = ref([])
      
          return { airports, favoriteAirports }
        }
      }
      </script>
      ...
      

      In this code snippet, you are creating a reactive data property called favoriteAirports, which is an empty array. In the <template>, you iterate through the empty array to render the <airport-card /> components, much like you did in an earlier step.

      Now you need to add the v-on event for your custom event:

      favorite-airports/src/App.vue

      <template>
        <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" @favoriteAirport="favoriteAirports.push($event)" />
          </div>
          <h1 v-if="favoriteAirports.length">Favorite Airports</h1>
          <div v-for="airport in favoriteAirports" :key="airport.abbreviation">
            <airport-card :airport="airport" />
         </div>
        </div>
      </template>
      ...
      

      In the @favoriteAiport custom event, you used the JavaScript push() method to add the airport from the child ($event) to the favoriteAirports reactive data property.

      Open you browser and navigate to your project at localhost:8080. When you click on one of the airport cards, that card will appear under Favorite Airports.

      Vue airport app with a list of favorite airports that includes the CVG airport card.

      In this section, you learned about custom events, what they are, and how to use them. A custom event is a way to pass data up to a parent component through the $emit function provided by Vue. Once that data has been emitted, you can further manipulate it in the parent component, like adding it to an array.

      Conclusion

      In this tutorial, you learned how Vue.js listens for a number of built-in events, such as click and mouseover. In addition to that, you tried out event and key modifiers, small pieces of code that you appended to your event to provide additional functionality. With this, you set up your app to execute the function once with the .once modifier and to only fire when holding down the SHIFT key using the .shift modifier.

      Vue provides an efficient way to listen for events that lets you focus on manipulating data over manually setting up event listeners. In addition to that, Vue allows you to think of components as functions: They accept data props and can return a value with $emit.

      To learn more about Vue components, it is recommended to read through the Vue documentation. For more tutorials on Vue, check out the How To Develop Websites with Vue.js series page.



      Source link

      How To Handle DOM and Window Events with React


      The author selected Creative Commons to receive a donation as part of the Write for DOnations program.

      Introduction

      In web development, events represent actions that happen in the web browser. By responding to events with event handlers, you can create dynamic JavaScript applications that respond to any user action, including clicking with a mouse, scrolling along a webpage, touching a touch screen, and more.

      In React apps, you can use event handlers to update state data, trigger prop changes, or prevent default browser actions. To do this, React uses a SyntheticEvent wrapper instead of the native Event interface. SyntheticEvent closely emulates the standard browser event, but provides more consistent behavior for different web browsers. React also gives you tools to safely add and remove a Window event listener when a component mounts and unmounts from the Document Object Model (DOM), giving you control over Window events while preventing memory leaks from improperly removed listeners.

      In this tutorial, you’ll learn how to handle events in React. You’ll build several sample components that handle user events, including a self-validating input component and an informative tooltip for the input form. Throughout the tutorial, you’ll learn how to add event handlers to components, pull information from the SyntheticEvent, and add and remove Window event listeners. By the end of this tutorial, you’ll be able to work with a variety of event handlers and apply the catalog of events supported by React.

      Prerequisites

      In this step, you’ll create a validating component using an <input> HTML element and the onChange event handler. This component will accept input and validate it, or make sure that the content adheres to a specific text pattern. You’ll use the SyntheticEvent wrapper to pass event data into the callback function and update the component using the data from the <input>. You will also call functions from the SyntheticEvent, such as preventDefault to prevent standard browser actions.

      In React, you don’t need to select elements before adding event listeners. Instead, you add event handlers directly to your JSX using props. There are a large number of supported events in React, including common events such as onClick or onChange and less common events such as onWheel.

      Unlike native DOM onevent handlers, React passes a special wrapper called SyntheticEvent to the event handler rather than the native browser Event. The abstraction helps reduce cross-browser inconsistencies and gives your components a standard interface for working with events. The API for SyntheticEvent is similar to the native Event, so most tasks are accomplished in the same manner.

      To demonstrate this, you will start by making your validating input. First, you will create a component called FileNamer. This will be a <form> element with an input for naming a file. As you fill in the input, you’ll see the information update a preview box above the component. The component will also include a submit button to run the validation, but for this example the form will not actually submit anything.

      First, create the directory:

      • mkdir src/components/FileNamer

      Then open FileNamer.js in your text editor:

      • nano src/components/FileNamer/FileNamer.js

      Inside FileNamer.js, create a wrapper <div>, then add another <div> with a class name of preview and a <form> element inside the wrapper by writing the following lines of code:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React from 'react';
      
      export default function FileNamer() {
        return(
          <div className="wrapper">
            <div className="preview">
            </div>
            <form>
            </form>
          </div>
        )
      }
      

      Next, add an input element for the name to display in the preview box and a Save button. Add the following highlighted lines:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React from 'react';
      
      export default function FileNamer() {
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview:</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input name="name" />
              </label>
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      In the preview <div>, you added an <h2> element with the text Preview. This will be your preview box. Inside your form, you added an <input> surrounded by a <label> element with Name: as its text. Then you added a button called Save directly before the closing <form> tag.

      Save and close the file.

      Next, open App.js:

      • nano src/components/App/App.js

      Import FileNamer, then render inside the App function by adding the following highlighted lines:

      events-tutorial/src/components/App/App.js

      import React from 'react';
      import FileNamer from '../FileNamer/FileNamer';
      
      function App() {
          return <FileNamer />
      }
      
      export default App;
      

      Save and close the file. When you do the browser will refresh and you’ll see your component.

      Name element

      Next, add some light styling to help define the sections and to add some padding and margins to the elements.

      Open FileNamer.css in your text editor:

      • nano src/components/FileNamer/FileNamer.css

      Give the .preview class a gray border and padding, then give the .wrapper class a small amount of padding. Display the items in a column using flex and flex-direction, and make all the text align left. Finally, remove the default button styles by removing the border and adding a black border:

      events-tutorial/src/components/FileNamer/FileNamer.css

      .preview {
          border: 1px darkgray solid;
          padding: 10px;
      }
      
      .wrapper {
          display: flex;
          flex-direction: column;
          padding: 20px;
          text-align: left;
      }
      
      .wrapper button {
          background: none;
          border: 1px black solid;
          margin-top: 10px;
      }
      

      Save and close the file. Then open FileNamer.js:

      • nano src/components/FileNamer/FileNamer.js

      Import the styles to apply them to your component:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview:</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input name="name" />
              </label>
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      Save the file. When you do, the browser will refresh and you’ll find the component has the new styles.

      Styled component

      Now that you have a basic component, you can add event handlers to the <input> element. But first, you’ll need a place to store the data in the input field. Add the useState Hook to hold the input:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input name="name" />
              </label>
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      In this code, you destructured useState into a variable name to hold the input and a function called setName to update the data. Then you displayed the name in the preview section followed by the .js extension, as if the user were naming a file.

      Now that you can store the input data, you can add an event handler to the <input> component. There are often several different event handlers you can use for a given task. In this case, your app needs to capture the data the user types into the element. The most common handler for this situation is onChange, which fires every time the component changes. However, you could also use keyboard events, such as onKeyDown, onKeyPress, and onKeyUp. The difference primarily has to do with when the event fires and the information passed to the SyntheticEvent object. For example, onBlur, an event for when an element becomes unfocused, fires before onClick. If you want to handle user information before another event fires, you can pick an earlier event.

      Your choice of event is also determined by the type of data you want to pass to the SyntheticEvent. The onKeyPress event, for example, will include the charCode of the key that the user pressed, while onChange will not include the specific character code, but will include the full input. This is important if you want to perform different actions depending on which key the user pressed.

      For this tutorial, use onChange to capture the entire input value and not just the most recent key. This will save you the effort of storing and concatenating the value on every change.

      Create a function that takes the event as an argument and pass it to the <input> element using the onChange prop:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input name="name" onChange={event => {}}/>
              </label>
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      As mentioned earlier, the event here is not the native browser event. It’s the SyntheticEvent provided by React, which is often treated the same. In the rare case you need the native event, you can use the nativeEvent attribute on the SyntheticEvent.

      Now that you have the event, pull out the current value from the target.value property of the event. Pass the value to setName to update the preview:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                 autoComplete="off"
                 name="name"
                 onChange={event => setName(event.target.value) }
               />
              </label>
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      In addition, you set the attribute autoComplete to "off" to turn off browser suggestions.

      Save the file. When you do, the page will reload, and when you type in the <input> you’ll see an update in the preview.

      Typing into the input element

      Note: You could also access the name of the input using event.target.name. This would be useful if you were using the same event handler across multiple inputs, since the name would automatically match the name attribute of the component.

      At this point, you have a working event handler. You are taking the user information, saving it to state, and updating another component with the data. But in addition to pulling information from an event, there are situations where you’ll need to halt an event, such as if you wanted to prevent a form submission or prevent a keypress action.

      To stop an event, call the preventDefault action on the event. This will stop the browser from performing the default behavior.

      In the case of the FileNamer component, there are certain characters that could break the process of choosing a file that your app should forbid. For example, you wouldn’t want a user to add a * to a filename since it conflicts with the wildcard character, which could be interpreted to refer to a different set of files. Before a user can submit the form, you’ll want to check to make sure there are no invalid characters. If there is an invalid character, you’ll stop the browser from submitting the form and display a message for the user.

      First, create a Hook that will generate an alert boolean and a setAlert function. Then add a <div> to display the message if alert is true:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
      
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autoComplete="off"
                  name="name"
                  onChange={event => setName(event.target.value) }
                />
              </label>
              {alert && <div> Forbidden Character: *</div>}
              <div>
                <button>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      In this code, you used the && operator to only show the new <div> if alert is set equal to true first. The message in the <div> will tell the user that the * character is not allowed in the input.

      Next, create a function called validate. Use the regular expression .test method to find out if the string contains a *. If it does, you will prevent the form submission:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
        const validate = event => {
          if(/*/.test(name)) {
            event.preventDefault();
            setAlert(true);
            return;
          }
            setAlert(false);
       };
      
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autoComplete="off"
                  name="name"
                  onChange={event => setName(event.target.value) }
                />
              </label>
              {alert && <div> Forbidden Character: *</div>}
              <div>
                <button onClick={validate}>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      When the validate function is called and the test returns true, it will use event.preventDefault then call setAlert(true). Otherwise, it will call setAlert(false). In the last part of the code, you added the event handler to the <button> element with onClick.

      Save the file. As before, you could have also used onMouseDown, but onClick is more common and thus allows you to avoid any unexpected side effects. This form doesn’t have any submit actions, but by preventing the default action, you prevent the page from reloading:

      Prevent Default and trigger a warning

      Now you have a form that uses two event handlers: onChange and onClick. You are using the event handlers to connect user actions to the component and the application, making it interactive. In doing so, you learned to add events to DOM elements, and how there are several events that fire on the same action, but that provide different information in the SyntheticEvent. You also learned how to extract information from the SyntheticEvent, update other components by saving that data to state, and halt an event using preventDefault.

      In the next step, you’ll add multiple events to a single DOM element to handle a variety of user actions.

      Step 2 — Adding Multiple Event Handlers to the Same Element

      There are situations when a single component will fire multiple events, and you’ll need to be able to connect to the different events on a single component. For example, in this step you’ll use the onFocus and onBlur event handlers to give the user just-in-time information about the component. By the end of this step, you’ll know more about the different supported events in React and how to add them to your components.

      The validate function is helpful for preventing your form from submitting bad data, but it’s not very helpful for user experience: The user only receives information about the valid characters after they’ve filled out the entire form. If there were multiple fields, it wouldn’t give the user any feedback until the last step. To make this component more user friendly, display the allowed and disallowed characters when the user enters the field by adding an onFocus event handler.

      First, update the alert <div> to include information about what characters are allowed. Tell the user alphanumeric characters are allowed and the * is not allowed:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
      ...
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autocomplete="off"
                  name="name"
                  onChange={event => setName(event.target.value) }
                />
              </label>
              {alert &&
               <div>
                 <span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
                 <br />
                 <span role="img" aria-label="not allowed">⛔️</span> *
               </div>
             }
              <div>
                <button onClick={validate}>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      In this code, you used Accessible Rich Internet Applications (ARIA) standards to make the component more accessible to screen readers.

      Next, add another event handler to the <input> element. You will alert the user about the allowed and disallowed characters when they activate the component by either clicking or tabbing into the input. Add in the following highlighted line:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
      ...
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autocomplete="off"
                  name="name"
                  onChange={event => setName(event.target.value) }
                  onFocus={() => setAlert(true)}
                />
              </label>
              {alert &&
                <div>
                  <span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
                  <br />
                  <span role="img" aria-label="not allowed">⛔️</span> *
                </div>
              }
              <div>
                <button onClick={validate}>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      You added the onFocus event handler to the <input> element. This event triggers when the user selects the field. After adding the event handler, you passed an anonymous function to onFocus that will call setAlert(true) and display the data. In this case, you don’t need any information from the SyntheticEvent; you only need to trigger an event when the user acts. React is still sending the SyntheticEvent to the function, but in the current situation you don’t need to use the information in it.

      Note: You could trigger the data display with onClick or even onMouseDown, but that wouldn’t be accessible for users that use the keyboard to tab into the form fields. In this case, the onFocus event will handle both cases.

      Save the file. When you do, the browser will refresh and the information will remain hidden until the user clicks on the input.

      Trigger the event when clicking on the input

      The user information now appears when the field is focused, but now the data is present for the duration of the component. There’s no way to make it go away. Fortunately, there’s another event called onBlur that fires when the user leaves an input. Add the onBlur event handler with an anonymous function that will set the alert to false. Like onFocus, this will work both when a user clicks away or when a user tabs away:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
      ...
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autocomplete="off"
                  name="name"
                  onBlur={() => setAlert(false)}
                  onChange={event => setName(event.target.value) }
                  onFocus={() => setAlert(true)}
                />
              </label>
              {alert &&
                <div>
                  <span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
                  <br />
                  <span role="img" aria-label="not allowed">⛔️</span> *
                </div>
              }
              <div>
                <button onClick={validate}>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      Save the file. When you do, the browser will refresh and the information will display when the user clicks on the element and disappear when the user clicks away:

      Show information on focus and hide on blur

      You can add as many event handlers as you need to an element. If you have an idea of an event you need, but aren’t sure of the name, scroll through the supported events and you may find what you need.

      In this step you added multiple event handlers to a single DOM element. You learned how different event handlers can handle a broad range of events—such as both click and tab—or a narrow range of events.

      In the next step, you’ll add global event listeners to the Window object to capture events that occur outside the immediate component.

      Step 3 — Adding Window Events

      In this step, you’ll put the user information in a pop-up component that will activate when the user focuses an input and will close when the user clicks anywhere else on the page. To achieve this effect, you’ll add a global event listener to the Window object using the useEffect Hook. You’ll also remove the event listener when the component unmounts to prevent memory leaks, when your app take up more memory than it needs to.

      By the end of this step, you’ll be able to safely add and remove event listeners on individual components. You’ll also learn how to use the useEffect Hook to perform actions when a component mounts and unmounts.

      In most cases, you’ll add event handlers directly to DOM elements in your JSX. This keeps your code focused and prevents confusing situations where a component is controlling another component’s behavior through the Window object. But there are times in which you’ll need to add global event listeners. For example, you may want a scroll listener to load new content, or you may want to capture click events outside of a component.

      In this tutorial, you only want to show the user the information about the input if they specifically ask for it. After you display the information, you’ll want to hide it whenever the user clicks the page outside the component.

      To start, move the alert display into a new <div> with a className of information-wrapper. Then add a new button with a className of information and an onClick event that will call setAlert(true):

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
      ...
        return(
          <div className="wrapper">
            <div className="preview">
              <h2>Preview: {name}.js</h2>
            </div>
            <form>
              <label>
                <p>Name:</p>
                <input
                  autocomplete="off"
                  name="name"
                  onChange={event => setName(event.target.value) }
                />
              </label>
              <div className="information-wrapper">
                <button
                  className="information"
                  onClick={() => setAlert(true)}
                  type="button"
                >
                  more information
                </button>
               {alert &&
                 <div className="popup">
                   <span role="img" aria-label="allowed">✅</span> Alphanumeric Characters
                   <br />
                   <span role="img" aria-label="not allowed">⛔️</span> *
                 </div>
               }
              </div>
              <div>
                <button onClick={validate}>Save</button>
              </div>
            </form>
          </div>
        )
      }
      

      You also removed the onFocus and onBlur handlers from the <input> element to remove the behavior from the last step.

      Save and close the file. Then open FileNamer.css:

      • nano src/components/FileNamer/FileNamer.css

      Add some styling to absolutely position the popup information above the button. Then change the <button> with a class of information to be blue with no border.

      events-tutorial/src/components/FileNamer/FileNamer.css

      
      .information {
         font-size: .75em;
         color: blue;
         cursor: pointer;
      }
      
      .wrapper button.information {
          border: none;
      }
      
      .information-wrapper {
         position: relative;
      }
      
      .popup {
          position: absolute;
          background: white;
          border: 1px darkgray solid;
          padding: 10px;
          top: -70px;
          left: 0;
      }
      
      .preview {
          border: 1px darkgray solid;
          padding: 10px;
      }
      
      .wrapper {
          display: flex;
          flex-direction: column;
          padding: 20px;
          text-align: left;
      }
      
      .wrapper button {
          background: none;
          border: 1px black solid;
          margin-top: 10px;
      }
      

      Save and close the file. When you do, the browser will reload, and when you click on more information, the information about the component will appear:

      Trigger information pop-up

      Now you can trigger the pop-up, but there’s no way to clear it. To fix that problem, add a global event listener that calls setAlert(false) on any click outside of the pop-up.

      The event listener would look something like this:

      window.addEventListener('click', () => setAlert(false))
      

      However, you have to be mindful about when you set the event listener in your code. You can’t, for example, add an event listener at the top of your component code, because then every time something changed, the component would re-render and add a new event listener. Since your component will likely re-render many times, that would create a lot of unused event listeners that take up memory.

      To solve this, React has a special Hook called useEffect that will run only when specific properties change. The basic structure is this:

      useEffect(() => {
       // run code when anything in the array changes
      }, [someProp, someOtherProp])
      

      In the simplified example, React will run the code in the anonymous function whenever someProp or someOtherProp changes. The items in the array are called dependencies. This Hook listens for changes to the dependencies and then runs the function after the change.

      Now you have the tools to add and remove a global event listener safely by using useEffect to add the event listener whenever alert is true and remove it whenever alert is false.

      There is one more step. When the component unmounts, it will run any function that you return from inside of your useEffect Hook. Because of this, you’ll also need to return a function that removes the event listener when the component unmounts.

      The basic structure would be like this:

      useEffect(() => {
       // run code when anything in the array changes
        return () => {} // run code when the component unmounts
      }, [someProp, someOtherProp])
      

      Now that you know the shape of your useEffect Hook, use it in your application. Open up FileNamer.js:

      • nano src/components/FileNamer/FileNamer.js

      Inside, import useEffect, then add an empty anonymous function with a dependency of alert and setAlert in the array after the function:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useEffect, useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
      
        useEffect(() => {
        }, [alert, setAlert]);
      ...
      

      In this code, you added both alert and setAlert. To be complete, React recommends you add all external dependencies to the useEffect function. Since you will be calling the setAlert function, it can be considered a dependency. setAlert will not change after the first render, but it’s a good practice to include anything that could be considered a dependency.

      Next, inside the anonymous function, create a new function called handleWindowClick that calls setAlert(false):

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useEffect, useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
      
        useEffect(() => {
          const handleWindowClick = () => setAlert(false)
        }, [alert, setAlert]);
        ...
      }
      

      Then add a conditional that will call window.addEventListener('click', handleWindowClick) when alert is true and will call window.removeEventListener('click', handleWindowClick) when alert is false. This will add the event listener every time you trigger the pop-up and remove it everytime the pop-up is closed:

      events-tutorial/src/components/FileNamer/FileNamer.js

      import React, { useEffect, useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
      
        useEffect(() => {
          const handleWindowClick = () => setAlert(false)
          if(alert) {
            window.addEventListener('click', handleWindowClick);
          } else {
            window.removeEventListener('click', handleWindowClick);
          }
        }, [alert, setAlert]);
        ...
      }
      

      Finally, return a function that will remove the event listener. Once again, this will run when the component unmounts. There may not be a live event listener, but it’s still worth cleaning up in situations where the listener still exists:

      events-tutorial/src/components/FileNamer/FileNamer.js

      
      import React, { useEffect, useState } from 'react';
      import './FileNamer.css';
      
      export default function FileNamer() {
        const [name, setName] = useState('');
        const [alert, setAlert] = useState(false);
      
        useEffect(() => {
          const handleWindowClick = () => setAlert(false)
          if(alert) {
            window.addEventListener('click', handleWindowClick);
          } else {
            window.removeEventListener('click', handleWindowClick)
          }
          return () => window.removeEventListener('click', handleWindowClick);
        }, [alert, setAlert]);
        ...
      }
      

      Save the file. When you do, the browser will refresh. If you click on the more information button, the message will appear. If you look at the global event listeners in the developer tools, you’ll see there is a click listener:

      Click event listener

      Click anywhere outside the component. The message will disappear and you’ll no longer see the global click event listener.

      No click event listener

      Your useEffect Hook successfully added and removed a global event listener based on a user interaction. It wasn’t tied to a specific DOM element, but was instead triggered by a change in the component state.

      Note: From an accessibility standpoint, this component is not complete. If a user is not able to use the mouse, they will be stuck with an open pop-up because they would never be able to click outside the component. The solution would be to add another event listener for keydown that would also remove the message. The code would be nearly identical except the method would be keydown instead of click.

      In this step you added global event listeners inside a component. You also learned how to use the useEffect Hook to properly add and remove the event listener as the state changes and how to clean up event listeners when the component unmounts.

      Conclusion

      Event handlers give you the opportunity to align your components with user actions. These will give your applications a rich experience and will increase the interactive possibilities of your app. They will also give you the ability to capture and respond to user actions.

      React’s event handlers let you keep your event callbacks integrated with the HTML so that you can share functionality and design across an application. In most cases, you should focus on adding event handlers directly to DOM elements, but in situations where you need to capture events outside of the component, you can add event listeners and clean them up when they are no longer in use to prevent memory leaks and create performative applications.

      If you would like to look at more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page. To learn more about events in JavaScript, read our Understanding Events in JavaScript and Using Event Emitters in Node.js tutorials.



      Source link

      What Are the Cloud Manager Events and Activity Feeds


      Updated by Linode

      Written by Linode

      Tasks performed using the Linode Cloud Manager or other account specific tools like Linode’s CLI or API will be logged to an individual Linode’s activity feed, or on your account’s Events Page. The events and activity pages are user accessible logs, or histories of events taking place on your account. They contain details regarding the most notable events affecting your Linodes, like reboots, shutdowns, migrations, and more.

      In This Guide

      Note

      The Events Page will be limited to information tied into User Permissions as set for each individual user on an account. For more information, see our Accounts and Passwords guide.

      Event’s Page

      Your account’s Events Page is a history, or a log, of all activity pertaining to your Linode Account. This includes changes to all billable resources, domains using our DNS Manager, StackScripts, and other events that take place affecting your account, like opening a new support ticket.

      1. The Events Page can be found by logging into the Cloud Manager and selecting the bell icon at the top right of the page. This will list the most recent events on your account. Each event will contain a brief descriptor of the event, a rounded amount of time to give you an idea of how long ago it occurred, and in some cases will show the user who initiated the event.

        https://www.linode.com/cloud-manager-event.png

      2. To view more events and additional details pertaining to them, select View All Events at the bottom of the list.

      3. The following page will list all events attributed to your account, including a description, the duration of the event, and the time that the event was initiated down to the exact second in Coordinated Universal Time (UTC). The list of events contains the entire history for the life of your account. It will continue to populate with past entries as you scroll down the page. When there are no entries left to display, you’ll see the text “No more events to show” at the bottom of the page.

        https://www.linode.com/events.png

      Linode Activity Feed

      The Linode Activity Feed is similar to your Account’s Events Page. However, this is a filtered list only relevant to the specific Linode you’re observing.

      1. To access a Linode’s Activity Feed, first log into the Linode Cloud Manager and select Linodes from the sidebar menu, and click on the Linode you’d like to observe events for.

      2. On the Summary page you will see a brief Activity feed. Additionally, you can click on the View More Activity link to see a list of all of your Linode’s activity in more detail. (You can also access this page by clicking on the Activity tab).

      3. On the Activity Feed page, you’ll see a list of events including the Event description, the duration of the event, and when the event was initiated in Coordinated Universal Time (UTC). In this case, you can see that the most recent event was a reboot that took 25 seconds to complete.

        cloud manager events

      4. The list of events will contain the entire history of the life of your Linode and will continue to populate with past entries as you scroll down the page. When there are no entries left, you’ll see the text “No more events to show” at the bottom of the page.

      This guide is published under a CC BY-ND 4.0 license.



      Source link