mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
docs: add deferrable views tutorial (#57934)
Add a new tutorial "Deferrable Views" to the tutorials page. PR Close #57934
This commit is contained in:
parent
b9d846dad7
commit
b84e2d3338
43 changed files with 7362 additions and 0 deletions
|
|
@ -11,6 +11,7 @@ import {NavigationItem} from '@angular/docs';
|
|||
// These 2 imports are expected to be red because they are generated a build time
|
||||
import FIRST_APP_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/first-app/routes.json';
|
||||
import LEARN_ANGULAR_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/learn-angular/routes.json';
|
||||
import DEFERRABLE_VIEWS_TUTORIAL_NAV_DATA from '../../src/assets/tutorials/deferrable-views/routes.json';
|
||||
|
||||
import {DefaultPage} from './core/enums/pages';
|
||||
import {getApiNavigationItems} from './features/references/helpers/manifest.helper';
|
||||
|
|
@ -872,6 +873,7 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
|||
export const TUTORIALS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
FIRST_APP_TUTORIAL_NAV_DATA,
|
||||
LEARN_ANGULAR_TUTORIAL_NAV_DATA,
|
||||
DEFERRABLE_VIEWS_TUTORIAL_NAV_DATA,
|
||||
{
|
||||
path: DefaultPage.TUTORIALS,
|
||||
contentPath: 'tutorials/home',
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ copy_to_directory(
|
|||
"//adev/src/content/tools/cli",
|
||||
"//adev/src/content/tools/libraries",
|
||||
"//adev/src/content/tutorials",
|
||||
"//adev/src/content/tutorials/deferrable-views:deferrable-views-guides",
|
||||
"//adev/src/content/tutorials/first-app:first-app-guides",
|
||||
"//adev/src/content/tutorials/learn-angular:learn-angular-guides",
|
||||
"//packages/animations:animations_docs",
|
||||
|
|
@ -84,6 +85,7 @@ copy_to_directory(
|
|||
copy_to_directory(
|
||||
name = "tutorials",
|
||||
srcs = [
|
||||
"//adev/src/content/tutorials/deferrable-views",
|
||||
"//adev/src/content/tutorials/first-app",
|
||||
"//adev/src/content/tutorials/homepage",
|
||||
"//adev/src/content/tutorials/learn-angular",
|
||||
|
|
|
|||
107
adev/src/assets/images/ang_illustrations-04.svg
Normal file
107
adev/src/assets/images/ang_illustrations-04.svg
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 960.4">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1, .cls-2 {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.cls-1, .cls-3, .cls-4, .cls-5, .cls-6, .cls-7, .cls-8, .cls-9 {
|
||||
stroke-width: 0px;
|
||||
}
|
||||
|
||||
.cls-10, .cls-11, .cls-12, .cls-13, .cls-2 {
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
.cls-10, .cls-11, .cls-12, .cls-13, .cls-2, .cls-14 {
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
|
||||
.cls-10, .cls-11, .cls-13, .cls-2, .cls-14 {
|
||||
stroke: #000;
|
||||
}
|
||||
|
||||
.cls-10, .cls-14, .cls-6 {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.cls-11, .cls-9 {
|
||||
fill: #e7e7e7;
|
||||
}
|
||||
|
||||
.cls-12 {
|
||||
stroke: #232428;
|
||||
}
|
||||
|
||||
.cls-12, .cls-13, .cls-5 {
|
||||
fill: #8514f5;
|
||||
}
|
||||
|
||||
.cls-14 {
|
||||
stroke-dasharray: 0 0 40 27;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.cls-4 {
|
||||
fill: #272428;
|
||||
}
|
||||
|
||||
.cls-7 {
|
||||
fill: #e4e4e4;
|
||||
}
|
||||
|
||||
.cls-8 {
|
||||
fill: #e90464;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-4" x="-36.05" y="-27.87" width="1982.09" height="1016.14"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="cls-5" d="m338.09,289.42h706.06c24.29,0,44.01,19.72,44.01,44.01v658.41c0,24.29-19.72,44.01-44.01,44.01H338.09c-24.29,0-44.01-19.72-44.01-44.01V333.43c0-24.29,19.72-44.01,44.01-44.01Z"/>
|
||||
<path class="cls-3" d="m1044.15,291.42c23.2,0,42.01,18.81,42.01,42.01v658.41c0,23.2-18.81,42.01-42.01,42.01H338.09c-23.2,0-42.01-18.81-42.01-42.01V333.43c0-23.2,18.81-42.01,42.01-42.01h706.06m0-4H338.09c-25.37,0-46.01,20.64-46.01,46.01v658.41c0,25.37,20.64,46.01,46.01,46.01h706.06c25.37,0,46.01-20.64,46.01-46.01V333.43c0-25.37-20.64-46.01-46.01-46.01h0Z"/>
|
||||
</g>
|
||||
<path class="cls-10" d="m457.15,126.61h1468.96c2.56,0,4.63,2.08,4.63,4.63v841.29c0,8.42-6.83,15.25-15.25,15.25H409.82c-2.56,0-4.63-2.08-4.63-4.63V178.57c0-28.68,23.28-51.96,51.96-51.96Z"/>
|
||||
<g>
|
||||
<polyline class="cls-11" points="1145.89 288.64 1145.89 956.86 405 956.86 405 288.64"/>
|
||||
<path class="cls-11" d="m405,288.64h85.87s13.1-4.18,13.1-13.98v-48.56s1.76-13.43,15.64-13.43h389.14c2.41,0,14.53.11,14.53,14.09v48.89s2.97,13.29,15.42,13.29h980.87"/>
|
||||
<rect class="cls-9" x="1291.4" y="427.76" width="547.94" height="238" rx="29.59" ry="29.59"/>
|
||||
<rect class="cls-13" x="1267.68" y="401.87" width="547.94" height="239.62" rx="29.59" ry="29.59"/>
|
||||
</g>
|
||||
<rect class="cls-12" x="536.44" y="235.79" width="184.97" height="45.02" rx="22.51" ry="22.51"/>
|
||||
<g>
|
||||
<line class="cls-2" x1="886.49" y1="241.45" x2="852.8" y2="275.15"/>
|
||||
<line class="cls-2" x1="886.49" y1="275.15" x2="852.8" y2="241.45"/>
|
||||
</g>
|
||||
<rect class="cls-12" x="644.27" y="433.64" width="131.87" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-10" x="805.21" y="433.64" width="211.92" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-10" x="710.21" y="505.35" width="211.92" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<g>
|
||||
<path class="cls-8" d="m732.22,623.09c-13.24,0-24.01-10.77-24.01-24.01s10.77-24.01,24.01-24.01h240.03c13.24,0,24.01,10.77,24.01,24.01s-10.77,24.01-24.01,24.01h-240.03Z"/>
|
||||
<path class="cls-3" d="m972.25,577.07c12.16,0,22.01,9.85,22.01,22.01h0c0,12.16-9.85,22.01-22.01,22.01h-240.03c-12.16,0-22.01-9.85-22.01-22.01h0c0-12.16,9.85-22.01,22.01-22.01h240.03m0-4h-240.03c-14.34,0-26.01,11.67-26.01,26.01s11.67,26.01,26.01,26.01h240.03c14.34,0,26.01-11.67,26.01-26.01s-11.67-26.01-26.01-26.01h0Z"/>
|
||||
</g>
|
||||
<rect class="cls-6" x="483.75" y="361.92" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-10" x="483.75" y="432.92" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-10" x="483.75" y="504.92" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-10" x="483.75" y="576.92" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="483.75" y="651.55" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="483.75" y="723.55" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="483.75" y="795.55" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="483.75" y="867.55" width="89.99" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="648.64" y="723.55" width="127.09" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="805.25" y="723.55" width="270.7" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="710.21" y="795.55" width="190.26" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="928.46" y="795.55" width="147.49" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-6" x="710.21" y="867.55" width="262.23" height="44.02" rx="22.01" ry="22.01"/>
|
||||
<rect class="cls-7" x="1289.13" y="716.84" width="550.44" height="129" rx="32.39" ry="32.39"/>
|
||||
<rect class="cls-14" x="1266.54" y="693.12" width="550.44" height="129" rx="32.39" ry="32.39"/>
|
||||
<rect class="cls-13" x="1294.68" y="734.42" width="52.14" height="50.42"/>
|
||||
<rect class="cls-10" x="1373.19" y="734.42" width="400.36" height="47.8" rx="23.9" ry="23.9"/>
|
||||
<g>
|
||||
<polygon class="cls-6" points="1677.74 739.07 1847.5 833.39 1753.87 840.47 1724.85 927.13 1677.74 739.07"/>
|
||||
<path class="cls-3" d="m1680.8,743.06l159.9,88.83-85.66,6.48-2.65.2-.84,2.52-26.42,78.91-44.33-176.94m-6.12-7.98l49.9,199.17,30.77-91.89,98.96-7.48-179.63-99.79h0Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect class="cls-1" y="0" width="1920" height="960.4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
|
|
@ -11,6 +11,7 @@ generate_guides(
|
|||
],
|
||||
),
|
||||
data = [
|
||||
"//adev/src/assets/images:ang_illustrations-04.svg",
|
||||
"//adev/src/assets/images:learn-angular-browser.svg",
|
||||
"//adev/src/assets/images:learn-angular-local.svg",
|
||||
],
|
||||
|
|
|
|||
21
adev/src/content/tutorials/deferrable-views/BUILD.bazel
Normal file
21
adev/src/content/tutorials/deferrable-views/BUILD.bazel
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
load("//adev/shared-docs:index.bzl", "generate_guides", "generate_tutorial")
|
||||
|
||||
package(default_visibility = ["//adev:__subpackages__"])
|
||||
|
||||
generate_guides(
|
||||
name = "deferrable-views-guides",
|
||||
srcs = glob(["**/*.md"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "files",
|
||||
srcs = glob(
|
||||
["**/*"],
|
||||
exclude = ["**/*.md"],
|
||||
),
|
||||
)
|
||||
|
||||
generate_tutorial(
|
||||
name = "deferrable-views",
|
||||
tutorial_srcs = ":files",
|
||||
)
|
||||
101
adev/src/content/tutorials/deferrable-views/common/angular.json
Normal file
101
adev/src/content/tutorials/deferrable-views/common/angular.json
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"first-app": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"inlineTemplate": true,
|
||||
"inlineStyle": true,
|
||||
"style": "scss",
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:class": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:guard": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:interceptor": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:pipe": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:resolver": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:service": {
|
||||
"skipTests": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"outputPath": "dist/first-app",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/public"
|
||||
}
|
||||
],
|
||||
"styles": ["src/styles.css"],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kB",
|
||||
"maximumError": "4kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "first-app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "first-app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# To learn more about how to use Nix to configure your environment
|
||||
# see: https://developers.google.com/idx/guides/customize-idx-env
|
||||
{ pkgs, ... }: {
|
||||
# Which nixpkgs channel to use.
|
||||
channel = "stable-23.11"; # or "unstable"
|
||||
# Use https://search.nixos.org/packages to find packages
|
||||
packages = [
|
||||
pkgs.nodejs_18
|
||||
];
|
||||
# Sets environment variables in the workspace
|
||||
env = {};
|
||||
idx = {
|
||||
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
||||
extensions = [
|
||||
"angular.ng-template"
|
||||
];
|
||||
workspace = {
|
||||
# Runs when a workspace is first created with this \`dev.nix\` file
|
||||
onCreate = {
|
||||
npm-install = "npm install --no-audit --prefer-offline";
|
||||
};
|
||||
# To run something each time the environment is rebuilt, use the \`onStart\` hook
|
||||
};
|
||||
# Enable previews and customize configuration
|
||||
previews = {
|
||||
enable = true;
|
||||
previews = {
|
||||
web = {
|
||||
command = ["npm" "run" "start" "--" "--port" "$PORT" "--host" "0.0.0.0"];
|
||||
manager = "web";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
6350
adev/src/content/tutorials/deferrable-views/common/package-lock.json
generated
Normal file
6350
adev/src/content/tutorials/deferrable-views/common/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "angular.dev",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "NG_BUILD_PARALLEL_TS=0 ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^18.0.0",
|
||||
"@angular/compiler": "^18.0.0",
|
||||
"@angular/core": "^18.0.0",
|
||||
"@angular/forms": "^18.0.0",
|
||||
"@angular/platform-browser": "^18.0.0",
|
||||
"@angular/router": "^18.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^18.0.1",
|
||||
"@angular/cli": "^18.0.0",
|
||||
"@angular/compiler-cli": "^18.0.0",
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
}
|
||||
11
adev/src/content/tutorials/deferrable-views/intro/README.md
Normal file
11
adev/src/content/tutorials/deferrable-views/intro/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Deferrable views tutorial
|
||||
|
||||
This interactive tutorial consists of lessons that introduce the Angular deferrable views concepts.
|
||||
|
||||
## How to use this tutorial
|
||||
|
||||
Each step represents a concept in Angular deferrable views. You can do one, or all of them.
|
||||
|
||||
If you get stuck, click "Reveal answer" at the top.
|
||||
|
||||
Alright, let's [get started](/tutorials/deferrable-views/1-what-are-deferrable-views).
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"title": "Deferrable Views",
|
||||
"type": "editor",
|
||||
"nextTutorial": "first-app",
|
||||
"openFiles": ["src/app/app.component.ts"]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
Welcome to Angular!
|
||||
`,
|
||||
standalone: true,
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# What are deferrable views?
|
||||
|
||||
A fully rendered Angular page may contain many different components, directives, and pipes. While certain parts of the page should be shown to the user immediately, there may be portions that can wait to display until later.
|
||||
Angular's *deferrable views*, using the `@defer` syntax, can help you speed up your application by telling Angular to wait to download the JavaScript for the parts of the page that don't need to be shown right away.
|
||||
|
||||
In this activity, you'll learn how to use deferrable views to defer load a section of your component template.
|
||||
|
||||
<hr>
|
||||
|
||||
<docs-workflow>
|
||||
|
||||
<docs-step title="Add a `@defer` block to a section of a template">
|
||||
In your `app.component.ts`, wrap the `article-comments` component with a `@defer` block to defer load it.
|
||||
|
||||
<docs-code language="angular-html">
|
||||
@defer {
|
||||
<article-comments />
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
By default, `@defer` loads the `article-comments` component when the browser is idle.
|
||||
|
||||
In your browser's developer console, you can see that the `article-comments-component` lazy chunk file is loaded separately (The specific file names may change from run to run):
|
||||
|
||||
<docs-code language="markdown">
|
||||
Initial chunk files | Names | Raw size
|
||||
chunk-NNSQHFIE.js | - | 769.00 kB |
|
||||
main.js | main | 229.25 kB |
|
||||
|
||||
Lazy chunk files | Names | Raw size
|
||||
chunk-T5UYXUSI.js | article-comments-component | 1.84 kB |
|
||||
</docs-code>
|
||||
|
||||
</docs-step>
|
||||
</docs-workflow>
|
||||
|
||||
|
||||
Great work! You’ve learned the basics of deferrable views.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@defer {
|
||||
<article-comments />
|
||||
}
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"openFiles": ["src/app/app.component.ts", "src/app/article-comments.component.ts"],
|
||||
"title": "What are deferrable views",
|
||||
"type": "editor"
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article-comments />
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# @loading, @error and @placeholder blocks
|
||||
|
||||
Deferrable views let you define content to be shown in different loading states.
|
||||
|
||||
<div class="docs-table docs-scroll-track-transparent">
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>@placeholder</code></td>
|
||||
<td>
|
||||
By default, defer blocks do not render any content before they are triggered. The <code>@placeholder</code> is an optional block that declares content to show before the deferred content loads. Angular replaces the placeholder with the deferred content after loading completes. While this block is optional, the Angular team recommends always including a placeholder.
|
||||
<a href="https://angular.dev/guide/defer#triggers" target="_blank">
|
||||
Learn more in the full deferrable views documentation
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>@loading</code></td>
|
||||
<td>
|
||||
This optional block allows you to declare content to be shown during the loading of any deferred dependencies.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>@error</code></td>
|
||||
<td>
|
||||
This block allows you to declare content which is shown if deferred loading fails.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
The contents of all the above sub-blocks are eagerly loaded. Additionally, some features require a `@placeholder` block.
|
||||
|
||||
In this activity, you'll learn how to use the `@loading`, `@error` and `@placeholder` blocks to manage the states of deferrable views.
|
||||
|
||||
<hr>
|
||||
|
||||
<docs-workflow>
|
||||
|
||||
<docs-step title="Add `@placeholder` block">
|
||||
In your `app.component.ts`, add a `@placeholder` block to the `@defer` block.
|
||||
|
||||
<docs-code language="angular-html" highlight="[3,4,5]">
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder {
|
||||
<p>Placeholder for comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Configure the `@placeholder` block">
|
||||
The `@placeholder` block accepts an optional parameter to specify the `minimum` amount of time that this placeholder should be shown. This `minimum` parameter is specified in time increments of milliseconds (ms) or seconds (s). This parameter exists to prevent fast flickering of placeholder content in the case that the deferred dependencies are fetched quickly.
|
||||
|
||||
<docs-code language="angular-html" highlight="[3,4,5]">
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Add `@loading` block">
|
||||
Next add a `@loading` block to the component template.
|
||||
|
||||
The `@loading` block accepts two optional parameters:
|
||||
|
||||
* `minimum`: the amount of time that this block should be shown
|
||||
* `after`: the amount of time to wait after loading begins before showing the loading template
|
||||
|
||||
Both parameters are specified in time increments of milliseconds (ms) or seconds (s).
|
||||
|
||||
Update `app.component.ts` to include a `@loading` block with a minimum parameter of `1s` as well as an after parameter with the value 500ms to the @loading block.
|
||||
|
||||
<docs-code language="angular-html" highlight="[5,6,7]">
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
Note: this example uses two parameters, separated by the ; character.
|
||||
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Add `@error` block">
|
||||
Finally, add an `@error` block to the `@defer` block.
|
||||
|
||||
<docs-code language="angular-html" highlight="[7,8,9]">
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
</docs-step>
|
||||
</docs-workflow>
|
||||
|
||||
Congratulations! At this point, you have a good understanding about deferrable views. Keep up the great work and let's learn about triggers next.
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"openFiles": ["src/app/app.component.ts", "src/app/article-comments.component.ts"],
|
||||
"title": "@loading, @error and @placeholder blocks",
|
||||
"type": "editor"
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@defer {
|
||||
<article-comments />
|
||||
}
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# Defer triggers
|
||||
|
||||
While the default options for `@defer` offer great options for lazy loading parts of your components it may still be desirable to further customize the deferred loading experience.
|
||||
|
||||
By default, deferred content loads when the browser is idle. You can, however, customize when this loading occurs by specifying a **trigger**. This lets you pick the loading behavior best suited to your component.
|
||||
|
||||
Deferrable views offer two types of loading trigger:
|
||||
|
||||
<div class="docs-table docs-scroll-track-transparent">
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>on</code></td>
|
||||
<td>
|
||||
A trigger condition using a trigger from the list of built-in triggers.<br/>
|
||||
For example: <code>@defer (on viewport)</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>when</code></td>
|
||||
<td>
|
||||
A condition as an expression which is evaluated for truthiness. When the expression is truthy, the placeholder is swapped with the lazily loaded content.<br/>
|
||||
For example: <code>@defer (when customizedCondition)</code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
If the `when` condition evaluates to `false`, the `defer` block is not reverted back to the placeholder. The swap is a one-time operation.
|
||||
|
||||
You can define multiple event triggers at once, these triggers will be evaluated as OR conditions.
|
||||
|
||||
* Ex: `@defer (on viewport; on timer(2s))`
|
||||
* Ex: `@defer (on viewport; when customizedCondition)`
|
||||
|
||||
In this activity, you'll learn how to use triggers to specify the condition to load the deferrable views.
|
||||
|
||||
<hr>
|
||||
|
||||
<docs-workflow>
|
||||
|
||||
<docs-step title="Add `on hover` trigger">
|
||||
In your `app.component.ts`, add an `on hover` trigger to the `@defer` block.
|
||||
|
||||
<docs-code language="angular-html" hightlight="[1]">
|
||||
@defer (on hover) {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
Now, the page will not render the comments section until you hover its placeholder.
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Add a 'Show all comments' button">
|
||||
Next, update the template to include a button with the label "Show all comments". Include a template variable called `#showComments` with the button.
|
||||
|
||||
<docs-code language="angular-html" hightlight="[1]">
|
||||
<button type="button" #showComments>Show all comments</button>
|
||||
|
||||
@defer (on hover) {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
Note: for more information on [template variables check the documentation](https://angular.dev/guide/templates/reference-variables#).
|
||||
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Add `on interaction` trigger">
|
||||
Update the `@defer` block in the template to use the `on interaction` trigger. Provide the `showComments` template variable as the parameter to `interaction`.
|
||||
|
||||
<docs-code language="angular-html" hightlight="[3]">
|
||||
<button type="button" #showComments>Show all comments</button>
|
||||
|
||||
@defer (on hover; on interaction(showComments)) {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
With these changes, the page will wait for one of the following conditions before rendering the comments section:
|
||||
* User hovers the comments section’s placeholder
|
||||
* User clicks on the “Show all comments" button
|
||||
|
||||
You can reload the page to try out different triggers to render the comments section.
|
||||
</docs-step>
|
||||
</docs-workflow>
|
||||
|
||||
If you would like to learn more, check out the documentation for [Deferrable View](https://angular.dev/guide/defer).
|
||||
Keep learning to unlock more of Angular's great features.
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<button type="button" #showComments>Show all comments</button>
|
||||
|
||||
@defer (on hover; on interaction(showComments)) {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"openFiles": ["src/app/app.component.ts", "src/app/article-comments.component.ts"],
|
||||
"title": "Defer triggers",
|
||||
"type": "editor"
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {ArticleCommentsComponent} from './article-comments.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@defer {
|
||||
<article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [ArticleCommentsComponent],
|
||||
})
|
||||
export class AppComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {ApplicationConfig} from '@angular/core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'article-comments',
|
||||
template: `
|
||||
<h2>Comments</h2>
|
||||
<p class="comment">
|
||||
Building for the web is fantastic!
|
||||
</p>
|
||||
<p class="comment">
|
||||
The new template syntax is great
|
||||
</p>
|
||||
<p class="comment">
|
||||
I agree with the other comments!
|
||||
</p>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin-left: 30px;
|
||||
background-color: paleturquoise;
|
||||
border-radius: 20px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArticleCommentsComponent {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {AppComponent} from './app/app.component';
|
||||
import {appConfig} from './app/app.config';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
||||
|
|
@ -9,4 +9,7 @@ Welcome to the Angular tutorials! These tutorials will guide you through the cor
|
|||
<docs-card title="Build your first Angular app locally" link="Start coding" href="tutorials/first-app" imgSrc="adev/src/assets/images/learn-angular-local.svg">
|
||||
via npm
|
||||
</docs-card>
|
||||
<docs-card title="Deferrable views" link="Start coding" href="tutorials/deferrable-views" imgSrc="adev/src/assets/images/ang_illustrations-04.svg">
|
||||
via the Playground
|
||||
</docs-card>
|
||||
</docs-card-container>
|
||||
|
|
|
|||
Loading…
Reference in a new issue