Categories
JavaScript React

Basic React Hooks – useContext and useReducer

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at the useContext and useReducer hooks.

useContext

We can use the useContext hook to read shared data shared from a React context. It accepts the context object returned from React.createContext as an argument and returns the current context value.

The current context value is determined by the value prop of the nearest context provider.

We can use it as follows:

const ColorContext = React.createContext("green");function Button() {  
  const color = React.useContext(ColorContext);  
  return <button style={{ color }}>button</button>;  
}function App() {  
  return (  
    <>  
      <ColorContext.Provider value="blue">  
        <Button />  
      </ColorContext.Provider>  
    </>  
  );  
}

In the code above, we created a new React context with:

const ColorContext = React.createContext("green");

Then in App , we wrapped out Button with the ColorContext.Provider with the value prop set to blue .

Then in Button , we have:

const color = React.useContext(ColorContext);

to get the value passed in from the ColorContext.Provider and set it to color .

Finally, we set the color style of the button with the color ‘s value.

A component calling useContext will always re-render when the context value changes. If re-rendering is expensive, then we can optimize it with memoization.

useContext is the React hooks version of Context.Consumer .

useReducer

This hook is an alternative to useState . It accepts a reducer function of type (state, action) => newState .

useReducer is preferable to useState when we have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

It also lets us optimize performance for components that trigger deep updates because we can pass dispatch down instead of callbacks.

For example, we can write:

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}

