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 .

Categories
JavaScript Vue

Vue.js Components — Templates and Controlling Updates

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

In this article, we look at alternative ways to define templates and controlling updates.

Alternative Ways to Define Templates

Inline Templates

When the inline-template attribute is present on a child component, the component will use its inner content as its template rather than treating it as distributed content.

However, the scope of the data that’s available inside would be confusing since we have access to the child component’s scope instead of the parent’s inside the tags.

For example, if we have:

src/index.js :

Vue.component("bar", {  
  data() {  
    return {  
      baz: "bar"  
    };  
  },  
  template: `  
    <p></p>  
  `  
});

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

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">  
      <bar inline-template>  
        <div>  
          {{baz}}  
        </div>  
      </bar>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then {{bar}} is referencing baz from the bar component. It also overrides the template that we defined in bar .

X-Templates

Another way to define templates is to use a script tag with type text/x-template . Then it can be referenced with an ID.

For example, we can write:

src/index.js :

Vue.component("hello", {  
  data() {  
    return {  
      hello: "hello"  
    };  
  },  
  template: "#hello-template"  
});

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

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>  
    <script type="text/x-template" id="hello-template">  
      <p>{{hello}}</p>  
    </script>  
    <div id="app">  
      <hello></hello>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The code:

<script type="text/x-template" id="hello-template">  
  <p>{{hello}}</p>  
</script>

is our template and we referenced it by using its ID in:

template: "#hello-template"

So we get hello displayed on the page. This should be avoided for production apps because they separate templates from the rest of the component definition.

Controlling Updates

Vue can control view updates with its reactivity system in most cases. However, there are some edge cases where we want to control the updates ourselves.

Forcing an Update

It’s likely that we made a mistake somewhere if we have to force an update in almost all cases.

In those unlikely cases, we can use $forceUpdate .

Use v-once to Render Static Components

We can use v-once to cache the static content after it’s rendered. This is useful for pages with lots of static content.

For example, we can use it as follows:

src/index.js :

Vue.component("hello", {  
  template: `  
    <div v-once>hello</div>  
  `  
});

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

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">  
      <hello></hello>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

It’s convenient for rare cases when we have to render lots of static content, but it shouldn’t be needed unless we actually see slow rendering.

It may cause trouble if we want to render dynamic content later and when developers aren’t familiar with v-once works on the code. They may be confused about why the component isn’t updating.

Conclusion

We can define templates within a component with the inline-template attribute or using a script element with the type text/x-template .

Then we can reference it by its ID in our component code.

We can use $forceUpdate to force updates and v-once to cache the content after it’s rendered, which may be useful for static content. However, they shouldn’t be used almost all the time.