function App() {  
  const [state, dispatch] = React.useReducer(reducer, { count: 0 });  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

In the code above, we have our reducer which returns the new state depends on the action.type ‘s value. In this case, it’s either 'INCREMENT' or 'DECREMENT' .

If it’s ‘INCREMENT’ , we return { count: state.count + 1 } .

If it’s ‘DECREMENT’ , we return { count: state.count — 1 } .

Otherwise, we throw an error.

Then in App , we call useReducer by passing in a reducer as the first argument and the initial state as the second argument.

Then we get the state object, which has the current state object and a dispatch function, which we can call with an action object, which has the type property with the value being one of ‘INCREMENT’ or ‘DECREMENT' .

We used the dispatch function in the buttons to update the state.

Finally, we display the latest state in state.count .

Lazy initialization

We can pass in a function to the 3rd argument of useReducer to initialize the state lazily.

The initial state will be set to init(initialArg) .

For instance, we can rewrite the previous example as follows:

const init = initialCount => {  
  return { count: initialCount };  
};

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";

function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}
function App() {  
  const [state, dispatch] = React.useReducer(reducer, 0, init);  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

First, we have:

const init = initialCount => {  
  return { count: initialCount };  
};

to return the initial state.

And instead of writing:

React.useReducer(reducer, { count: 0 });

We have:

React.useReducer(reducer, 0, init);

0 is passed in as the initialCount of init .

Then the rest of the code is the same as before.

Bailing out of a dispatch

If the same value is returned from a Reducer hook is the same as the current state, React will bail out without rendering the children or firing effects.

The comparison is done using the Object.is() algorithm.

If we’re doing expensive operations while rendering, we can optimize it with useMemo .

Conclusion

The useContext hook is the React hook equivalent of the Context.Consumer of the Context API.

It takes a React context object as the argument and returns the current value from the context.

useReducer is an alternative version of useState for more complex state changes.

It takes in a reducer as the first argument and the initial state object as the second argument.

It can also take the same first argument, and take the initial state value as the second argument, and a function to return the initial state as the 3rd argument. This combination lets React set the initial state lazily.

Categories
Angular JavaScript

Creating Web Components with Angular

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at how to create Angular Elements, which are packaged as Web Components.

Angular Elements

Web Components are supported by most browsers like Chrome, Firefox, Opera or Safari.

We can transform Angular components to Web Components to make all the Angular infrastructure available to the browser.

Features like data-binding and other Angular functionalities are mapped to their HTML equivalents.

Creating and Using Custom Elements

We can create a Web Component by creating an Angular component, then building it into a Web Component.

To create a Web Component with Angular, we have to do a few things.

First, we create a component to build into Web Components. Then we have to set the component we created as the entry point.

Then we can add it to the DOM.

We’ll make a custom component to get a joke. To do this, we first run:

ng g component customJoke  
ng g service joke

to create our component and service to get our joke and display it.

Then we run:

ng add @angular/element

to add the Angular Element files to create our Web Component.

Then injoke.service.ts , we add:

import { Injectable } from '@angular/core';

@Injectable({  
  providedIn: 'root'  
})  
export class JokeService { 
  constructor() { } 

  async getJokeById(id: number) {  
    const response = await fetch(`http://api.icndb.com/jokes/${id}`)  
    const joke = await response.json();  
    return joke;  
  }  
}

The code above gets a joke from the Chuck Norris API by ID.

Next, we write our component code as follows:

app.module.ts :

import { BrowserModule } from '@angular/platform-browser';  
import { NgModule, Injector } from '@angular/core';  
import { AppComponent } from './app.component';  
import { CustomJokeComponent } from './custom-joke/custom-joke.component';  
import { JokeService } from './joke.service';

@NgModule({  
  declarations: [  
    CustomJokeComponent,  
    AppComponent  
  ],  
  imports: [  
    BrowserModule,  
  ],  
  providers: [JokeService],  
  bootstrap: [AppComponent],  
  entryComponents: [CustomJokeComponent]  
})  
export class AppModule {}

In AppModule , we add CustomJokeComponent to entryComponents so that it’ll be the entry point component instead of AppComponent .

It’ll load when custom-joke element is created.

app.component.ts :

import { Component, Injector } from '@angular/core';  
import { createCustomElement, WithProperties, NgElement } from '@angular/elements';  
import { CustomJokeComponent } from './custom-joke/custom-joke.component';

@Component({  
  selector: 'app-root',  
  template: ''  
})  
export class AppComponent {  
  constructor(injector: Injector) {  
    const JokeElement = createCustomElement(CustomJokeComponent, { injector });  
    customElements.define('custom-joke', JokeElement);  
    this.showAsElement(20);  
  } 

  showAsElement(id: number) {  
    const jokeEl: WithProperties<CustomJokeComponent> = document.createElement('custom-joke') as any;  
    jokeEl.id = id;  
    document.body.appendChild(jokeEl as any);  
  }  
}

The code in the constructor creates the custom component and attaches it to the DOM with our showAsElement method.

createCustomElement is from our @angular/element code.

The showAsElement method loads our custom-joke Web Component that we defined earlier.

custom-joke.component.ts :

import { Component, OnInit, ViewEncapsulation, Input } from '@angular/core';  
import { JokeService } from '../joke.service';

@Component({  
  selector: 'custom-joke',  
  template: `<p>{{joke?.value?.joke}}</p>`,  
  styles: [`p { font-size: 20px }`],  
  encapsulation: ViewEncapsulation.Native  
})  
export class CustomJokeComponent implements OnInit {  
  @Input() id: number = 1;  
  joke: any = {}; 

  constructor(private jokeService: JokeService) { } 

  async ngOnInit() {  
    this.joke = await this.jokeService.getJokeById(this.id)  
  }}

We put everything in one file so they can all be included in our custom-joke Web Component.

The @Input will be converted to an attribute that we can pass a number into and get the joke by its ID.

We leave custom-joke.component.html and app.component.html blank.

Conclusion

We use the @angular/element package to create a Web Component that we can use.

The difference is that we include the template and styles inline.

Also, we have to register the component and attach it to the DOM.

Categories
JavaScript React

Basic Built-in React Hooks- useState and useEffect

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at some basic built-in React hooks, including useState and useEffect .

useState

The useState hook lets us manage the internal state of a function component. It takes an initial value as an argument and returns an array with the current state and a function to update it.

It returns the initial state when the component is initially rendered.

We can pass in a function to update the value if the new value is computed using the previous state.

For example, we can write the following to update the value based on a previous one:

function App() {  
  const [count, setCount] = React.useState(0);  
  return (  
    <>  
      Count: {count}  
      <button onClick={() => setCount(0)}>Reset</button>  
      <button onClick={() => setCount(prevCount => prevCount - 1)}>  
        Decrement  
      </button>  
      <button onClick={() => setCount(prevCount => prevCount + 1)}>  
        Increment  
      </button>  
    </>  
  );  
}

In the code above, we have:

setCount(prevCount => prevCount - 1)}

and:

setCount(prevCount => prevCount + 1)}

which decrements the count and increment it respectively by passing in functions that take the previous count as the parameter and return the new count.

Otherwise, we can just pass in the new value to the state update function as we did in:

setCount(0)

useState doesn’t automatically merge update objects. We can replicate this behavior with the spread syntax:

function App() {  
  const [nums, setNums] = React.useState({});  
  return (  
    <>  
      <p>{Object.keys(nums).join(",")}</p>  
      <button  
        onClick={() =>  
          setNums(oldNums => {  
            const randomObj = { [Math.random()]: Math.random() };  
            return { ...oldNums, ...randomObj };  
          })  
        }  
      >  
        Click Me  
      </button>  
    </>  
  );  
}

In the code above, we have:

setNums(oldNums => {  
            const randomObj = { [Math.random()]: Math.random() };  
            return { ...oldNums, ...randomObj };  
          })

to create a randomObj object with a random number as the key and value, and we merge that into another object with the old value then return it.

Then we display it with:

Object.keys(nums).join(",")

by getting the keys and joining them together.

Lazy initial state

We can pass in a function to useState if we want to delay the setting of the initial state.

It’ll be ignored after the initial render if we pass in a function.

This is useful if the initial state is computed from some expensive operation.

For example, we can write:

function App() {  
  const [count, setCount] = React.useState(() => 0);  
  return (  
    <>  
      Count: {count}  
      <button onClick={() => setCount(() => 0)}>Reset</button>  
      <button onClick={() => setCount(prevCount => prevCount - 1)}>  
        Decrement  
      </button>  
      <button onClick={() => setCount(prevCount => prevCount + 1)}>  
        Increment  
      </button>  
    </>  
  );  
}

In the code above, we have:

React.useState(() => 0)

which is a function that just returns 0.

We’ll see the same results as before.

Bailing out of a state update

If we update a state hook with the same value as the current. React will skip updating the state without rendering the children or firing effects.

React uses Object.is() to compare the current and new states, which is close to the === operator except that +0 and -0 are treated to be not equal and NaN is equal to itself.

React may still render before bailing out but it won’t go deeper into the tree if it finds that the old and new values are the same.

useEffect

We can use the useEffect hook to do various operations that aren’t allowed inside the main body of the function component, which is anything outside the rendering phase.

Therefore, we can use this to do any mutations, subscriptions, setting timers, and other side effects.

It takes a callback to run the code.

We can return a function inside to run any cleanup code after each render and also when the component unmounts.

The callback passed into useEffect fires after layout and paint, during a deferred event.

This makes this suitable for running operations that shouldn’t block the browser from updating the screen.

Code that must be run synchronously can be put into the callback of the useLayoutEffect hook instead, which is the synchronous version of useEffect .

It’s guaranteed to fire before any new renders. React will always flush the previous render’s effects before starting a new update.

Conditionally firing an effect

We can pass in a second argument to useEffect with an array of values that requires an effect to be run when they change.

For example, we can use it to get data from an API on initial render as follows:

function App() {  
  const [joke, setJoke] = React.useState({});  
  useEffect(() => {  
    (async () => {  
      const response = await fetch("https://api.icndb.com/jokes/random");  
      const res = await response.json();  
      console.log(res);  
      setJoke(res);  
    })();  
  }, []);  
  return (  
    <>  
      <p>{joke.value && joke.value.joke}</p>  
    </>  
  );  
}

Passing an empty array as the second argument will stop it from loading in subsequent renders.

We can pass in a value to the array to watch the value in the array change and then run the callback function:

function App() {  
  const [joke, setJoke] = React.useState({});  
  const [id, setId] = React.useState(1);  
  useEffect(() => {  
    (async () => {  
      const response = await fetch(`https://api.icndb.com/jokes/${id}`));  
      const res = await response.json();  
      console.log(res);  
      setJoke(res);  
    })();  
  }, [id]);  
  return (  
    <>  
      <button onClick={() => setId(Math.ceil(Math.random() * 100))}>  
        Random Joke  
      </button>  
      <p>{joke.value && joke.value.joke}</p>  
    </>  
  );  
}

In the code above, when we click the Random Joke button, setId is called with a new number between 1 and 100. Then id changes, which triggers the useEffect callback to run.

Then joke is set with a new value, then the new joke is displayed on the screen.

Conclusion

useState and useEffect are the most basic built-in React hooks.

useState lets us update the state by passing in a function which returns the initial state, or passing in the initial state directly.

It returns an array with the current state and a function to update the state. The state update function returned takes in a value or a function that has the previous value as the parameter and returns the new value if it depends on the previous value.

useEffect lets us run any side effect, mutation, or anything outside of the rendering phase.

It takes a callback with the code to run as the first argument, and an array with the values to watch for changes for before the callback is run.

If an empty array is passed in, then the callback only runs on initial render.

Categories
JavaScript React

Rendering Arrays in React Components

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to render lists in a React component.

Lists and Keys

We can transform lists into HTML by calling the array’s map method.

For example, if we want to display an array of numbers as a list, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    return (  
      <div>  
        {[1, 2, 3, 4, 5].map(num => (  
          <span>{num}</span>  
        ))}  
      </div>  
    );  
  }  
}

In the code above, we called map on the [1, 2, 3, 4, 5] array. In the map method’s callback, we returned a span with the number inside and we do the same for each element.

Then we get:

12345

displayed on the screen.

We can assign it to a variable and then pass it into the ReactDOM.render method as follows:

import React from "react";  
import ReactDOM from "react-dom";
const nums = [1, 2, 3, 4, 5].map(num => <span>{num}</span>);
const rootElement = document.getElementById("root");  
ReactDOM.render(nums, rootElement);

We’ll get the same items displayed.

Also, we can use the same code inside the render method:

import React from "react";  
import ReactDOM from "react-dom";

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    const nums = [1, 2, 3, 4, 5].map(num => <span>{num}</span>);  
    return <div>{nums}</div>;  
  }  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

Keys

When we render lists, we should provide a value for key prop for each rendered element so that React can identify which items have changed, added, or removed.

It gives elements a stable identity. We should pick a key by using a string that uniquely identifies a list item among its siblings.

A key should be a string value.

For example, if we want to render a list of to-do items, we should pick the id field as the key ‘s value as follows:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <p key={todo.id.toString()}>{todo.text}</p>  
        ))}  
      </div>  
    );  
  }  
}

In the code above, we have the key={todo.id.toString()} prop to set the key to the todo ‘s id converted to a string.

If we have no stable identity for our items, we can use the index for the entry as a last resort:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [{ text: "eat" }, { text: "drink" }, { text: "sleep" }]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map((todo, index) => (  
          <p key={index.toString()}>{todo.text}</p>  
        ))}  
      </div>  
    );  
  }  
}

index is always available and it’s unique for each array element, so it can be used as a value for the key prop.

Extracting Components with Keys

If we render components, we should put the key prop in the component rather than the element that’s being rendered.

For example, the following is incorrectly using the key prop:

function TodoItem({ todo }) {  
  return <p key={todo.id.toString()}>{todo.text}</p>;  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <TodoItem todo={todo} />  
        ))}  
      </div>  
    );  
  }  
}

In the TodoItem component, we have:

<p key={todo.id.toString()}>{todo.text}</p>;

with the key prop. We don’t want this there because we don’t need to identify a unique li since it’s isolated from the outside already. Instead, we want to identify a unique TodoItem .

Instead, we should write:

function TodoItem({ todo }) {  
  return <p>{todo.text}</p>;  
}class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <TodoItem todo={todo} key={todo.id.toString()} />  
        ))}  
      </div>  
    );  
  }  
}

We should add keys to items return with map ‘s callback.

Keys Only Need to Be Unique Among Siblings

Keys only need to be unique among sibling elements.

For example, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      posts: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ],  
      comments: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        <div>  
          {this.state.posts.map(post => (  
            <p key={post.id.toString()}>{post.text}</p>  
          ))}  
        </div>  
        <div>  
          {this.state.comments.map(comment => (  
            <p key={comment.id.toString()}>{comment.text}</p>  
          ))}  
        </div>  
      </div>  
    );  
  }

Since posts and comments aren’t rendered in the same div , the key values can overlap.

The key prop doesn’t get passed to components. If we need the same value in a component we have to use a different name.

Embedding map() in JSX

We can embed the expression that calls map straight between the curly braces.

For example, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    return (  
      <div>  
        {[1, 2, 3, 4, 5].map(num => (  
          <span key={num.toString()}>{num}</span>  
        ))}  
      </div>  
    );  
  }  
}

Conclusion

We can use JavaScript array’s map method to map values to React elements or components.

To help React identify elements unique, we should pass in a unique string to key prop for each entry rendered.

It should be passed to anything that’s returned by map ‘s callback since they’re the items that have to be uniquely identified by React.

Also, keys only have to be unique among direct siblings. Other places can have the same key values.

Categories
JavaScript Vue

Handling Form Input with Vue.js with v-model

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to handle form inputs with Vue.js for the v-model directive.

Basic Usage

We can use the v-model directive to create 2-way bindings for form input, textarea, and select elements.

It gets the data from the form, sets the data in the Vue instance or component, and update the view accordingly.

It will ignore some initial value, checked or selected attributes found on form elements. It’ll treat the Vue instance data as the source of truth. Therefore, we should set the initial data in the data option of our component.

v-model uses different properties and emit different events for different input elements:

  • text and textarea elements use the value attribute and input event
  • checkboxes and radio buttons use checked property and change event
  • select fields use value attribute and change as an event

v-model doesn’t get updates during IME composition. We can listen to the input event to pick up those updates.

Text Input

A simple example is as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    message: "Hello"  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input type="text" v-model="message" />  
      <p>Message is {{message}}</p>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

Then when we type something in the input box, we’ll get the same thing displayed below.

Multiline Text

It also works for multiline text. For example, we can write:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    message: "Hello"  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <textarea type="text" v-model="message"> </textarea>  
      <pre>{{message}}</pre>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

Note that only v-model works for model binding, writing <textarea>{{message}}</textarea> won’t work.

Checkbox

We can use v-model on a checkbox as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    checked: false  
  }  
});

index.js :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input type="checkbox" id="checkbox" v-model="checked" />  
      <label for="checkbox">{{ checked }}</label>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

Then when we toggle the checkbox, we’ll get true or false displayed depending on if the checkbox is checked or not.

Multiple checkboxes bound to the same model will be bound to the same array.

For instance, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    persons: []  
  }  
});

Note that persons must be an array.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <label>  
        Joe  
        <input type="checkbox" v-model="persons" value="Joe" />  
      </label>  
      <label>  
        Jane  
        <input type="checkbox" v-model="persons" value="Jane" />  
      </label>  
      <label>  
        Mary  
        <input type="checkbox" v-model="persons" value="Mary" />  
      </label>  
      <p>{{ persons.join(", ") }}</p>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have to bind to the same model, then we have the value attribute values populated in the persons array when the checkbox is checked.

If all 3 are checked, we get something like:

Jane, Joe, Mary

depending on the order that they’re checked.

Radio

We can also use v-model on radio buttons. To use it, we can write:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    person: ""  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input type="radio" value="Jane" v-model="person" />  
      <label>Jane</label>  
      <br />  
      <input type="radio" value="Mary" v-model="person" />  
      <label>Mary</label>  
      <br />  
      <p>{{ person }}</p>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

Then when we click on a radio button, we get the value attribute value for the radio button displayed when it’s selected.

Select

We can use v-model on select as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    selected: ""  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <select v-model="selected">  
        <option disabled value="">Select One</option>  
        <option>foo</option>  
        <option>bar</option>  
        <option>baz</option>  
      </select>  
      <br />  
      <span>Selected: {{ selected }}</span>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

Then we get the selected option displayed when we select an option.

If the initial value of the v-model expression doesn’t match any options, it’ll render in an unselected state.

Multiselect also works. For instance, we can use it as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    selected: []  
  }  
});

Note that it must be an array.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <select v-model="selected" multiple>  
        <option>foo</option>  
        <option>bar</option>  
        <option>baz</option>  
      </select>  
      <br />  
      <span>Selected: {{ selected.join(', ') }}</span>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

We add the multiple attribute to the select element to allow for multiple selections. Then when we shift-click on multiple options, multiple choices will be displayed.

We can also render options dynamically as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    selected: undefined,  
    options: [  
      { text: "One", value: "one" },  
      { text: "Two", value: "two" },  
      { text: "Three", value: "three" }  
    ]  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <select v-model="selected">  
        <option v-for="option in options" v-bind:value="option.value">  
          {{ option.text }}  
        </option>  
      </select>  
      <br />  
      <span>Selected: {{ selected }}</span>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

The value attribute value of the select option element will be displayed.

Conclusion

We can use the v-model directive on input , textarea , and select elements.

It works on both single and multiple selection elements. When binding data to multiple selection elements, it must be bound to an array.

We can also render choices dynamically for elements with multiple choices with v-for .