Compare commits
894 Commits
Author | SHA1 | Date | |
---|---|---|---|
b667bd2224 | |||
03e8a31bf5 | |||
800e90e4ed | |||
7290053952 | |||
14890e9117 | |||
06c49b4a6b | |||
d269b111dd | |||
46b160e925 | |||
dcbc28f729 | |||
9bdffb1e5c | |||
155f40c175 | |||
8c446b05d0 | |||
2647f708b7 | |||
fa15814d75 | |||
7a62530ed1 | |||
6ece7db37a | |||
3a2b195a58 | |||
489cef6ea2 | |||
985513351b | |||
8f3dd85600 | |||
6b67cd5620 | |||
0cd4c019cf | |||
7e46a6d99d | |||
85d051f8d5 | |||
c7542a1d09 | |||
2172368eae | |||
2c402d5c99 | |||
35a025fbca | |||
a86850e3f2 | |||
1bcd58cee8 | |||
dd0be7feb7 | |||
3d7303efc0 | |||
716af1059c | |||
a182714703 | |||
17b32b5fd4 | |||
29e1c53a31 | |||
87ce4e997b | |||
2bb9a65351 | |||
6b51ed29ef | |||
b696413a79 | |||
b6aeaceb8e | |||
5ae9b76a9b | |||
82055b2fb8 | |||
44039a4b16 | |||
a445826dad | |||
7f7033bbd7 | |||
27997a16c0 | |||
59c3700c8c | |||
4d93d2406f | |||
d39a2beae1 | |||
c038992fae | |||
8a470b9af9 | |||
399935c32b | |||
97ab52c618 | |||
f69e4e6f77 | |||
9f2ae5d6ff | |||
9eefe25e2f | |||
221782a8a1 | |||
24ca582bc5 | |||
b31a292955 | |||
1d7aa0a92c | |||
0aff4a6919 | |||
f50dede8f7 | |||
0e68c7edf9 | |||
54ef63b0f4 | |||
215ef3c5f4 | |||
5a8eb924ba | |||
c845a7b887 | |||
8b26447c4f | |||
ce196105ce | |||
b9a94c6d02 | |||
ebc71f7caa | |||
f65db20c6d | |||
8f084d7214 | |||
cb848b9410 | |||
d52ae7cbab | |||
9c954ebc62 | |||
f14693b9a4 | |||
f10d6c66c9 | |||
4495a46b99 | |||
ef75fb8ecd | |||
7b6ee5e0d9 | |||
e822394075 | |||
1b6e8411bd | |||
7151eae36d | |||
376ad9c3cd | |||
4aecf9253b | |||
60f58bf051 | |||
10a1e1974b | |||
647d7bdd88 | |||
69a612d402 | |||
221cbd0b47 | |||
ce9d0de840 | |||
18f0c2f1d4 | |||
5bd12c5aa1 | |||
0139b11227 | |||
e061e638cb | |||
dda781ecce | |||
a27c5dd740 | |||
012b535147 | |||
2200884e55 | |||
78e7fdd98d | |||
1e9eeafa9e | |||
9ef9bfe76b | |||
a5f9a86520 | |||
dd664f694c | |||
b66d82e308 | |||
518bca0841 | |||
d7ca263cc4 | |||
e8ae3c5f2e | |||
85a7fe8702 | |||
32c07ceca0 | |||
d3744457ab | |||
fc61284dbe | |||
12fd06916b | |||
9e83822679 | |||
54794f9b31 | |||
897bd18fbc | |||
1ac07757dd | |||
0110de2662 | |||
f166b6d8f6 | |||
09576e9683 | |||
40d785f0a0 | |||
46c03bd866 | |||
d5d8657d30 | |||
8853f13f82 | |||
3166cffd28 | |||
40705f3366 | |||
19bc11139d | |||
31ea254a07 | |||
caf8c0a437 | |||
d6c80871f5 | |||
edc51f76c4 | |||
c529be9f24 | |||
b65e11e3c3 | |||
3a09d01c63 | |||
604d9063c5 | |||
c4c340a7c4 | |||
32aa18be78 | |||
80fa84c177 | |||
e44ba0ffa9 | |||
19a28e599b | |||
14ad7562c6 | |||
0c61a35ea3 | |||
fac20bd8d1 | |||
63e458dd3a | |||
d545bbeee4 | |||
4bb283cbb2 | |||
a08b4b3519 | |||
0e86551a63 | |||
5c738417db | |||
3d9ba19ff8 | |||
8b7a4d7550 | |||
76b755e292 | |||
565a58e261 | |||
7014b67e51 | |||
6f50aad5c4 | |||
ef44f51d58 | |||
9204de96a1 | |||
7c62a8f9ca | |||
a55c6df07b | |||
d33204956f | |||
66d6b53fb1 | |||
e85fa5d4ff | |||
0c00c94f34 | |||
9b29ca95a2 | |||
479d926b4b | |||
b9195289a5 | |||
75b6b0e1ba | |||
2d4f507b61 | |||
3246a8553c | |||
db557221bc | |||
7ea6073534 | |||
1cba5d42d1 | |||
103a5b42ec | |||
fe1793844d | |||
68940f05d8 | |||
53212db3ed | |||
dee16a4355 | |||
6da1446afc | |||
76e3b57a12 | |||
524180c271 | |||
c69e552a83 | |||
2844f2779f | |||
2b44be984e | |||
989ebcbb62 | |||
23e0d65471 | |||
e92fb68f3c | |||
7724f7446a | |||
207f9b6017 | |||
a581773887 | |||
7f2330a968 | |||
aaaeb924ac | |||
98a68ad3e7 | |||
36d3062a42 | |||
83b19bf1a2 | |||
e6f1b04cd5 | |||
6aaca21c27 | |||
50c4ec6687 | |||
9a2d1fab84 | |||
8052de07e2 | |||
40aaa42f44 | |||
35f8bfce8b | |||
4b05ebc804 | |||
e30f494a39 | |||
1d3e22766a | |||
c0955975f4 | |||
9515f171b4 | |||
1efaac5cb0 | |||
d27181fcdd | |||
9e34670b25 | |||
5039faff8d | |||
44c6534f3c | |||
09970d52e8 | |||
95a9d67599 | |||
fde016bc38 | |||
11a208f55c | |||
1db3ac457c | |||
02491a6ce8 | |||
dca713c087 | |||
eb6281f5b4 | |||
a4a423a083 | |||
ba5b3af077 | |||
64e7af4e43 | |||
d2d84c4460 | |||
29f5582af5 | |||
63bdfca580 | |||
361109d80f | |||
b7a099d27e | |||
f83dfd6f5a | |||
dd36f3ac99 | |||
0d6fd134d4 | |||
bbb27b5517 | |||
7ca611cd12 | |||
c12b6fa028 | |||
a29dc961a2 | |||
0de5d79bf6 | |||
f57e77eeb4 | |||
2b5d52fbdc | |||
81332150aa | |||
c6b29f4c6d | |||
261dc04d8e | |||
15e397816f | |||
f96a81a818 | |||
4f38419e33 | |||
119004c7d4 | |||
d171006083 | |||
19e8570ac0 | |||
93abc35213 | |||
d7be38f84b | |||
2d38623974 | |||
5306330d85 | |||
c150354464 | |||
7217525da4 | |||
b6e8d19313 | |||
6c0cca093a | |||
f2360aab9d | |||
d7b4172678 | |||
641a4ea763 | |||
da4f7fbe1b | |||
9c87d223ee | |||
2be061a96e | |||
3851544674 | |||
6b7b4ee891 | |||
279e74603e | |||
8503901746 | |||
e01d697eed | |||
59d2edfebe | |||
a8f3b317f1 | |||
3788ebb714 | |||
32c760f5e7 | |||
f690a4e0af | |||
42036f4b79 | |||
74f637f98d | |||
e943859843 | |||
a94bdc6793 | |||
2dfd97d8f0 | |||
869e3e8edc | |||
7c4c676413 | |||
4004d15ba5 | |||
abbbc69e64 | |||
4fe0e75365 | |||
103064a3d0 | |||
29a9909232 | |||
7186f9c016 | |||
1e7e065423 | |||
ae1ac45981 | |||
280e8563f0 | |||
660800ca4e | |||
2c07820636 | |||
44b1ce6c72 | |||
5eb4691dec | |||
35acd44a07 | |||
8afc998ec4 | |||
26a85a82ff | |||
98685e6f85 | |||
61f2353467 | |||
ef9cb6a034 | |||
3846192bde | |||
a1d436e6a4 | |||
02d98ed823 | |||
e8d0265c1e | |||
00ecfc7f9a | |||
6ff3970ec7 | |||
1d5c44551d | |||
2aba485118 | |||
b11a2057c6 | |||
6ba42f1da4 | |||
708d0a2db2 | |||
ab27337612 | |||
72e4ff7591 | |||
5bec683692 | |||
cd617b15e8 | |||
a38433f36b | |||
28d3bfc416 | |||
f7e9659c4d | |||
16717fa12c | |||
74f4f5dfab | |||
3fb73ac62b | |||
a5dd4edab9 | |||
e83667ad76 | |||
805fc8698c | |||
23c017121e | |||
fcb03abc72 | |||
6f5d910ddd | |||
d72f8c949f | |||
29df3b0ee2 | |||
a4fc98cace | |||
131e2440f2 | |||
65974154e2 | |||
7035f225ad | |||
9c06af2dfc | |||
83f0304cfc | |||
a9502886b1 | |||
4bd6fca4ef | |||
bd3b0564e6 | |||
b1664425a9 | |||
ecd7f6ecdc | |||
6a381d9246 | |||
1f1cf1a169 | |||
48def92cad | |||
dc613b336d | |||
7ff628f8d5 | |||
3fb78aaacc | |||
5e53956c2b | |||
fad03c3c14 | |||
34eaafdf40 | |||
bf7d046269 | |||
5eb7426216 | |||
7b3bcc23af | |||
b356fb01d5 | |||
f2219081e3 | |||
70ad91ed8b | |||
75ac724842 | |||
4c45aa39e4 | |||
c5d1e1a3da | |||
b1fe1aa8fa | |||
9177ffaf58 | |||
f4fe1f65be | |||
029f1be204 | |||
91008bd979 | |||
f0395836b6 | |||
4b16d98955 | |||
ab86a58f27 | |||
4ec50811d4 | |||
c34abf2cbc | |||
c6b180380a | |||
7814ef55c5 | |||
f72772b038 | |||
0bf810022a | |||
bc04d18420 | |||
7a53b9090e | |||
db08fd2607 | |||
3998335188 | |||
f4cd2b75b4 | |||
5909c442b7 | |||
f5fa9dc6b8 | |||
87665fe324 | |||
16ac611a84 | |||
beaab27a49 | |||
87168acf39 | |||
65544ac742 | |||
57c4788bc7 | |||
7e49beb8cd | |||
036294d566 | |||
98515e1ecf | |||
c52ade2878 | |||
4adf95ed6f | |||
a1fc4deff3 | |||
e0969b2480 | |||
c596795e64 | |||
a6cb20cbe7 | |||
6fbfb5a159 | |||
16aa6ceff8 | |||
b5aa0473fc | |||
e76690be29 | |||
6c4d91297e | |||
f41242f18e | |||
e2fd628618 | |||
2c2135d331 | |||
7e3a60ad31 | |||
85d38ae564 | |||
4ad323a4d6 | |||
a4601eca68 | |||
e84b51d2b6 | |||
8f5c396a7c | |||
0c3bb6a731 | |||
cc0bd11a5e | |||
5d24a75ac9 | |||
799d1fd333 | |||
6bc9c78d76 | |||
bb4e230eae | |||
48d11d5fa0 | |||
1a5c7112e0 | |||
352f9672c0 | |||
76584804c8 | |||
2c78da00ae | |||
bb8a18e72d | |||
82e0b4a4fb | |||
574990e0fd | |||
aa9eb55e3c | |||
052ef654d2 | |||
58be2ff884 | |||
7912db3829 | |||
0ee09cdd7e | |||
b2937b16c3 | |||
a4b4f35533 | |||
b0866769b0 | |||
699283c4ee | |||
bb635c09fd | |||
c15e6750d5 | |||
87bf1791a9 | |||
8c4bd61b2f | |||
230e9766f6 | |||
2b4d5c7548 | |||
271d2b51a9 | |||
7b0bee73de | |||
c9ce485ce0 | |||
ba4ca5f9a5 | |||
4155ed439a | |||
2b9a4cc6a6 | |||
016b3f16a3 | |||
87b1a2af4d | |||
a2cd401a2e | |||
93af1f8456 | |||
5193acb0a3 | |||
532c1cb485 | |||
ef0b2cc74d | |||
a794143820 | |||
ba83d33dd0 | |||
17d87d4e10 | |||
9d9c9e43e5 | |||
c0386757b1 | |||
5c18f23788 | |||
7afd2603c9 | |||
81c2a94310 | |||
297222f892 | |||
64488b12ac | |||
8b6fbf8655 | |||
383ab8515d | |||
11a4454ab3 | |||
04587a33c5 | |||
b4b7af86c2 | |||
f440bd1793 | |||
3859bcc70c | |||
30efb6b8ea | |||
05a43ca869 | |||
b51d8dd438 | |||
ea2d453118 | |||
17bfedd224 | |||
540b01402f | |||
8852b793df | |||
d1df0a94d4 | |||
00cc905b98 | |||
337b6fe003 | |||
ef4a15bc0b | |||
0d4f8c7dd9 | |||
b74df20c2a | |||
4ecff42e7f | |||
55a14e4866 | |||
c7850fff3b | |||
456f2e70af | |||
4da5e9a156 | |||
812c231b0c | |||
3ed7463ad7 | |||
8154433130 | |||
07cd65b5ec | |||
cd6fc8bf06 | |||
fcdd784667 | |||
a981dd2aab | |||
b4e68025f8 | |||
680d38513b | |||
21328f2373 | |||
dd8cf19352 | |||
8bedf50073 | |||
32886cf9ac | |||
fcef39048a | |||
1315d23aa4 | |||
8ce288a852 | |||
f936590573 | |||
876cd603f1 | |||
aca339e864 | |||
f4cd3740b2 | |||
6d861f240b | |||
1f79c827a0 | |||
e0c36620c1 | |||
80394ce08b | |||
99c9bcab03 | |||
fa354888b1 | |||
d82adbe8c4 | |||
09c57ecf95 | |||
282abdb02d | |||
19bbf4bc8e | |||
53c6b78c51 | |||
91699259b2 | |||
41f372fe79 | |||
8e8c1ad47d | |||
b61784948a | |||
b4644d7bb0 | |||
7a0f8ac36c | |||
5e0f982961 | |||
f5b0c8a323 | |||
d2b0ac7de8 | |||
a2d26c6f2a | |||
62332b80da | |||
e3f3b106ac | |||
fd23663a29 | |||
71be1da0ad | |||
6a5cc8f95c | |||
2c406fb1a9 | |||
0b23adca80 | |||
671f64324b | |||
f1f8d70a41 | |||
8301028319 | |||
ba5309c1f8 | |||
fa5d8ca041 | |||
24ca8ba7ce | |||
af4925f374 | |||
77578266fd | |||
7bf7244ba3 | |||
1a98d51f98 | |||
82682bb93f | |||
d72479b628 | |||
dd0815095f | |||
48093823cb | |||
51cb5925c5 | |||
a36cacae79 | |||
1b5096d5a9 | |||
875eedbfb0 | |||
75cdda5f0a | |||
6363db89d0 | |||
573f57ac90 | |||
41cf066906 | |||
661c6e6f10 | |||
84dd2679a9 | |||
dc6406e5e8 | |||
deb77bd3df | |||
d5f96a887d | |||
68cd0cab8c | |||
9b3af1468d | |||
be0bc799f3 | |||
0d23cedab8 | |||
6bf5ec241d | |||
cdb5ea4200 | |||
bfedfa79ed | |||
911a8160ec | |||
8479cb4233 | |||
250887244e | |||
9b035e4038 | |||
ccc76f7498 | |||
f310a5960e | |||
b5c893916d | |||
132c61dfd4 | |||
5640cedc82 | |||
faac51fd2e | |||
214ae0ea4c | |||
dcdecfa9a8 | |||
4299ecf9be | |||
21e8ac1e02 | |||
01cf04c85f | |||
5c5cee9f39 | |||
2f336f15be | |||
e122b44269 | |||
9ce9561737 | |||
2545445ffb | |||
300f1b289a | |||
975845596d | |||
2cdbe9b2ef | |||
988afad2af | |||
1537aec1f9 | |||
7555a46e23 | |||
38d7acee4d | |||
10f48278c2 | |||
d4e6263453 | |||
86c46908d4 | |||
fa6cbb3ffe | |||
e20b92ba37 | |||
c7a9987067 | |||
1bdec3ed6a | |||
620cd5c148 | |||
76391f8999 | |||
02523debe5 | |||
70fd4300f4 | |||
3125376ec1 | |||
2cd5294394 | |||
3c548189b1 | |||
ae91f45b27 | |||
f74e0fd825 | |||
f1ea78ba09 | |||
87a2366eeb | |||
0f5da82cfd | |||
66f269c077 | |||
b613f90146 | |||
2fe6f350cb | |||
514ebf402a | |||
7c0667d215 | |||
f6bf8928f2 | |||
6debe9dfb9 | |||
0d52a27f41 | |||
697046c2b2 | |||
53a0b26348 | |||
8c00fced1c | |||
a50c1bb7bc | |||
f3c69e7f6b | |||
c9f5f3d802 | |||
a96976e88f | |||
ebfbc04000 | |||
e1af6e3c70 | |||
9e946c9715 | |||
0d97143965 | |||
df1d3fbd7b | |||
e946594bf8 | |||
abe4433202 | |||
c79bffaacb | |||
e58e5ec6a6 | |||
e688e02ee4 | |||
d7eaae6f22 | |||
1c3ee41902 | |||
f78bda9ff0 | |||
6454f76cf6 | |||
28ae22ecb9 | |||
c1135ee18f | |||
1114053daa | |||
95830ee584 | |||
661a57d9e2 | |||
660a091f41 | |||
7d31f7b540 | |||
ab4a23d0e0 | |||
a39f4e2301 | |||
8e2e9dcee6 | |||
9d5abfb3d9 | |||
fd7dd4d9fc | |||
01919fbaae | |||
80d4fc5e26 | |||
eda09e69ea | |||
0937062a64 | |||
6f073885b0 | |||
f03475cac8 | |||
848e53efd0 | |||
6bf8b1007c | |||
98ded949dd | |||
a5a1f4f52f | |||
8c1a041411 | |||
b1ba2d6f4e | |||
1714451a6d | |||
1f6fcb6cd3 | |||
60235b5aef | |||
d18c58816f | |||
222dde129d | |||
257e9646d0 | |||
a5e06ba629 | |||
9a6d298ca7 | |||
6ec621b72d | |||
07ebe9624f | |||
b4014e9a39 | |||
73e3f565e0 | |||
757d4c33df | |||
edd775eabc | |||
c613596658 | |||
f4655ea98a | |||
f6aa60c03c | |||
7fec1771fc | |||
c9b588b349 | |||
37f69eddc7 | |||
0fa72a8bc8 | |||
48b77459ef | |||
989bfd2e97 | |||
aeec66b657 | |||
e68490c5e4 | |||
95c5b1a7f6 | |||
8e201f713a | |||
ac34a1429b | |||
739e5a4f53 | |||
bf94932c7a | |||
6cb3b50a03 | |||
0e92332491 | |||
f5127f601d | |||
1b613c3ebf | |||
3f7e823b80 | |||
e9ead2bc09 | |||
b6b1aec22b | |||
1aff524b63 | |||
077809398c | |||
f9404d9e7c | |||
b766987b98 | |||
c62c5e2999 | |||
f2ae452f01 | |||
79903b1842 | |||
0051ddf0f3 | |||
3a8f74e392 | |||
8555016eec | |||
45e11915dc | |||
1a0e500eea | |||
35c1750fcc | |||
53f356427f | |||
d20b0f4b93 | |||
79d4b16f8a | |||
0fd9d086e4 | |||
4f9b16783b | |||
018a5168a5 | |||
cf86ed7b29 | |||
dbb150a9bd | |||
9e5377a2e3 | |||
0cdf5980e2 | |||
6ceb9034dc | |||
f9fb921f91 | |||
1b059e595f | |||
ff29cccb77 | |||
c7f9a95a3f | |||
06efc340b6 | |||
3fecab64b1 | |||
34e0d621fd | |||
cc2f175617 | |||
96baff3a85 | |||
090eac068a | |||
d09d8e0adf | |||
a57f3e7bbf | |||
197584d1af | |||
18c0ba5272 | |||
1bd4891c9a | |||
3a7bfc721e | |||
f74373f2dd | |||
2f35dbfd3b | |||
31df5139c5 | |||
7569a2e0d9 | |||
7dad3284e3 | |||
0cf09fc981 | |||
877b2285f9 | |||
0d4a0b6519 | |||
4feb9b1c72 | |||
cb6dea473f | |||
5ab809ddf9 | |||
fbff03b476 | |||
411524d341 | |||
0a0b4c1d8f | |||
5887ddfa3c | |||
d80ae6ba0d | |||
44cf981407 | |||
5fd39283ec | |||
1f2b39ad7d | |||
24e172d779 | |||
b68850215a | |||
9abf114fbb | |||
8d3365e4fc | |||
8cec8f5584 | |||
741a5dc5f7 | |||
de996c6d56 | |||
d750b1e10d | |||
d2c83ea81b | |||
bf031fc56b | |||
b1d45ee6d2 | |||
f26f036286 | |||
0ffdb48f62 | |||
cb6ad971c3 | |||
d70b1ff177 | |||
3aff79c251 | |||
d8665e639b | |||
c016e2c4ec | |||
452f121486 | |||
728db88280 | |||
9a807bd26a | |||
eccc41c5cf | |||
509352fc36 | |||
349935a434 | |||
6357d4a0d3 | |||
29786e856d | |||
bf6bedd714 | |||
f094bb54a7 | |||
4c12d742dc | |||
04a9f28c3d | |||
d9b9ed56b6 | |||
7c8a62d64d | |||
de651122a5 | |||
4a96ddfb54 | |||
8ced321bb6 | |||
2a0f497e94 | |||
392473ec79 | |||
345a3cd9aa | |||
bd37622050 | |||
48de6e87f0 | |||
3b551e0fcd | |||
be8fbac942 | |||
98a38ec98b | |||
4f055d4257 | |||
c59717571e | |||
f5b2ae616f | |||
1660b34e2d | |||
b40f6f3eae | |||
3327bd8eab | |||
ea9a381c8c | |||
b2437c4500 | |||
d6538eb2fd | |||
0926119977 | |||
39f2c9f46b | |||
60a8888b4f | |||
4537816c1d | |||
bf73fb7420 | |||
1ec092ba32 | |||
30d1f292c9 | |||
b70d20b510 | |||
066ec33342 | |||
5b80ab372d | |||
638ba4a2cf | |||
7ec8806dc5 | |||
7d6f4885b2 | |||
b1506a3271 | |||
b15a403c71 | |||
37c598db04 | |||
ad94e02981 | |||
00ffc03523 | |||
e53cf81689 | |||
089fcbf369 | |||
68ff2cc323 | |||
164d160b22 | |||
1353bf0277 | |||
6dc884f2ab | |||
05eabb19d6 | |||
f4916730b5 | |||
67012509a8 | |||
28a1caa0ed | |||
f015dbe1ba | |||
029a93963a | |||
20898f9f4f | |||
ef861958a9 | |||
16d7dde2ad | |||
1fd2cc6340 | |||
5ced8fbbd5 | |||
23152c37c8 | |||
4a2405929c | |||
eef4ca5dd3 | |||
321da5cc83 | |||
c2cf500da9 | |||
4c03208537 | |||
78b5bd5174 | |||
1195dabb84 | |||
2945f47977 | |||
a44b510087 | |||
572b54967c | |||
6f433887e0 | |||
537502d685 | |||
e5c3695dbd | |||
3cf318b498 | |||
54d4105264 | |||
dd59b1d371 | |||
124e49752f | |||
fc2dd5482e | |||
e4b81a6957 | |||
3efdd39a18 | |||
582ef2e7b4 | |||
214fef2ee4 | |||
531fcaa99a | |||
8a60239ae7 | |||
10705684c8 | |||
bdc6818716 | |||
5f95796b61 | |||
f2709ac3f9 | |||
cce9b9912f | |||
2ae26ce20b | |||
d47de60944 | |||
acfcf90528 | |||
c99d379cc8 | |||
0151ad432b | |||
1b0be8d656 | |||
47244ba2b8 | |||
0d66844ad6 | |||
b945bc3a9e | |||
4ae0ee86cb | |||
6c86ae710a | |||
f3ce8eeb83 | |||
876ceb3688 | |||
ee12c45473 | |||
1f4c380f58 | |||
b9f0720c95 | |||
71b8b355a6 |
@ -1,3 +1,4 @@
|
|||||||
|
.git
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
aio/content
|
aio/content
|
||||||
|
72
.bazelrc
72
.bazelrc
@ -1,20 +1,3 @@
|
|||||||
################################
|
|
||||||
# Settings for Angular team members only
|
|
||||||
################################
|
|
||||||
# To enable this feature check the "Remote caching" section in docs/BAZEL.md.
|
|
||||||
build:angular-team --remote_http_cache=https://storage.googleapis.com/angular-team-cache
|
|
||||||
|
|
||||||
###############################
|
|
||||||
# Typescript / Angular / Sass #
|
|
||||||
###############################
|
|
||||||
|
|
||||||
# Make compilation fast, by keeping a few copies of the compilers
|
|
||||||
# running as daemons, and cache SourceFile AST's to reduce parse time.
|
|
||||||
build --strategy=AngularTemplateCompile=worker
|
|
||||||
# TODO(alexeagle): re-enable after fixing worker instability with rxjs typings
|
|
||||||
# build --strategy=TypeScriptCompile=worker
|
|
||||||
build --strategy=TypeScriptCompile=standalone
|
|
||||||
|
|
||||||
# Enable debugging tests with --config=debug
|
# Enable debugging tests with --config=debug
|
||||||
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
|
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
|
||||||
|
|
||||||
@ -91,12 +74,6 @@ query --output=label_kind
|
|||||||
# By default, failing tests don't print any output, it goes to the log file
|
# By default, failing tests don't print any output, it goes to the log file
|
||||||
test --test_output=errors
|
test --test_output=errors
|
||||||
|
|
||||||
# Show which actions are run under workers,
|
|
||||||
# and print all the actions running in parallel.
|
|
||||||
# Helps to demonstrate that bazel uses all the cores on the machine.
|
|
||||||
build --experimental_ui
|
|
||||||
test --experimental_ui
|
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# Settings for CircleCI #
|
# Settings for CircleCI #
|
||||||
################################
|
################################
|
||||||
@ -137,14 +114,19 @@ build:remote --platforms=//tools:rbe_ubuntu1604-angular
|
|||||||
|
|
||||||
# Remote instance.
|
# Remote instance.
|
||||||
build:remote --remote_instance_name=projects/internal-200822/instances/default_instance
|
build:remote --remote_instance_name=projects/internal-200822/instances/default_instance
|
||||||
|
build:remote --project_id=internal-200822
|
||||||
|
|
||||||
# Do not accept remote cache.
|
# Remote caching
|
||||||
# We need to understand the security risks of using prior build artifacts.
|
build:remote --remote_cache=remotebuildexecution.googleapis.com
|
||||||
|
# By default, do not accept remote cache, to be set to true for CI based on environment
|
||||||
build:remote --remote_accept_cached=false
|
build:remote --remote_accept_cached=false
|
||||||
|
# By default, do not upload local results to cache, to be set to true for CI based on environment
|
||||||
|
build:remote --remote_upload_local_results=false
|
||||||
|
|
||||||
# Load any settings specific to the current user. Needs to be last statement in this
|
# Build Event Service Configuration
|
||||||
# config, as the user configuration should be able to overwrite flags from this file.
|
build:remote --bes_backend=buildeventservice.googleapis.com
|
||||||
try-import .bazelrc.user
|
build:remote --bes_timeout=30s
|
||||||
|
build:remote --bes_results_url="https://source.cloud.google.com/results/invocations/"
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# NodeJS rules settings
|
# NodeJS rules settings
|
||||||
@ -154,3 +136,37 @@ try-import .bazelrc.user
|
|||||||
# Turn on managed directories feature in Bazel
|
# Turn on managed directories feature in Bazel
|
||||||
# This allows us to avoid installing a second copy of node_modules
|
# This allows us to avoid installing a second copy of node_modules
|
||||||
common --experimental_allow_incremental_repository_updates
|
common --experimental_allow_incremental_repository_updates
|
||||||
|
|
||||||
|
# This option is changed to true in Bazel 0.27 and exposes a possible
|
||||||
|
# regression in Bazel 0.27.0.
|
||||||
|
# Error observed is in npm_package target `//packages/common/locales:package`:
|
||||||
|
# ```
|
||||||
|
# ERROR: /home/circleci/ng/packages/common/locales/BUILD.bazel:13:1: Assembling
|
||||||
|
# npm package packages/common/locales/package failed: No usable spawn strategy found
|
||||||
|
# for spawn with mnemonic SkylarkAction. Your --spawn_strategyor --strategy flags
|
||||||
|
# are probably too strict. Visit https://github.com/bazelbuild/bazel/issues/7480 for
|
||||||
|
# migration advises
|
||||||
|
# ```
|
||||||
|
# Suspect is https://github.com/bazelbuild/rules_nodejs/blob/master/internal/npm_package/npm_package.bzl#L75-L82:
|
||||||
|
# ```
|
||||||
|
# execution_requirements = {
|
||||||
|
# # Never schedule this action remotely because it's not computationally expensive.
|
||||||
|
# # It just copies files into a directory; it's not worth copying inputs and outputs to a remote worker.
|
||||||
|
# # Also don't run it in a sandbox, because it resolves an absolute path to the bazel-out directory
|
||||||
|
# # allowing the .pack and .publish runnables to work with no symlink_prefix
|
||||||
|
# # See https://github.com/bazelbuild/rules_nodejs/issues/187
|
||||||
|
# "local": "1",
|
||||||
|
# },
|
||||||
|
# ```
|
||||||
|
build --incompatible_list_based_execution_strategy_selection=false
|
||||||
|
test --incompatible_list_based_execution_strategy_selection=false
|
||||||
|
run --incompatible_list_based_execution_strategy_selection=false
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# User bazel configuration
|
||||||
|
# NOTE: This needs to be the *last* entry in the config.
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# Load any settings which are specific to the current user. Needs to be *last* statement
|
||||||
|
# in this config, as the user configuration should be able to overwrite flags from this file.
|
||||||
|
try-import .bazelrc.user
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
# Heavily based on https://github.com/StefanScherer/dockerfiles-windows/ images.
|
|
||||||
# Combines the node windowsservercore image with the Bazel Prerequisites (https://docs.bazel.build/versions/master/install-windows.html).
|
|
||||||
# msys install taken from https://github.com/StefanScherer/dockerfiles-windows/issues/30
|
|
||||||
# VS redist install taken from https://github.com/StefanScherer/dockerfiles-windows/blob/master/apache/Dockerfile
|
|
||||||
# The nanoserver image won't work because MSYS2 does not run in it https://github.com/Alexpux/MSYS2-packages/issues/1493
|
|
||||||
|
|
||||||
# Before building this image, you must locally build node-windows:10.13.0-windowsservercore-1803.
|
|
||||||
# Clone https://github.com/StefanScherer/dockerfiles-windows/commit/4ce7101a766b9b880ac262479dd9126b64d656cf and build using
|
|
||||||
# docker build -t node-windows:10.13.0-windowsservercore-1803 --build-arg core=microsoft/windowsservercore:1803 --build-arg target=microsoft/windowsservercore:1803 .
|
|
||||||
FROM node-windows:10.13.0-windowsservercore-1803
|
|
||||||
|
|
||||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
|
||||||
|
|
||||||
# Install 7zip to extract msys2
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe
|
|
||||||
# For some reason the last letter in the destination directory is lost. So '/D=C:\\7zip0' will extract to '/D=C:\\7zip'.
|
|
||||||
RUN Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait
|
|
||||||
|
|
||||||
# Extract msys2
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz
|
|
||||||
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait
|
|
||||||
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait
|
|
||||||
RUN Remove-Item msys2.tar.xz
|
|
||||||
RUN Remove-Item msys2.tar
|
|
||||||
RUN Remove-Item 7z.exe
|
|
||||||
RUN Remove-Item -Recurse 7zip
|
|
||||||
|
|
||||||
# Add MSYS2 to PATH, and set BAZEL_SH
|
|
||||||
RUN [Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
RUN [Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
|
|
||||||
# Install Microsoft Visual C++ Redistributable for Visual Studio 2015
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe' -OutFile vc_redist.x64.exe
|
|
||||||
RUN Start-Process 'c:\\vc_redist.x64.exe' -ArgumentList '/Install', '/Passive', '/NoRestart' -NoNewWindow -Wait
|
|
||||||
RUN Remove-Item vc_redist.x64.exe
|
|
||||||
|
|
||||||
# Add a fix for https://github.com/docker/for-win/issues/2920 as entry point to the container.
|
|
||||||
SHELL ["cmd", "/c"]
|
|
||||||
COPY "fix-msys64.cmd" "C:\\fix-msys64.cmd"
|
|
||||||
ENTRYPOINT cmd /C C:\\fix-msys64.cmd && cmd /c
|
|
||||||
|
|
||||||
CMD ["cmd.exe"]
|
|
@ -1,96 +0,0 @@
|
|||||||
# BuildKite configuration
|
|
||||||
|
|
||||||
This folder contains configuration for the [BuildKite](https://buildkite.com) based CI checks for
|
|
||||||
this repository.
|
|
||||||
|
|
||||||
BuildKite is a CI provider that provides build coordination and reports while we provide the
|
|
||||||
infrastructure.
|
|
||||||
|
|
||||||
CI runs are triggered by new PRs and will show up on the GitHub checks interface, along with the
|
|
||||||
other current CI solutions.
|
|
||||||
|
|
||||||
Currently it is only used for tests on Windows platforms.
|
|
||||||
|
|
||||||
|
|
||||||
## The build pipeline
|
|
||||||
|
|
||||||
BuildKite uses a pipeline for each repository. The `pipeline.yml` file defines pipeline
|
|
||||||
[build steps](https://buildkite.com/docs/pipelines/defining-steps) for this repository.
|
|
||||||
|
|
||||||
Run results can be seen in the GitHub checks interface and in the
|
|
||||||
[pipeline dashboard](https://buildkite.com/angular/angular).
|
|
||||||
|
|
||||||
Although most configuration is done via `pipeline.yml`, some options are only available
|
|
||||||
in the online [pipeline settings](https://buildkite.com/angular/angular/settings).
|
|
||||||
|
|
||||||
|
|
||||||
## Infrastructure
|
|
||||||
|
|
||||||
BuildKite does not provide the host machines where the builds runs, providing instead the
|
|
||||||
[BuildKite Agent](https://buildkite.com/docs/agent/v3) that should be run our own infrastructure.
|
|
||||||
|
|
||||||
|
|
||||||
### Agents
|
|
||||||
|
|
||||||
This agent polls the BuildKite API for builds, runs them, and reports back the results.
|
|
||||||
Agents are the unit of concurrency: each agent can run one build at any given time.
|
|
||||||
Adding agents allows more builds to be ran at the same time.
|
|
||||||
|
|
||||||
Individual agents can have tags, and pipeline steps can target only agents with certain tags via the
|
|
||||||
`agents` field in `pipeline.yml`.
|
|
||||||
For example: agents on Windows machines are tagged as `windows`, and the Windows specific build
|
|
||||||
steps list `windows: true` in their `agents` field.
|
|
||||||
|
|
||||||
You can see the current agent pool, along with their tags, in the
|
|
||||||
[agents list](https://buildkite.com/organizations/angular/agents).
|
|
||||||
|
|
||||||
|
|
||||||
### Our host machines
|
|
||||||
|
|
||||||
We use [Google Cloud](https://cloud.google.com/) as our cloud provider, under the
|
|
||||||
[Angular project](https://console.cloud.google.com/home/dashboard?project=internal-200822).
|
|
||||||
To access this project you need need to be logged in with a Google account that's a member of
|
|
||||||
team@angular.io.
|
|
||||||
For googlers this may be your google.com account, for others it is an angular.io account.
|
|
||||||
|
|
||||||
In this project we have a number of Windows VMs running, each of them with several agents.
|
|
||||||
The `provision-windows-buildkite.ps1` file contains instructions on how to create new host VMs that
|
|
||||||
are fully configured to run the BuildKite agents as services.
|
|
||||||
|
|
||||||
Our pipeline uses [docker-buildkite-plugin](https://github.com/buildkite-plugins/docker-buildkite-plugin)
|
|
||||||
to run build steps inside docker containers.
|
|
||||||
This way we achieve isolation and hermeticity.
|
|
||||||
|
|
||||||
The `Dockerfile` file describes a custom Docker image that includes NodeJs, Yarn, and the Bazel
|
|
||||||
pre-requisites on Windows.
|
|
||||||
|
|
||||||
To upload a new version of the docker image, follow any build instructions in `Dockerfile` and then
|
|
||||||
run `docker build -t angular/node-bazel-windows:NEW_VERSION`, followed by
|
|
||||||
`docker push angular/node-bazel-windows:NEW_VERSION`.
|
|
||||||
After being pushed it should be available online, and you can use the new version in `pipeline.yml`.
|
|
||||||
|
|
||||||
|
|
||||||
## Caretaker
|
|
||||||
|
|
||||||
BuildKite status can be found at https://www.buildkitestatus.com/.
|
|
||||||
|
|
||||||
Issues related to the BuildKite setup should be escalated to the Tools Team via the current
|
|
||||||
caretaker, followed by Alex Eagle and Filipe Silva.
|
|
||||||
|
|
||||||
Support requests should be submitted via email to support@buildkite.com and cc Igor, Misko, Alex,
|
|
||||||
Jeremy and Manu
|
|
||||||
|
|
||||||
|
|
||||||
## Rollout strategy
|
|
||||||
|
|
||||||
At the moment our BuildKite CI uses 1 host VM running 4 agents, thus being capable of 4 concurrent
|
|
||||||
builds.
|
|
||||||
The only test running is `bazel test //tools/ts-api-guardian:all`, and the PR check is not
|
|
||||||
mandatory.
|
|
||||||
|
|
||||||
In the future we should add cache support to speed up the initial `yarn` install, and also Bazel
|
|
||||||
remote caching to speed up Bazel builds.
|
|
||||||
|
|
||||||
After the current setup is verified as stable and reliable the GitHub PR check can become mandatory.
|
|
||||||
|
|
||||||
The tests ran should also be expanded to cover most, if not all, of the Bazel tests.
|
|
@ -1,6 +0,0 @@
|
|||||||
@echo off
|
|
||||||
REM Fix for https://github.com/docker/for-win/issues/2920
|
|
||||||
REM echo "Fixing msys64 folder..."
|
|
||||||
REM Touch all .dll files inside C:\msys64\
|
|
||||||
forfiles /p C:\msys64\ /s /m *.dll /c "cmd /c Copy /B @path+,, >NUL"
|
|
||||||
REM echo "Fixed msys64 folder."
|
|
@ -1,10 +0,0 @@
|
|||||||
steps:
|
|
||||||
- label: windows-test
|
|
||||||
commands:
|
|
||||||
- "yarn install --frozen-lockfile --non-interactive --network-timeout 100000"
|
|
||||||
- "yarn bazel test //tools/ts-api-guardian:all --noshow_progress"
|
|
||||||
plugins:
|
|
||||||
- docker#v2.1.0:
|
|
||||||
image: "filipesilva/node-bazel-windows:0.0.2"
|
|
||||||
agents:
|
|
||||||
windows: true
|
|
@ -1,94 +0,0 @@
|
|||||||
# PowerShell script to provision a Windows Server with BuildKite
|
|
||||||
# This script follows https://buildkite.com/docs/agent/v3/windows.
|
|
||||||
|
|
||||||
# Instructions
|
|
||||||
|
|
||||||
# VM creation:
|
|
||||||
# In Google Cloud Platform, create a Compute Engine instance.
|
|
||||||
# We recommend machine type n1-standard-16 (16 vCPUs, 60 GB memory).
|
|
||||||
# Use a recent windows boot disk with container support such as
|
|
||||||
# "Windows Server version 1803 Datacenter Core for Containers", and add a 128GB SSD disk.
|
|
||||||
# Give it a name, then click "Create".
|
|
||||||
|
|
||||||
# VM setup:
|
|
||||||
# In the Compute Engine menu, select "VM Instances". Click on the VM name you chose before.
|
|
||||||
# Click "Set Windows Password" to choose a username and password.
|
|
||||||
# Click RDP to open a remote desktop via browser, using the username and password.
|
|
||||||
# In the Windows command prompt start an elevated powershell by inputing
|
|
||||||
# "powershell -Command "Start-Process PowerShell -Verb RunAs" followed by Enter.
|
|
||||||
# Download and execute this script from GitHub, passing the token (mandatory), tags (optional)
|
|
||||||
# and number of agents (optional) as args:
|
|
||||||
# ```
|
|
||||||
# Invoke-WebRequest -Uri https://raw.githubusercontent.com/angular/angular/master/.buildkite/provision-windows-buildkite.ps1 -OutFile provision.ps1
|
|
||||||
# .\provision.ps1 -token "MY_TOKEN" -tags "windows=true,another_tag=true" -agents 4
|
|
||||||
# ```
|
|
||||||
# The VM should restart and be fully configured.
|
|
||||||
|
|
||||||
# Creating extra VMs
|
|
||||||
# You can create an image of the current VM by following the instructions below.
|
|
||||||
# https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image
|
|
||||||
# Then create a new VM and choose "Custom images".
|
|
||||||
|
|
||||||
|
|
||||||
# Script proper.
|
|
||||||
|
|
||||||
# Get the token and tags from arguments.
|
|
||||||
param (
|
|
||||||
[Parameter(Mandatory=$true)][string]$token,
|
|
||||||
[string]$tags = "",
|
|
||||||
[Int]$agents = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
# Allow HTTPS
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
|
|
||||||
|
|
||||||
# Helper to add to PATH.
|
|
||||||
# Will take current PATH so avoid running it after anything to modifies only the powershell session path.
|
|
||||||
function Add-Path ([string]$newPathItem) {
|
|
||||||
$Env:Path+= ";" + $newPathItem + ";"
|
|
||||||
[Environment]::SetEnvironmentVariable("Path",$env:Path, [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install Git for Windows
|
|
||||||
Write-Host "Installing Git for Windows."
|
|
||||||
Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.19.1.windows.1/Git-2.19.1-64-bit.exe -OutFile git.exe
|
|
||||||
.\git.exe /VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh" /DIR="C:\git"
|
|
||||||
Add-Path "C:\git\bin"
|
|
||||||
# Sleep for 15s while git is installed. Trying to remove the git.exe before it finishes install causes an error.
|
|
||||||
Start-Sleep -s 15
|
|
||||||
Remove-Item git.exe
|
|
||||||
|
|
||||||
# Download NSSM (https://nssm.cc/) to run the BuildKite agent as a service.
|
|
||||||
Write-Host "Downloading NSSM."
|
|
||||||
Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -OutFile nssm.zip
|
|
||||||
Expand-Archive -Path nssm.zip -DestinationPath C:\nssm
|
|
||||||
Add-Path "C:\nssm\nssm-2.24-101-g897c7ad\win64"
|
|
||||||
Remove-Item nssm.zip
|
|
||||||
|
|
||||||
# Run the BuildKite agent install script
|
|
||||||
Write-Host "Installing BuildKite agent."
|
|
||||||
$env:buildkiteAgentToken = $token
|
|
||||||
$env:buildkiteAgentTags = $tags
|
|
||||||
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
||||||
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/buildkite/agent/master/install.ps1'))
|
|
||||||
|
|
||||||
# Configure the BuildKite agent clone and timestamp behavior
|
|
||||||
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ngit-clone-flags=--config core.autocrlf=input --config core.eol=lf --config core.longpaths=true --config core.symlinks=true`n"
|
|
||||||
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ntimestamp-lines=true`n"
|
|
||||||
|
|
||||||
# Register the BuildKite agent service using NSSM, so that it persists through restarts and is
|
|
||||||
# restarted if the process dies.
|
|
||||||
for ($i=1; $i -le $agents; $i++)
|
|
||||||
{
|
|
||||||
$agentName = "buildkite-agent-$i"
|
|
||||||
Write-Host "Registering $agentName as a service."
|
|
||||||
nssm.exe install $agentName "C:\buildkite-agent\bin\buildkite-agent.exe" "start"
|
|
||||||
nssm.exe set $agentName AppStdout "C:\buildkite-agent\$agentName.log"
|
|
||||||
nssm.exe set $agentName AppStderr "C:\buildkite-agent\$agentName.log"
|
|
||||||
nssm.exe status $agentName
|
|
||||||
nssm.exe start $agentName
|
|
||||||
nssm.exe status $agentName
|
|
||||||
}
|
|
||||||
|
|
||||||
# Restart the machine.
|
|
||||||
Restart-Computer
|
|
@ -28,3 +28,14 @@ test --flaky_test_attempts=2
|
|||||||
|
|
||||||
# More details on failures
|
# More details on failures
|
||||||
build --verbose_failures=true
|
build --verbose_failures=true
|
||||||
|
|
||||||
|
# We have seen some flakiness in using TS workers on CircleCI
|
||||||
|
# https://angular-team.slack.com/archives/C07DT5M6V/p1562693245183400
|
||||||
|
# > failures like `ERROR: /home/circleci/ng/packages/core/test/BUILD.bazel:5:1:
|
||||||
|
# > Compiling TypeScript (devmode) //packages/core/test:test_lib failed: Worker process did not return a WorkResponse:`
|
||||||
|
# > I saw that issue a couple times today.
|
||||||
|
# > Example job: https://circleci.com/gh/angular/angular/385517
|
||||||
|
# We expect that TypeScript compilations will parallelize wider than the number of local cores anyway
|
||||||
|
# so we should saturate remote workers with TS compilations
|
||||||
|
build --strategy=TypeScriptCompile=standalone
|
||||||
|
build --strategy=AngularTemplateCompile=standalone
|
||||||
|
@ -58,7 +58,7 @@ var_5: &setup_bazel_remote_execution
|
|||||||
# cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734
|
# cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734
|
||||||
openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials
|
openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials
|
||||||
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV
|
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV
|
||||||
sudo bash -c "echo 'build --config=remote' >> /etc/bazel.bazelrc"
|
./.circleci/setup-rbe.sh .bazelrc.user
|
||||||
|
|
||||||
# Settings common to each job
|
# Settings common to each job
|
||||||
var_6: &job_defaults
|
var_6: &job_defaults
|
||||||
@ -106,7 +106,7 @@ var_10: &restore_cache
|
|||||||
|
|
||||||
# Branch filter that can be specified for jobs that should only run on publish branches
|
# Branch filter that can be specified for jobs that should only run on publish branches
|
||||||
# (e.g. master or the patch branch)
|
# (e.g. master or the patch branch)
|
||||||
var_12: &publish_branches_filter
|
var_11: &publish_branches_filter
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
@ -117,10 +117,35 @@ var_12: &publish_branches_filter
|
|||||||
# `build-npm-packages`.
|
# `build-npm-packages`.
|
||||||
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
|
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
|
||||||
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
|
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
|
||||||
var_13: &attach_workspace
|
var_12: &attach_workspace
|
||||||
attach_workspace:
|
attach_workspace:
|
||||||
at: ~/
|
at: ~/
|
||||||
|
|
||||||
|
var_13: ¬ify_caretaker_on_fail
|
||||||
|
run:
|
||||||
|
when: on_fail
|
||||||
|
name: Notify caretaker about failure
|
||||||
|
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||||
|
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||||
|
command: |
|
||||||
|
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
|
||||||
|
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_CARETAKER_WEBHOOK_URL
|
||||||
|
|
||||||
|
var_14: ¬ify_dev_infra_on_fail
|
||||||
|
run:
|
||||||
|
when: on_fail
|
||||||
|
name: Notify dev-infra about failure
|
||||||
|
# `$SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||||
|
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||||
|
command: |
|
||||||
|
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
|
||||||
|
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
|
||||||
|
|
||||||
|
# Cache key for the Material unit tests job. **Note** when updating the SHA in the cache keys,
|
||||||
|
# also update the SHA for the "MATERIAL_REPO_COMMIT" environment variable.
|
||||||
|
var_15: &material_unit_tests_cache_key v4-angular-material-701302dc482d7e4b77990b24e3b5ab330bbf1aa5
|
||||||
|
var_16: &material_unit_tests_cache_key_short v4-angular-material
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
@ -170,11 +195,16 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
|
||||||
- setup_remote_docker
|
|
||||||
# Setup remote execution and run RBE-compatible tests.
|
# Setup remote execution and run RBE-compatible tests.
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
||||||
|
- run: mkdir ~/testlogs
|
||||||
|
- run: cp -Lr dist/testlogs/* ~/testlogs
|
||||||
|
- store_test_results:
|
||||||
|
# Bazel always writes test.xml files under this directory
|
||||||
|
path: ~/testlogs
|
||||||
|
- store_artifacts:
|
||||||
|
path: ~/testlogs
|
||||||
|
|
||||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||||
test_ivy_aot:
|
test_ivy_aot:
|
||||||
@ -184,8 +214,6 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
|
||||||
- setup_remote_docker
|
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
||||||
@ -212,6 +240,11 @@ jobs:
|
|||||||
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
|
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
|
||||||
destination: core/todo/bundle.br
|
destination: core/todo/bundle.br
|
||||||
|
|
||||||
|
# This job is currently a PoC for running tests on SauceLabs via bazel. It runs a subset of the
|
||||||
|
# tests in `legacy-unit-tests-saucelabs` (see
|
||||||
|
# [BUILD.bazel](https://github.com/angular/angular/blob/ef44f51d5/BUILD.bazel#L66-L92)).
|
||||||
|
#
|
||||||
|
# NOTE: This is currently limited to master builds only. See the `default_workflow` configuration.
|
||||||
test_saucelabs_bazel:
|
test_saucelabs_bazel:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
|
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
|
||||||
@ -240,6 +273,7 @@ jobs:
|
|||||||
# //packages/forms/test:web_test_sauce TIMEOUT in 315.0s
|
# //packages/forms/test:web_test_sauce TIMEOUT in 315.0s
|
||||||
- run: yarn bazel test --config=saucelabs //:test_web_all
|
- run: yarn bazel test --config=saucelabs //:test_web_all
|
||||||
- run: ./scripts/saucelabs/stop-tunnel.sh
|
- run: ./scripts/saucelabs/stop-tunnel.sh
|
||||||
|
- *notify_dev_infra_on_fail
|
||||||
|
|
||||||
test_aio:
|
test_aio:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -259,6 +293,8 @@ jobs:
|
|||||||
- run: yarn --cwd aio e2e --configuration=ci
|
- run: yarn --cwd aio e2e --configuration=ci
|
||||||
# Run PWA-score tests
|
# Run PWA-score tests
|
||||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
|
# Run accessibility tests
|
||||||
|
- run: yarn --cwd aio test-a11y-score-localhost
|
||||||
# Check the bundle sizes.
|
# Check the bundle sizes.
|
||||||
- run: yarn --cwd aio payload-size
|
- run: yarn --cwd aio payload-size
|
||||||
# Run unit tests for Firebase redirects
|
# Run unit tests for Firebase redirects
|
||||||
@ -293,8 +329,7 @@ jobs:
|
|||||||
# Run PWA-score tests
|
# Run PWA-score tests
|
||||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
# Check the bundle sizes.
|
# Check the bundle sizes.
|
||||||
# Temporary disabled due to a problem with patch branch (8.0.x)
|
- run: yarn --cwd aio payload-size aio-local
|
||||||
# - run: yarn --cwd aio payload-size aio-local
|
|
||||||
|
|
||||||
test_aio_local_ivy:
|
test_aio_local_ivy:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -313,8 +348,7 @@ jobs:
|
|||||||
# Run PWA-score tests
|
# Run PWA-score tests
|
||||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
# Check the bundle sizes.
|
# Check the bundle sizes.
|
||||||
# Temporary disabled due to a problem with patch branch (8.0.x)
|
- run: yarn --cwd aio payload-size aio-local-ivy
|
||||||
# - run: yarn --cwd aio payload-size aio-local-ivy
|
|
||||||
|
|
||||||
test_aio_tools:
|
test_aio_tools:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -369,7 +403,7 @@ jobs:
|
|||||||
# Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
|
# Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
|
||||||
# Since the parallelism is set to "3", there will be three parallel CircleCI containers
|
# Since the parallelism is set to "3", there will be three parallel CircleCI containers
|
||||||
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
|
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
|
||||||
- run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
|
- run: yarn --cwd aio example-e2e --setup --local --ivy --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
|
||||||
|
|
||||||
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
|
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
|
||||||
aio_preview:
|
aio_preview:
|
||||||
@ -417,8 +451,6 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
|
||||||
- setup_remote_docker
|
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
- run: scripts/build-packages-dist.sh
|
- run: scripts/build-packages-dist.sh
|
||||||
@ -445,8 +477,6 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
|
||||||
- setup_remote_docker
|
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
- run: scripts/build-ivy-npm-packages.sh
|
- run: scripts/build-ivy-npm-packages.sh
|
||||||
@ -529,12 +559,8 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Run tests against https://angular.io/
|
name: Run tests against https://angular.io/
|
||||||
command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE
|
command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||||
- run:
|
- *notify_caretaker_on_fail
|
||||||
name: Notify caretaker about failure
|
- *notify_dev_infra_on_fail
|
||||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
|
||||||
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
|
||||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL'
|
|
||||||
when: on_fail
|
|
||||||
|
|
||||||
aio_monitoring_next:
|
aio_monitoring_next:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -548,12 +574,8 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Run tests against https://next.angular.io/
|
name: Run tests against https://next.angular.io/
|
||||||
command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
|
command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||||
- run:
|
- *notify_caretaker_on_fail
|
||||||
name: Notify caretaker about failure
|
- *notify_dev_infra_on_fail
|
||||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
|
||||||
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
|
||||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL'
|
|
||||||
when: on_fail
|
|
||||||
|
|
||||||
legacy-unit-tests-saucelabs:
|
legacy-unit-tests-saucelabs:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -598,44 +620,55 @@ jobs:
|
|||||||
resource_class: xlarge
|
resource_class: xlarge
|
||||||
docker:
|
docker:
|
||||||
- image: *browsers_docker_image
|
- image: *browsers_docker_image
|
||||||
# The Material unit tests support splitting the browsers across multiple CircleCI
|
|
||||||
# instances. Since by default this job launches two browsers, we run each browser
|
|
||||||
# in its own container instance.
|
|
||||||
# https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L107-L110
|
|
||||||
parallelism: 2
|
|
||||||
environment:
|
|
||||||
# The Material unit tests also support launching the same browser multiple times by
|
|
||||||
# sharding individual specs across the defined multiple instances.
|
|
||||||
# See: https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L113-L116
|
|
||||||
KARMA_PARALLEL_BROWSERS: 3
|
|
||||||
steps:
|
steps:
|
||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- run:
|
# Although RBE is configured below for the Material repo, also setup RBE in the Angular repo
|
||||||
name: "Cloning Material repository"
|
# to provision Angular's GCP token into the environment variables.
|
||||||
command: ./scripts/ci/clone_angular_material_repo.sh
|
- *setup_bazel_remote_execution
|
||||||
|
# Restore the cache before cloning the repository because the clone script re-uses
|
||||||
|
# the restored repository if present. This reduces the amount of times the components
|
||||||
|
# repository needs to be cloned (this is slow and increases based on commits in the repo).
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
|
|
||||||
# It needs to be hardcoded here, because env variables interpolation is not supported.
|
|
||||||
keys:
|
keys:
|
||||||
- v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
|
- *material_unit_tests_cache_key
|
||||||
- v2-angular-material-
|
- *material_unit_tests_cache_key_short
|
||||||
- run:
|
- run:
|
||||||
|
name: "Fetching Material repository"
|
||||||
|
command: ./scripts/ci/clone_angular_material_repo.sh
|
||||||
|
- run:
|
||||||
|
# Run yarn install to fetch the Bazel binaries as used in the Material repo.
|
||||||
name: Installing Material dependencies.
|
name: Installing Material dependencies.
|
||||||
command: yarn --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive
|
command: yarn --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive
|
||||||
# Save the cache before we run the Material unit tests script. This is necessary
|
|
||||||
# because we don't want to cache the node modules which have been modified to contain
|
|
||||||
# the attached Ivy package output.
|
|
||||||
- save_cache:
|
- save_cache:
|
||||||
|
key: *material_unit_tests_cache_key
|
||||||
|
paths:
|
||||||
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
|
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
|
||||||
# It needs to be hardcoded here, because env variables interpolation is not supported.
|
# It needs to be hardcoded here, because env variables interpolation is not supported.
|
||||||
key: v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
|
- "/tmp/material2"
|
||||||
paths:
|
- run:
|
||||||
- "/tmp/material2/node_modules"
|
name: "Setup Bazel RBE remote execution in Material repo"
|
||||||
|
command: |
|
||||||
|
./.circleci/setup-rbe.sh "${MATERIAL_REPO_TMP_DIR}/.bazelrc.user"
|
||||||
- run:
|
- run:
|
||||||
name: "Running Material unit tests"
|
name: "Running Material unit tests"
|
||||||
command: ./scripts/ci/run_angular_material_unit_tests.sh
|
command: ./scripts/ci/run_angular_material_unit_tests.sh
|
||||||
|
|
||||||
|
test_zonejs:
|
||||||
|
<<: *job_defaults
|
||||||
|
steps:
|
||||||
|
- *attach_workspace
|
||||||
|
- *init_environment
|
||||||
|
# Install
|
||||||
|
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
|
||||||
|
# Run zone.js tools tests
|
||||||
|
- run: yarn --cwd packages/zone.js promisetest
|
||||||
|
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||||
|
- run: yarn bazel build //packages/zone.js:npm_package &&
|
||||||
|
cp dist/bin/packages/zone.js/npm_package/dist/zone-mix.js ./packages/zone.js/test/extra/ &&
|
||||||
|
cp dist/bin/packages/zone.js/npm_package/dist/zone-patch-electron.js ./packages/zone.js/test/extra/ &&
|
||||||
|
yarn --cwd packages/zone.js electrontest
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
default_workflow:
|
default_workflow:
|
||||||
@ -656,18 +689,28 @@ workflows:
|
|||||||
- build-ivy-npm-packages:
|
- build-ivy-npm-packages:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
- test_aio:
|
- legacy-misc-tests:
|
||||||
|
requires:
|
||||||
|
- build-npm-packages
|
||||||
|
- legacy-unit-tests-saucelabs:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
- legacy-unit-tests-saucelabs:
|
- test_saucelabs_bazel:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
|
# This job is currently a PoC and a subset of `legacy-unit-tests-saucelabs`. Running on
|
||||||
|
# master only to avoid wasting resources.
|
||||||
|
#
|
||||||
|
# TODO: Run this job on all branches (including PRs) as soon as it is not a PoC.
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only: master
|
||||||
|
- test_aio:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
- deploy_aio:
|
- deploy_aio:
|
||||||
requires:
|
requires:
|
||||||
- test_aio
|
- test_aio
|
||||||
- legacy-misc-tests:
|
|
||||||
requires:
|
|
||||||
- build-npm-packages
|
|
||||||
- test_aio_local:
|
- test_aio_local:
|
||||||
requires:
|
requires:
|
||||||
- build-npm-packages
|
- build-npm-packages
|
||||||
@ -720,22 +763,9 @@ workflows:
|
|||||||
- material-unit-tests:
|
- material-unit-tests:
|
||||||
requires:
|
requires:
|
||||||
- build-ivy-npm-packages
|
- build-ivy-npm-packages
|
||||||
|
- test_zonejs:
|
||||||
saucelabs_tests:
|
|
||||||
jobs:
|
|
||||||
- setup
|
|
||||||
- test_saucelabs_bazel:
|
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
triggers:
|
|
||||||
- schedule:
|
|
||||||
# Runs the Saucelabs legacy tests every hour. We still want to run Saucelabs
|
|
||||||
# frequently as the caretaker needs up-to-date results when merging PRs or creating
|
|
||||||
# a new release. Also we primarily moved the Saucelabs job into a cronjob that doesn't
|
|
||||||
# run for PRs, in order to ensure that PRs are not affected by Saucelabs flakiness or
|
|
||||||
# incidents. This is still guaranteed (even if we run the job every hour).
|
|
||||||
cron: "0 * * * *"
|
|
||||||
filters: *publish_branches_filter
|
|
||||||
|
|
||||||
aio_monitoring:
|
aio_monitoring:
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -77,7 +77,9 @@ setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
|||||||
# their separate build setups.
|
# their separate build setups.
|
||||||
setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2"
|
setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2"
|
||||||
setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git"
|
setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git"
|
||||||
setPublicVar MATERIAL_REPO_BRANCH "ivy-2019"
|
setPublicVar MATERIAL_REPO_BRANCH "master"
|
||||||
|
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI "config.yml".
|
||||||
|
setPublicVar MATERIAL_REPO_COMMIT "701302dc482d7e4b77990b24e3b5ab330bbf1aa5"
|
||||||
|
|
||||||
# Source `$BASH_ENV` to make the variables available immediately.
|
# Source `$BASH_ENV` to make the variables available immediately.
|
||||||
source $BASH_ENV;
|
source $BASH_ENV;
|
||||||
|
Binary file not shown.
20
.circleci/setup-rbe.sh
Executable file
20
.circleci/setup-rbe.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u -e -o pipefail
|
||||||
|
|
||||||
|
# The path of the .bazelrc.user file to update should be passed as first parameter to this script.
|
||||||
|
# This allows to setup RBE for both the Angular repo and the Material repo.
|
||||||
|
bazelrc_user="$1"
|
||||||
|
|
||||||
|
echo "Writing RBE configuration to ${bazelrc_user}"
|
||||||
|
|
||||||
|
touch ${bazelrc_user}
|
||||||
|
echo -e 'build --config=remote\n' >> ${bazelrc_user}
|
||||||
|
echo -e 'build:remote --remote_accept_cached=true\n' >> ${bazelrc_user}
|
||||||
|
echo "Reading from remote cache for bazel remote jobs."
|
||||||
|
if [[ "$CI_PULL_REQUEST" == "false" ]]; then
|
||||||
|
echo -e 'build:remote --remote_upload_local_results=true\n' >> ${bazelrc_user}
|
||||||
|
echo "Uploading local build results to remote cache."
|
||||||
|
else
|
||||||
|
echo -e 'build:remote --remote_upload_local_results=false\n' >> ${bazelrc_user}
|
||||||
|
echo "Not uploading local build results to remote cache."
|
||||||
|
fi
|
@ -1,3 +1,5 @@
|
|||||||
|
# escape=`
|
||||||
|
|
||||||
ARG core=mcr.microsoft.com/windows/servercore:1809
|
ARG core=mcr.microsoft.com/windows/servercore:1809
|
||||||
ARG target=mcr.microsoft.com/powershell:windowsservercore-1809
|
ARG target=mcr.microsoft.com/powershell:windowsservercore-1809
|
||||||
|
|
||||||
@ -10,57 +12,57 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
|
|||||||
|
|
||||||
ENV GPG_VERSION 2.3.4
|
ENV GPG_VERSION 2.3.4
|
||||||
|
|
||||||
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; \
|
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; `
|
||||||
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait
|
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait
|
||||||
|
|
||||||
RUN @( \
|
RUN @( `
|
||||||
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', \
|
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', `
|
||||||
'FD3A5288F042B6850C66B31F09FE44734EB7990E', \
|
'FD3A5288F042B6850C66B31F09FE44734EB7990E', `
|
||||||
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', \
|
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', `
|
||||||
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', \
|
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', `
|
||||||
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', \
|
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', `
|
||||||
'B9AE9905FFD7803F25714661B63B535A4C206CA9', \
|
'B9AE9905FFD7803F25714661B63B535A4C206CA9', `
|
||||||
'77984A986EBC2AA786BC0F66B01FBB92821C587A', \
|
'77984A986EBC2AA786BC0F66B01FBB92821C587A', `
|
||||||
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', \
|
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', `
|
||||||
'4ED778F539E3634C779C87C6D7062848A1AB005C', \
|
'4ED778F539E3634C779C87C6D7062848A1AB005C', `
|
||||||
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', \
|
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', `
|
||||||
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' \
|
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' `
|
||||||
) | foreach { \
|
) | foreach { `
|
||||||
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; \
|
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; `
|
||||||
}
|
}
|
||||||
|
|
||||||
ENV NODE_VERSION=$node_version
|
ENV NODE_VERSION=$node_version
|
||||||
|
|
||||||
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; \
|
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; `
|
||||||
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
|
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
|
||||||
|
|
||||||
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \
|
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; `
|
||||||
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; \
|
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; `
|
||||||
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; \
|
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; `
|
||||||
Expand-Archive node.zip -DestinationPath C:\ ; \
|
Expand-Archive node.zip -DestinationPath C:\ ; `
|
||||||
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
|
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
|
||||||
|
|
||||||
ENV YARN_VERSION=$yarn_version
|
ENV YARN_VERSION=$yarn_version
|
||||||
|
|
||||||
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \
|
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||||
Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; \
|
Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; `
|
||||||
$sig = Get-AuthenticodeSignature yarn.msi ; \
|
$sig = Get-AuthenticodeSignature yarn.msi ; `
|
||||||
if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; \
|
if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; `
|
||||||
Write-Output $sig.SignerCertificate.Thumbprint ; \
|
Write-Output $sig.SignerCertificate.Thumbprint ; `
|
||||||
if (@( \
|
if (@( `
|
||||||
'7E253367F8A102A91D04829E37F3410F14B68A5F', \
|
'7E253367F8A102A91D04829E37F3410F14B68A5F', `
|
||||||
'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' \
|
'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' `
|
||||||
) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; \
|
) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; `
|
||||||
Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait
|
Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait
|
||||||
|
|
||||||
ENV GIT_VERSION 2.20.1
|
ENV GIT_VERSION 2.20.1
|
||||||
ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip
|
ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip
|
||||||
ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c
|
ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c
|
||||||
|
|
||||||
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \
|
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||||
Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; \
|
Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; `
|
||||||
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; \
|
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; `
|
||||||
Expand-Archive git.zip -DestinationPath C:\git; \
|
Expand-Archive git.zip -DestinationPath C:\git; `
|
||||||
Remove-Item git.zip
|
Remove-Item git.zip
|
||||||
|
|
||||||
FROM $target as baseimage
|
FROM $target as baseimage
|
||||||
@ -80,24 +82,45 @@ FROM baseimage
|
|||||||
|
|
||||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||||
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; \
|
# Install Bazel prereqs on Windows (https://docs.bazel.build/versions/master/install-windows.html)
|
||||||
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; \
|
|
||||||
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; \
|
|
||||||
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; \
|
|
||||||
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; \
|
|
||||||
Remove-Item msys2.tar.xz; \
|
|
||||||
Remove-Item msys2.tar; \
|
|
||||||
Remove-Item 7z.exe; \
|
|
||||||
Remove-Item -Recurse 7zip; \
|
|
||||||
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); \
|
|
||||||
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine); \
|
|
||||||
Invoke-WebRequest -UseBasicParsing 'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe' -OutFile vc_redist.x64.exe; \
|
|
||||||
Start-Process 'c:\\vc_redist.x64.exe' -ArgumentList '/Install', '/Passive', '/NoRestart' -NoNewWindow -Wait; \
|
|
||||||
Remove-Item vc_redist.x64.exe
|
|
||||||
|
|
||||||
# Add a fix for https://github.com/docker/for-win/issues/2920 as entry point to the container.
|
# Install MSYS2
|
||||||
SHELL ["cmd", "/c"]
|
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; `
|
||||||
COPY "fix-msys64.cmd" "C:\\fix-msys64.cmd"
|
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; `
|
||||||
ENTRYPOINT cmd /C C:\\fix-msys64.cmd && cmd /c
|
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; `
|
||||||
|
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; `
|
||||||
|
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; `
|
||||||
|
Remove-Item msys2.tar.xz; `
|
||||||
|
Remove-Item msys2.tar; `
|
||||||
|
Remove-Item 7z.exe; `
|
||||||
|
Remove-Item -Recurse 7zip; `
|
||||||
|
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); `
|
||||||
|
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
|
||||||
|
|
||||||
|
# Install MSYS2 packages
|
||||||
|
RUN C:\msys64\usr\bin\bash.exe -l -c \"pacman --needed --noconfirm -S zip unzip patch diffutils git\"
|
||||||
|
|
||||||
|
# Install VS Build Tools (required to build C++ targets)
|
||||||
|
RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; `
|
||||||
|
# Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M
|
||||||
|
setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; `
|
||||||
|
Start-Process vs_BuildTools.exe `
|
||||||
|
-ArgumentList `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Workload.VCTools', `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', `
|
||||||
|
'--add', 'Microsoft.Component.VC.Runtime.UCRTSDK', `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Component.Windows10SDK.17763', `
|
||||||
|
'--quiet', '--norestart', '--nocache' `
|
||||||
|
-NoNewWindow -Wait; `
|
||||||
|
Remove-Item -Force vs_buildtools.exe; `
|
||||||
|
Remove-Item -Force -Recurse \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\"; `
|
||||||
|
Remove-Item -Force -Recurse ${Env:TEMP}\*; `
|
||||||
|
Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; `
|
||||||
|
[Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine)
|
||||||
|
|
||||||
|
# Install Python (required to build Python targets)
|
||||||
|
RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; `
|
||||||
|
Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; `
|
||||||
|
Remove-Item -Force python-3.5.1.exe
|
||||||
|
|
||||||
CMD ["cmd.exe"]
|
CMD ["cmd.exe"]
|
@ -2,11 +2,17 @@
|
|||||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||||
# See documentation in /docs/BAZEL.md
|
# See documentation in /docs/BAZEL.md
|
||||||
|
|
||||||
# Save downloaded repositories in a location that can be cached by CodeFresh and shared between
|
# Save built files and downloaded repositories in a location that can be cached by CodeFresh and
|
||||||
# builds. This helps speed up the analysis time significantly with Bazel managed node dependencies
|
# shared between builds. This helps speed up the analysis time significantly with Bazel managed node
|
||||||
# on the CI.
|
# dependencies on the CI.
|
||||||
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
|
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
|
||||||
build --repository_cache=C:/codefresh/volume/bazel_repository_cache
|
build --repository_cache=C:/codefresh/volume/bazel_repository_cache
|
||||||
|
# Setting the output_base to a Docker volume is currently broken because of a Docker bug on Windows:
|
||||||
|
# https://github.com/moby/moby/issues/37024
|
||||||
|
# This affects Bazel because bazel_output_base\external\bazel_tools is an absolute path junction.
|
||||||
|
# When its fixed we can uncomment this line, and use a different output_base for Ivy tests (they
|
||||||
|
# use a separate compiler and destructively replace the cache).
|
||||||
|
# startup --output_base=C:/codefresh/volume/bazel_output_base
|
||||||
|
|
||||||
# Don't be spammy in the logs
|
# Don't be spammy in the logs
|
||||||
# TODO(gmagolan): Hide progress again once build performance improves
|
# TODO(gmagolan): Hide progress again once build performance improves
|
||||||
@ -23,20 +29,10 @@ build --announce_rc
|
|||||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||||
# Limit Bazel to consuming resources that fit in CodeFresh VMs
|
# Limit Bazel to consuming resources that fit in CodeFresh VMs
|
||||||
# TODO(filipesilva): determine the correct memory limit
|
# TODO(filipesilva): determine the correct memory limit
|
||||||
build --local_resources=8000,8.0,1.0
|
build --local_resources=10240,8.0,1.0
|
||||||
|
|
||||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||||
test --flaky_test_attempts=2
|
test --flaky_test_attempts=2
|
||||||
|
|
||||||
# More details on failures
|
# More details on failures
|
||||||
build --verbose_failures=true
|
build --verbose_failures=true
|
||||||
|
|
||||||
# Include PATH in Windows build/tests
|
|
||||||
# https://github.com/bazelbuild/rules_typescript/pull/356
|
|
||||||
build --action_env=PATH
|
|
||||||
test --action_env=PATH --test_env=PATH
|
|
||||||
|
|
||||||
# Exclude tests known to not work on Windows.
|
|
||||||
|
|
||||||
# Chrome web tests are currently broken.
|
|
||||||
test --test_tag_filters=-browser:chromium-local
|
|
||||||
|
@ -2,6 +2,7 @@ version: '1.0'
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
BuildImage:
|
BuildImage:
|
||||||
|
title: Build Docker image
|
||||||
type: build
|
type: build
|
||||||
image_name: node-bazel-windows
|
image_name: node-bazel-windows
|
||||||
working_directory: ./.codefresh
|
working_directory: ./.codefresh
|
||||||
@ -12,7 +13,7 @@ steps:
|
|||||||
dockerfile: ./Dockerfile.win-1809
|
dockerfile: ./Dockerfile.win-1809
|
||||||
|
|
||||||
RunTests:
|
RunTests:
|
||||||
title: Run Example
|
title: Run Bazel tests
|
||||||
image: ${{BuildImage}}
|
image: ${{BuildImage}}
|
||||||
commands:
|
commands:
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
@ -20,7 +21,8 @@ steps:
|
|||||||
# Add Bazel CI config
|
# Add Bazel CI config
|
||||||
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
|
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
|
||||||
# Run tests
|
# Run tests
|
||||||
- yarn bazel test //tools/ts-api-guardian:all //packages/language-service/test //packages/compiler/test //packages/compiler-cli/test:ngc //packages/compiler-cli/test/ngtsc:ngtsc
|
# At the moment 'browser:chromium-local' are broken in CI while locally they work
|
||||||
- yarn test-ivy-aot //packages/animations/test //packages/common/test //packages/forms/test //packages/http/test //packages/platform-browser/test //packages/platform-browser-dynamic/test //packages/router/test
|
# VE
|
||||||
- yarn bazel test //tools/public_api_guard/...
|
- yarn bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //...
|
||||||
- yarn bazel test //packages/compiler-cli/integrationtest:integrationtest //packages/compiler-cli/test/compliance:compliance
|
# Ivy
|
||||||
|
- yarn bazel test --define=compile=aot --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //...
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
@echo off
|
|
||||||
REM Fix for https://github.com/docker/for-win/issues/2920
|
|
||||||
REM echo "Fixing msys64 folder..."
|
|
||||||
REM Touch all .dll files inside C:\msys64\
|
|
||||||
forfiles /p C:\msys64\ /s /m *.dll /c "cmd /c Copy /B @path+,, >NUL"
|
|
||||||
REM echo "Fixed msys64 folder."
|
|
20
.github/CODEOWNERS
vendored
20
.github/CODEOWNERS
vendored
@ -53,6 +53,8 @@
|
|||||||
# IgorMinar - Igor Minar
|
# IgorMinar - Igor Minar
|
||||||
# jasonaden - Jason Aden
|
# jasonaden - Jason Aden
|
||||||
# jenniferfell - Jennifer Fell
|
# jenniferfell - Jennifer Fell
|
||||||
|
# JiaLiPassion - Jia Li
|
||||||
|
# josephperrott - Joey Perrott
|
||||||
# kara - Kara Erickson
|
# kara - Kara Erickson
|
||||||
# kyliau - Keen Yee Liau
|
# kyliau - Keen Yee Liau
|
||||||
# matsko - Matias Niemelä
|
# matsko - Matias Niemelä
|
||||||
@ -247,6 +249,15 @@
|
|||||||
# - mhevery
|
# - mhevery
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================
|
||||||
|
# @angular/fw-zones
|
||||||
|
# ===========================================================
|
||||||
|
#
|
||||||
|
# - JiaLiPassion
|
||||||
|
# - mhevery
|
||||||
|
# - vikerman
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
# @angular/tools-benchpress
|
# @angular/tools-benchpress
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
@ -346,7 +357,7 @@
|
|||||||
# - filipesilva
|
# - filipesilva
|
||||||
# - gkalpak
|
# - gkalpak
|
||||||
# - IgorMinar
|
# - IgorMinar
|
||||||
|
# - josephperrott
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -730,6 +741,13 @@ testing/** @angular/fw-test
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
# zone.js
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
/packages/zone.js/** @angular/fw-zones @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# benchpress
|
# benchpress
|
||||||
# ================================================
|
# ================================================
|
||||||
|
31
BUILD.bazel
31
BUILD.bazel
@ -18,15 +18,15 @@ filegroup(
|
|||||||
name = "web_test_bootstrap_scripts",
|
name = "web_test_bootstrap_scripts",
|
||||||
# do not sort
|
# do not sort
|
||||||
srcs = [
|
srcs = [
|
||||||
"@npm//node_modules/core-js:client/core.js",
|
"@npm//:node_modules/core-js/client/core.js",
|
||||||
"@npm//node_modules/zone.js:dist/zone.js",
|
"@npm//:node_modules/zone.js/dist/zone.js",
|
||||||
"@npm//node_modules/zone.js:dist/zone-testing.js",
|
"@npm//:node_modules/zone.js/dist/zone-testing.js",
|
||||||
"@npm//node_modules/zone.js:dist/task-tracking.js",
|
"@npm//:node_modules/zone.js/dist/task-tracking.js",
|
||||||
"//:test-events.js",
|
"//:test-events.js",
|
||||||
"//:shims_for_IE.js",
|
"//:shims_for_IE.js",
|
||||||
# Including systemjs because it defines `__eval`, which produces correct stack traces.
|
# Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||||
"@npm//node_modules/systemjs:dist/system.src.js",
|
"@npm//:node_modules/systemjs/dist/system.src.js",
|
||||||
"@npm//node_modules/reflect-metadata:Reflect.js",
|
"@npm//:node_modules/reflect-metadata/Reflect.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,15 +35,15 @@ filegroup(
|
|||||||
srcs = [
|
srcs = [
|
||||||
# We also declare the unminfied AngularJS files since these can be used for
|
# We also declare the unminfied AngularJS files since these can be used for
|
||||||
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
|
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
|
||||||
"@npm//node_modules/angular:angular.js",
|
"@npm//:node_modules/angular/angular.js",
|
||||||
"@npm//node_modules/angular:angular.min.js",
|
"@npm//:node_modules/angular/angular.min.js",
|
||||||
"@npm//node_modules/angular-1.5:angular.js",
|
"@npm//:node_modules/angular-1.5/angular.js",
|
||||||
"@npm//node_modules/angular-1.5:angular.min.js",
|
"@npm//:node_modules/angular-1.5/angular.min.js",
|
||||||
"@npm//node_modules/angular-1.6:angular.js",
|
"@npm//:node_modules/angular-1.6/angular.js",
|
||||||
"@npm//node_modules/angular-1.6:angular.min.js",
|
"@npm//:node_modules/angular-1.6/angular.min.js",
|
||||||
"@npm//node_modules/angular-mocks:angular-mocks.js",
|
"@npm//:node_modules/angular-mocks/angular-mocks.js",
|
||||||
"@npm//node_modules/angular-mocks-1.5:angular-mocks.js",
|
"@npm//:node_modules/angular-mocks-1.5/angular-mocks.js",
|
||||||
"@npm//node_modules/angular-mocks-1.6:angular-mocks.js",
|
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,6 +74,7 @@ karma_web_test(
|
|||||||
"//packages/core/test:test_lib",
|
"//packages/core/test:test_lib",
|
||||||
"//packages/forms/test:test_lib",
|
"//packages/forms/test:test_lib",
|
||||||
"//packages/http/test:test_lib",
|
"//packages/http/test:test_lib",
|
||||||
|
"//packages/zone.js/test:karma_jasmine_test_ci",
|
||||||
# "//packages/router/test:test_lib",
|
# "//packages/router/test:test_lib",
|
||||||
# //packages/router/test:test_lib fails with:
|
# //packages/router/test:test_lib fails with:
|
||||||
# IE 11.0.0 (Windows 8.1.0.0) bootstrap should restore the scrolling position FAILED
|
# IE 11.0.0 (Windows 8.1.0.0) bootstrap should restore the scrolling position FAILED
|
||||||
|
405
CHANGELOG.md
405
CHANGELOG.md
@ -1,3 +1,176 @@
|
|||||||
|
<a name="8.2.0"></a>
|
||||||
|
# [8.2.0](https://github.com/angular/angular/compare/8.2.0-rc.0...8.2.0) (2019-07-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** DebugElement.listeners not cleared on destroy ([#31820](https://github.com/angular/angular/issues/31820)) ([46b160e](https://github.com/angular/angular/commit/46b160e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.2.0-rc.0"></a>
|
||||||
|
# [8.2.0-rc.0](https://github.com/angular/angular/compare/8.2.0-next.2...8.2.0-rc.0) (2019-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** increase memory limit of ngc under bazel from 2 to 4 GB ([#31784](https://github.com/angular/angular/issues/31784)) ([5a8eb92](https://github.com/angular/angular/commit/5a8eb92))
|
||||||
|
* **core:** allow Z variations of CSS transforms in sanitizer ([#29264](https://github.com/angular/angular/issues/29264)) ([78e7fdd](https://github.com/angular/angular/commit/78e7fdd))
|
||||||
|
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([7151eae](https://github.com/angular/angular/commit/7151eae)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
|
||||||
|
* **platform-browser:** debug element query predicates not compatible with strictFunctionTypes ([#30993](https://github.com/angular/angular/issues/30993)) ([10a1e19](https://github.com/angular/angular/commit/10a1e19))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bazel:** compile targets used for indexing by Kythe with Ivy ([#31786](https://github.com/angular/angular/issues/31786)) ([82055b2](https://github.com/angular/angular/commit/82055b2))
|
||||||
|
* **upgrade:** support $element in upgraded component template/templateUrl functions ([#31637](https://github.com/angular/angular/issues/31637)) ([29e1c53](https://github.com/angular/angular/commit/29e1c53))
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([24ca582](https://github.com/angular/angular/commit/24ca582)), closes [#31627](https://github.com/angular/angular/issues/31627)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.3"></a>
|
||||||
|
## [8.1.3](https://github.com/angular/angular/compare/8.1.2...8.1.3) (2019-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([434b796](https://github.com/angular/angular/commit/434b796)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([1f3daa0](https://github.com/angular/angular/commit/1f3daa0)), closes [#31627](https://github.com/angular/angular/issues/31627)
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.2.0-next.2"></a>
|
||||||
|
# [8.2.0-next.2](https://github.com/angular/angular/compare/8.2.0-next.1...8.2.0-next.2) (2019-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([9204de9](https://github.com/angular/angular/commit/9204de9))
|
||||||
|
* **bazel:** pass custom bazel compiler host rather than rewriting one ([#31496](https://github.com/angular/angular/issues/31496)) ([0c61a35](https://github.com/angular/angular/commit/0c61a35))
|
||||||
|
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([3166cff](https://github.com/angular/angular/commit/3166cff)), closes [#22524](https://github.com/angular/angular/issues/22524)
|
||||||
|
* **language-service:** Eagarly initialize data members ([#31577](https://github.com/angular/angular/issues/31577)) ([0110de2](https://github.com/angular/angular/commit/0110de2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.2"></a>
|
||||||
|
## [8.1.2](https://github.com/angular/angular/compare/8.1.0...8.1.2) (2019-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([4aed480](https://github.com/angular/angular/commit/4aed480))
|
||||||
|
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([13dbb98](https://github.com/angular/angular/commit/13dbb98)), closes [#22524](https://github.com/angular/angular/issues/22524)
|
||||||
|
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.2.0-next.1"></a>
|
||||||
|
# [8.2.0-next.1](https://github.com/angular/angular/compare/8.2.0-next.0...8.2.0-next.1) (2019-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
|
||||||
|
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** add automatic migration from Renderer to Renderer2 ([#30936](https://github.com/angular/angular/issues/30936)) ([c095597](https://github.com/angular/angular/commit/c095597))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.1"></a>
|
||||||
|
## [8.1.1](https://github.com/angular/angular/compare/8.1.0...8.1.1) (2019-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.2.0-next.0"></a>
|
||||||
|
# [8.2.0-next.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.2.0-next.0) (2019-07-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
|
||||||
|
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), closes [#30968](https://github.com/angular/angular/issues/30968)
|
||||||
|
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bazel:** allow passing a custom bazel compiler host to ngc compile ([#31341](https://github.com/angular/angular/issues/31341)) ([a29dc96](https://github.com/angular/angular/commit/a29dc96))
|
||||||
|
* **bazel:** allow passing and rewriting an old bazel host ([#31381](https://github.com/angular/angular/issues/31381)) ([11a208f](https://github.com/angular/angular/commit/11a208f)), closes [#31341](https://github.com/angular/angular/issues/31341)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0"></a>
|
||||||
|
# [8.1.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.1.0) (2019-07-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
|
||||||
|
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([b0c3453](https://github.com/angular/angular/commit/b0c3453)), closes [#30968](https://github.com/angular/angular/issues/30968)
|
||||||
|
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([a9038ef](https://github.com/angular/angular/commit/a9038ef))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0-rc.0"></a>
|
||||||
|
# [8.1.0-rc.0](https://github.com/angular/angular/compare/8.1.0-next.3...8.1.0-rc.0) (2019-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** exclude all angular schematics folders from metadata build ([#31237](https://github.com/angular/angular/issues/31237)) ([16717fa](https://github.com/angular/angular/commit/16717fa)), closes [#31235](https://github.com/angular/angular/issues/31235)
|
||||||
|
* **bazel:** remove unsupported Css pre-processors from ng new ([#31234](https://github.com/angular/angular/issues/31234)) ([e83667a](https://github.com/angular/angular/commit/e83667a)), closes [#31209](https://github.com/angular/angular/issues/31209)
|
||||||
|
* **bazel:** update ng new schema to match the current ng new schema of [@schematics](https://github.com/schematics)/angular ([#31234](https://github.com/angular/angular/issues/31234)) ([805fc86](https://github.com/angular/angular/commit/805fc86)), closes [#31233](https://github.com/angular/angular/issues/31233)
|
||||||
|
* **compiler:** fix Elements not making a new ParseSourceSpan ([#31190](https://github.com/angular/angular/issues/31190)) ([7035f22](https://github.com/angular/angular/commit/7035f22))
|
||||||
|
* **compiler:** stringify `Object.create(null)` tokens ([#16848](https://github.com/angular/angular/issues/16848)) ([5e53956](https://github.com/angular/angular/commit/5e53956))
|
||||||
|
* **service-worker:** registration failed on Safari ([#31140](https://github.com/angular/angular/issues/31140)) ([a5dd4ed](https://github.com/angular/angular/commit/a5dd4ed)), closes [#31061](https://github.com/angular/angular/issues/31061)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **upgrade:** provide unit test helpers for wiring up injectors ([#16848](https://github.com/angular/angular/issues/16848)) ([3fb78aa](https://github.com/angular/angular/commit/3fb78aa))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.0.3"></a>
|
||||||
|
## [8.0.3](https://github.com/angular/angular/compare/8.0.2...8.0.3) (2019-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** exclude all angular schematics folders from metadata build ([#31237](https://github.com/angular/angular/issues/31237)) ([6bad2ca](https://github.com/angular/angular/commit/6bad2ca)), closes [#31235](https://github.com/angular/angular/issues/31235)
|
||||||
|
* **bazel:** remove unsupported Css pre-processors from ng new ([#31234](https://github.com/angular/angular/issues/31234)) ([980bcaf](https://github.com/angular/angular/commit/980bcaf)), closes [#31209](https://github.com/angular/angular/issues/31209)
|
||||||
|
* **bazel:** update ng new schema to match the current ng new schema of [@schematics](https://github.com/schematics)/angular ([#31234](https://github.com/angular/angular/issues/31234)) ([48f7f65](https://github.com/angular/angular/commit/48f7f65)), closes [#31233](https://github.com/angular/angular/issues/31233)
|
||||||
|
* **service-worker:** registration failed on Safari ([#31140](https://github.com/angular/angular/issues/31140)) ([f470e69](https://github.com/angular/angular/commit/f470e69)), closes [#31061](https://github.com/angular/angular/issues/31061)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0-next.3"></a>
|
||||||
|
# [8.1.0-next.3](https://github.com/angular/angular/compare/8.1.0-next.2...8.1.0-next.3) (2019-06-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** builder workspace should use nodejs v10.16.0 ([#31088](https://github.com/angular/angular/issues/31088)) ([a1fc4de](https://github.com/angular/angular/commit/a1fc4de))
|
||||||
|
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBedStatic.get overload ([#30714](https://github.com/angular/angular/issues/30714)) ([6bc9c78](https://github.com/angular/angular/commit/6bc9c78)), closes [#30514](https://github.com/angular/angular/issues/30514)
|
||||||
|
* **language-service:** Remove 'any' in getQuickInfoAtPosition ([#31014](https://github.com/angular/angular/issues/31014)) ([a4601ec](https://github.com/angular/angular/commit/a4601ec))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="8.0.2"></a>
|
<a name="8.0.2"></a>
|
||||||
## [8.0.2](https://github.com/angular/angular/compare/8.0.1...8.0.2) (2019-06-19)
|
## [8.0.2](https://github.com/angular/angular/compare/8.0.1...8.0.2) (2019-06-19)
|
||||||
|
|
||||||
@ -10,6 +183,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0-next.2"></a>
|
||||||
|
# [8.1.0-next.2](https://github.com/angular/angular/compare/8.1.0-next.1...8.1.0-next.2) (2019-06-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** do not modify tsconfig.json ([#30877](https://github.com/angular/angular/issues/30877)) ([b086676](https://github.com/angular/angular/commit/b086676))
|
||||||
|
* **bazel:** exclude components schematics from build ([#30825](https://github.com/angular/angular/issues/30825)) ([05a43ca](https://github.com/angular/angular/commit/05a43ca))
|
||||||
|
* **bazel:** Load global stylesheet in dev and prod ([#30879](https://github.com/angular/angular/issues/30879)) ([17bfedd](https://github.com/angular/angular/commit/17bfedd))
|
||||||
|
* **common:** expose the `HttpUploadProgressEvent` interface as public API ([#30852](https://github.com/angular/angular/issues/30852)) ([5c18f23](https://github.com/angular/angular/commit/5c18f23)), closes [#30814](https://github.com/angular/angular/issues/30814)
|
||||||
|
* **service-worker:** avoid uncaught rejection warning when registration fails ([#30876](https://github.com/angular/angular/issues/30876)) ([81c2a94](https://github.com/angular/angular/commit/81c2a94))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="8.0.1"></a>
|
<a name="8.0.1"></a>
|
||||||
## [8.0.1](https://github.com/angular/angular/compare/8.0.0...8.0.1) (2019-06-13)
|
## [8.0.1](https://github.com/angular/angular/compare/8.0.0...8.0.1) (2019-06-13)
|
||||||
|
|
||||||
@ -24,24 +211,83 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0-next.1"></a>
|
||||||
|
# [8.1.0-next.1](https://github.com/angular/angular/compare/8.1.0-beta.0...8.1.0-next.1) (2019-06-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** TypeScript related migrations should cater for BOM ([#30719](https://github.com/angular/angular/issues/30719)) ([80394ce](https://github.com/angular/angular/commit/80394ce)), closes [/github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts#L72](https://github.com//github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts/issues/L72) [#30713](https://github.com/angular/angular/issues/30713)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="8.1.0-beta.0"></a>
|
||||||
|
# [8.1.0-beta.0](https://github.com/angular/angular/compare/8.0.0...8.1.0-beta.0) (2019-05-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bazel:** allow ts_library interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([3125376](https://github.com/angular/angular/commit/3125376))
|
||||||
|
* **bazel:** Bump ibazel to 0.10.1 for windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([1353bf0](https://github.com/angular/angular/commit/1353bf0))
|
||||||
|
* **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([2a0f497](https://github.com/angular/angular/commit/2a0f497))
|
||||||
|
* **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([b6b1aec](https://github.com/angular/angular/commit/b6b1aec))
|
||||||
|
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([1f4c380](https://github.com/angular/angular/commit/1f4c380))
|
||||||
|
* **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([e688e02](https://github.com/angular/angular/commit/e688e02))
|
||||||
|
* **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([3aff79c](https://github.com/angular/angular/commit/3aff79c)), closes [#29785](https://github.com/angular/angular/issues/29785)
|
||||||
|
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([4ae0ee8](https://github.com/angular/angular/commit/4ae0ee8))
|
||||||
|
* **bazel:** Use existing npm/yarn lock files ([#30438](https://github.com/angular/angular/issues/30438)) ([ff29ccc](https://github.com/angular/angular/commit/ff29ccc))
|
||||||
|
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([60a8888](https://github.com/angular/angular/commit/60a8888))
|
||||||
|
* **core:** consistently use ng:/// for sourcemap URLs ([#29826](https://github.com/angular/angular/issues/29826)) ([392473e](https://github.com/angular/angular/commit/392473e))
|
||||||
|
* **core:** CSS sanitizer now allows parens in file names ([#30322](https://github.com/angular/angular/issues/30322)) ([728db88](https://github.com/angular/angular/commit/728db88))
|
||||||
|
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([30d1f29](https://github.com/angular/angular/commit/30d1f29))
|
||||||
|
* **core:** migrations not always migrating all files ([#30269](https://github.com/angular/angular/issues/30269)) ([349935a](https://github.com/angular/angular/commit/349935a))
|
||||||
|
* **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([a96976e](https://github.com/angular/angular/commit/a96976e))
|
||||||
|
* **core:** require 'static' flag on queries in typings ([#30639](https://github.com/angular/angular/issues/30639)) ([84dd267](https://github.com/angular/angular/commit/84dd267))
|
||||||
|
* **core:** static-query migration errors not printed properly ([#30458](https://github.com/angular/angular/issues/30458)) ([6ceb903](https://github.com/angular/angular/commit/6ceb903))
|
||||||
|
* **core:** static-query migration fails with default parameter values ([#30269](https://github.com/angular/angular/issues/30269)) ([6357d4a](https://github.com/angular/angular/commit/6357d4a))
|
||||||
|
* **core:** static-query migration should gracefully exit if AOT compiler throws ([#30269](https://github.com/angular/angular/issues/30269)) ([509352f](https://github.com/angular/angular/commit/509352f))
|
||||||
|
* **core:** static-query migration should handle queries on accessors ([#30327](https://github.com/angular/angular/issues/30327)) ([0ffdb48](https://github.com/angular/angular/commit/0ffdb48))
|
||||||
|
* **core:** static-query migration should not fallback to test strategy ([#30458](https://github.com/angular/angular/issues/30458)) ([0cdf598](https://github.com/angular/angular/commit/0cdf598))
|
||||||
|
* **core:** static-query migration should not prompt if no queries are used ([#30254](https://github.com/angular/angular/issues/30254)) ([4c12d74](https://github.com/angular/angular/commit/4c12d74))
|
||||||
|
* **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([8d3365e](https://github.com/angular/angular/commit/8d3365e))
|
||||||
|
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBed.get overload ([#30514](https://github.com/angular/angular/issues/30514)) ([f6bf892](https://github.com/angular/angular/commit/f6bf892)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905)
|
||||||
|
* **language-service:** Remove tsserverlibrary from rollup globals ([#30123](https://github.com/angular/angular/issues/30123)) ([124e497](https://github.com/angular/angular/commit/124e497))
|
||||||
|
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([b40f6f3](https://github.com/angular/angular/commit/b40f6f3))
|
||||||
|
* **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([0fd9d08](https://github.com/angular/angular/commit/0fd9d08)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160)
|
||||||
|
* **router:** fix a problem with router not responding to back button ([#30160](https://github.com/angular/angular/issues/30160)) ([3327bd8](https://github.com/angular/angular/commit/3327bd8))
|
||||||
|
* **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([197584d](https://github.com/angular/angular/commit/197584d))
|
||||||
|
* **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([53f3564](https://github.com/angular/angular/commit/53f3564))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bazel:** use `rbe_autoconfig()` and new container. ([#29336](https://github.com/angular/angular/issues/29336)) ([9abf114](https://github.com/angular/angular/commit/9abf114))
|
||||||
|
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([1aff524](https://github.com/angular/angular/commit/1aff524))
|
||||||
|
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([95830ee](https://github.com/angular/angular/commit/95830ee))
|
||||||
|
* **core:** deprecate integration with the Web Tracing Framework (WTF) ([#30642](https://github.com/angular/angular/issues/30642)) ([f310a59](https://github.com/angular/angular/commit/f310a59))
|
||||||
|
* **language-service:** Implement `definitionAndBoundSpan` ([#30125](https://github.com/angular/angular/issues/30125)) ([f491673](https://github.com/angular/angular/commit/f491673))
|
||||||
|
* **platform-webworker:** deprecate platform-webworker ([#30642](https://github.com/angular/angular/issues/30642)) ([ccc76f7](https://github.com/angular/angular/commit/ccc76f7))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="8.0.0"></a>
|
<a name="8.0.0"></a>
|
||||||
# [8.0.0](https://github.com/angular/angular/compare/8.0.0-rc.5...8.0.0) (2019-05-28)
|
# [8.0.0](https://github.com/angular/angular/compare/8.0.0-rc.5...8.0.0) (2019-05-28)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* add support for TypeScript 3.3 (and drop older versions) ([#29004](https://github.com/angular/angular/issues/29004)) ([75748d6](https://github.com/angular/angular/commit/75748d6))
|
* add support for TypeScript 3.4 (and drop older versions) ([#29372](https://github.com/angular/angular/issues/29372)) ([ef85336](https://github.com/angular/angular/commit/ef85336))
|
||||||
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([8022d36](https://github.com/angular/angular/commit/8022d36))
|
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([8022d36](https://github.com/angular/angular/commit/8022d36))
|
||||||
* **common:** stricter types for SlicePipe ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa))
|
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa))
|
||||||
* **bazel:** use rbe_autoconfig() and new container. ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc))
|
* **bazel:** use `rbe_autoconfig()` and new container ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc))
|
||||||
* **common:** add [@angular](https://github.com/angular)/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
* **common:** add @angular/common/upgrade package for `$location`-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
||||||
* **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
|
* **common:** add ability to retrieve the state from `Location` service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
|
||||||
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
|
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
|
||||||
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
|
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
|
||||||
* **common:** add MockPlatformLocation to enable more robust testing of Location services ([#30055](https://github.com/angular/angular/issues/30055)) ([d0672c2](https://github.com/angular/angular/commit/d0672c2))
|
* **common:** add `MockPlatformLocation` to enable more robust testing of `Location` services ([#30055](https://github.com/angular/angular/issues/30055)) ([d0672c2](https://github.com/angular/angular/commit/d0672c2))
|
||||||
* **common:** add UrlCodec type for use with upgrade applications ([#30055](https://github.com/angular/angular/issues/30055)) ([ec455e1](https://github.com/angular/angular/commit/ec455e1))
|
* **common:** add `UrlCodec` type for use with upgrade applications ([#30055](https://github.com/angular/angular/issues/30055)) ([ec455e1](https://github.com/angular/angular/commit/ec455e1))
|
||||||
* **common:** provide replacement for AngularJS $location service ([#30055](https://github.com/angular/angular/issues/30055)) ([4277600](https://github.com/angular/angular/commit/4277600))
|
* **common:** provide replacement for AngularJS $location service ([#30055](https://github.com/angular/angular/issues/30055)) ([4277600](https://github.com/angular/angular/commit/4277600))
|
||||||
* remove deprecated DOCUMENT token from platform-browser ([#28117](https://github.com/angular/angular/issues/28117)) ([3a9d247](https://github.com/angular/angular/commit/3a9d247))
|
* remove deprecated `DOCUMENT` token from platform-browser ([#28117](https://github.com/angular/angular/issues/28117)) ([3a9d247](https://github.com/angular/angular/commit/3a9d247))
|
||||||
* **compiler:** support skipping leading trivia in template source-maps ([#30095](https://github.com/angular/angular/issues/30095)) ([304a12f](https://github.com/angular/angular/commit/304a12f))
|
* **compiler:** support skipping leading trivia in template source-maps ([#30095](https://github.com/angular/angular/issues/30095)) ([304a12f](https://github.com/angular/angular/commit/304a12f))
|
||||||
* **core:** add missing ARIA attributes to html sanitizer ([#29685](https://github.com/angular/angular/issues/29685)) ([909557d](https://github.com/angular/angular/commit/909557d)), closes [#26815](https://github.com/angular/angular/issues/26815)
|
* **core:** add missing ARIA attributes to html sanitizer ([#29685](https://github.com/angular/angular/issues/29685)) ([909557d](https://github.com/angular/angular/commit/909557d)), closes [#26815](https://github.com/angular/angular/issues/26815)
|
||||||
* **router:** deprecate loadChildren:string ([#30073](https://github.com/angular/angular/issues/30073)) ([c61df39](https://github.com/angular/angular/commit/c61df39))
|
* **router:** deprecate loadChildren:string ([#30073](https://github.com/angular/angular/issues/30073)) ([c61df39](https://github.com/angular/angular/commit/c61df39))
|
||||||
@ -50,28 +296,28 @@
|
|||||||
* **service-worker:** support bypassing SW with specific header/query param ([#30010](https://github.com/angular/angular/issues/30010)) ([6200732](https://github.com/angular/angular/commit/6200732)), closes [#21191](https://github.com/angular/angular/issues/21191)
|
* **service-worker:** support bypassing SW with specific header/query param ([#30010](https://github.com/angular/angular/issues/30010)) ([6200732](https://github.com/angular/angular/commit/6200732)), closes [#21191](https://github.com/angular/angular/issues/21191)
|
||||||
* **compiler-cli:** export tooling definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e1f51ea](https://github.com/angular/angular/commit/e1f51ea))
|
* **compiler-cli:** export tooling definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e1f51ea](https://github.com/angular/angular/commit/e1f51ea))
|
||||||
* **compiler-cli:** lower some exported expressions ([#30038](https://github.com/angular/angular/issues/30038)) ([8e73f9b](https://github.com/angular/angular/commit/8e73f9b))
|
* **compiler-cli:** lower some exported expressions ([#30038](https://github.com/angular/angular/issues/30038)) ([8e73f9b](https://github.com/angular/angular/commit/8e73f9b))
|
||||||
* **core:** add schematics to move deprecated DOCUMENT import ([#29950](https://github.com/angular/angular/issues/29950)) ([645e305](https://github.com/angular/angular/commit/645e305))
|
* **core:** add schematics to move deprecated `DOCUMENT` import ([#29950](https://github.com/angular/angular/issues/29950)) ([645e305](https://github.com/angular/angular/commit/645e305))
|
||||||
* **bazel:** update the build to use the new architect api ([#29720](https://github.com/angular/angular/issues/29720)) ([902a53a](https://github.com/angular/angular/commit/902a53a))
|
* **bazel:** update the build to use the new architect api ([#29720](https://github.com/angular/angular/issues/29720)) ([902a53a](https://github.com/angular/angular/commit/902a53a))
|
||||||
* remove [@angular](https://github.com/angular)/http dependency from [@angular](https://github.com/angular)/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
|
* remove @angular/http dependency from @angular/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
|
||||||
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
|
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
|
||||||
* **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
|
* **core:** Add `AbstractType<T>` interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
|
||||||
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
|
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
|
||||||
* **bazel:** Upgrade rules_nodejs and rules_sass ([#29388](https://github.com/angular/angular/issues/29388)) ([d6d081e](https://github.com/angular/angular/commit/d6d081e))
|
* **bazel:** Upgrade rules_nodejs and rules_sass ([#29388](https://github.com/angular/angular/issues/29388)) ([d6d081e](https://github.com/angular/angular/commit/d6d081e))
|
||||||
* **service-worker:** support multiple apps on different subpaths of a domain ([#27080](https://github.com/angular/angular/issues/27080)) ([e721c08](https://github.com/angular/angular/commit/e721c08)), closes [#21388](https://github.com/angular/angular/issues/21388)
|
* **service-worker:** support multiple apps on different subpaths of a domain ([#27080](https://github.com/angular/angular/issues/27080)) ([e721c08](https://github.com/angular/angular/commit/e721c08)), closes [#21388](https://github.com/angular/angular/issues/21388)
|
||||||
* **bazel:** Eject Bazel ([#29167](https://github.com/angular/angular/issues/29167)) ([36a1550](https://github.com/angular/angular/commit/36a1550))
|
* **bazel:** Eject Bazel ([#29167](https://github.com/angular/angular/issues/29167)) ([36a1550](https://github.com/angular/angular/commit/36a1550))
|
||||||
* **bazel:** Hide Bazel files in Bazel builder ([#29110](https://github.com/angular/angular/issues/29110)) ([7060d90](https://github.com/angular/angular/commit/7060d90))
|
* **bazel:** Hide Bazel files in Bazel builder ([#29110](https://github.com/angular/angular/issues/29110)) ([7060d90](https://github.com/angular/angular/commit/7060d90))
|
||||||
* **forms:** clear (remove all) components from a FormArray ([#28918](https://github.com/angular/angular/issues/28918)) ([a68b1a1](https://github.com/angular/angular/commit/a68b1a1)), closes [#18531](https://github.com/angular/angular/issues/18531)
|
* **forms:** clear (remove all) components from a FormArray ([#28918](https://github.com/angular/angular/issues/28918)) ([a68b1a1](https://github.com/angular/angular/commit/a68b1a1)), closes [#18531](https://github.com/angular/angular/issues/18531)
|
||||||
* **platform-server:** wait on returned BEFORE_APP_SERIALIZED promises ([#29120](https://github.com/angular/angular/issues/29120)) ([7102ea8](https://github.com/angular/angular/commit/7102ea8))
|
* **platform-server:** wait on returned `BEFORE_APP_SERIALIZED` promises ([#29120](https://github.com/angular/angular/issues/29120)) ([7102ea8](https://github.com/angular/angular/commit/7102ea8))
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **bazel:** allow ts_library interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([bf38df4](https://github.com/angular/angular/commit/bf38df4))
|
* **bazel:** allow `ts_library` interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([bf38df4](https://github.com/angular/angular/commit/bf38df4))
|
||||||
* **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([3de26a8](https://github.com/angular/angular/commit/3de26a8))
|
* **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([3de26a8](https://github.com/angular/angular/commit/3de26a8))
|
||||||
* **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([8bc4da8](https://github.com/angular/angular/commit/8bc4da8))
|
* **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([8bc4da8](https://github.com/angular/angular/commit/8bc4da8))
|
||||||
* **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([5a46f94](https://github.com/angular/angular/commit/5a46f94))
|
* **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([5a46f94](https://github.com/angular/angular/commit/5a46f94))
|
||||||
* **core:** require 'static' flag on queries in typings ([#30641](https://github.com/angular/angular/issues/30641)) ([c8af830](https://github.com/angular/angular/commit/c8af830))
|
* **core:** require 'static' flag on queries in typings ([#30641](https://github.com/angular/angular/issues/30641)) ([c8af830](https://github.com/angular/angular/commit/c8af830))
|
||||||
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBed.get overload ([#30514](https://github.com/angular/angular/issues/30514)) ([561e01d](https://github.com/angular/angular/commit/561e01d)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905)
|
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a `TextBed.get` overload ([#30514](https://github.com/angular/angular/issues/30514)) ([561e01d](https://github.com/angular/angular/commit/561e01d)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905)
|
||||||
* **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([32daa93](https://github.com/angular/angular/commit/32daa93))
|
* **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([32daa93](https://github.com/angular/angular/commit/32daa93))
|
||||||
* **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([d1fcc2b](https://github.com/angular/angular/commit/d1fcc2b))
|
* **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([d1fcc2b](https://github.com/angular/angular/commit/d1fcc2b))
|
||||||
* **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([71eba45](https://github.com/angular/angular/commit/71eba45)), closes [#29785](https://github.com/angular/angular/issues/29785)
|
* **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([71eba45](https://github.com/angular/angular/commit/71eba45)), closes [#29785](https://github.com/angular/angular/issues/29785)
|
||||||
@ -87,7 +333,7 @@
|
|||||||
* **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([e295c6a](https://github.com/angular/angular/commit/e295c6a))
|
* **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([e295c6a](https://github.com/angular/angular/commit/e295c6a))
|
||||||
* **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([9b88920](https://github.com/angular/angular/commit/9b88920)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160)
|
* **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([9b88920](https://github.com/angular/angular/commit/9b88920)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160)
|
||||||
* **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([c383491](https://github.com/angular/angular/commit/c383491))
|
* **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([c383491](https://github.com/angular/angular/commit/c383491))
|
||||||
* **bazel:** Bump ibazel to 0.10.1 for windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([9f68c35](https://github.com/angular/angular/commit/9f68c35))
|
* **bazel:** Bump ibazel to 0.10.1 for Windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([9f68c35](https://github.com/angular/angular/commit/9f68c35))
|
||||||
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([548b003](https://github.com/angular/angular/commit/548b003))
|
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([548b003](https://github.com/angular/angular/commit/548b003))
|
||||||
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([3fe3a84](https://github.com/angular/angular/commit/3fe3a84))
|
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([3fe3a84](https://github.com/angular/angular/commit/3fe3a84))
|
||||||
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([9720227](https://github.com/angular/angular/commit/9720227))
|
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([9720227](https://github.com/angular/angular/commit/9720227))
|
||||||
@ -97,57 +343,54 @@
|
|||||||
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22))
|
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22))
|
||||||
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583))
|
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583))
|
||||||
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
|
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
|
||||||
* **bazel:** Make sure only single copy of `[@angular](https://github.com/angular)/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
|
* **bazel:** Make sure only single copy of @angular/bazel is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
|
||||||
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
|
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
|
||||||
* **common:** add upgrade sub-package to ng_package rule for [@angular](https://github.com/angular)/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
|
* **common:** add upgrade sub-package to `ng_package` rule for @angular/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
|
||||||
* **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
|
* **common:** adjust `MockPlatformLocation` to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
|
||||||
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
|
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
|
||||||
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
|
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
|
||||||
* **bazel:** do not typecheck core schematic files ([#29876](https://github.com/angular/angular/issues/29876)) ([2ba799d](https://github.com/angular/angular/commit/2ba799d))
|
* **bazel:** do not typecheck core schematic files ([#29876](https://github.com/angular/angular/issues/29876)) ([2ba799d](https://github.com/angular/angular/commit/2ba799d))
|
||||||
* **bazel:** restore ng build --prod ([#30005](https://github.com/angular/angular/issues/30005)) ([96a8289](https://github.com/angular/angular/commit/96a8289))
|
* **bazel:** restore `ng build --prod` ([#30005](https://github.com/angular/angular/issues/30005)) ([96a8289](https://github.com/angular/angular/commit/96a8289))
|
||||||
* **common:** prevent repeated application of HttpParams mutations ([#29045](https://github.com/angular/angular/issues/29045)) ([8e8e89a](https://github.com/angular/angular/commit/8e8e89a)), closes [#20430](https://github.com/angular/angular/issues/20430)
|
* **common:** prevent repeated application of `HttpParams` mutations ([#29045](https://github.com/angular/angular/issues/29045)) ([8e8e89a](https://github.com/angular/angular/commit/8e8e89a)), closes [#20430](https://github.com/angular/angular/issues/20430)
|
||||||
* **common:** async pipe will properly check when it recieves an NaN value from an observable ([#22305](https://github.com/angular/angular/issues/22305)) ([3f6bf6d](https://github.com/angular/angular/commit/3f6bf6d)), closes [#15721](https://github.com/angular/angular/issues/15721)
|
* **common:** async pipe will properly check when it receives an NaN value from an observable ([#22305](https://github.com/angular/angular/issues/22305)) ([3f6bf6d](https://github.com/angular/angular/commit/3f6bf6d)), closes [#15721](https://github.com/angular/angular/issues/15721)
|
||||||
* **core:** don't include a local `EventListener` in typings ([#29809](https://github.com/angular/angular/issues/29809)) ([4bde40f](https://github.com/angular/angular/commit/4bde40f)), closes [/github.com/angular/angular/blob/303eae918d997070a36b523ddc97e018f622c258/packages/core/src/debug/debug_node.ts#L32](https://github.com//github.com/angular/angular/blob/303eae918d997070a36b523ddc97e018f622c258/packages/core/src/debug/debug_node.ts/issues/L32) [#29806](https://github.com/angular/angular/issues/29806)
|
* **core:** don't include a local `EventListener` in typings ([#29809](https://github.com/angular/angular/issues/29809)) ([4bde40f](https://github.com/angular/angular/commit/4bde40f)), closes [#29806](https://github.com/angular/angular/issues/29806)
|
||||||
* **core:** use shakeable global definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e5905bb](https://github.com/angular/angular/commit/e5905bb)), closes [/github.com/angular/angular-cli/blob/5fc1f2499cbe57f9a95e4b0dfced130eb3a8046d/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts#L279-L282](https://github.com//github.com/angular/angular-cli/blob/5fc1f2499cbe57f9a95e4b0dfced130eb3a8046d/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts/issues/L279-L282)
|
* **core:** use shakeable global definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e5905bb](https://github.com/angular/angular/commit/e5905bb))
|
||||||
* **language-service:** Use proper types instead of any ([#29942](https://github.com/angular/angular/issues/29942)) ([1a56cd5](https://github.com/angular/angular/commit/1a56cd5))
|
* **language-service:** Use proper types instead of any ([#29942](https://github.com/angular/angular/issues/29942)) ([1a56cd5](https://github.com/angular/angular/commit/1a56cd5))
|
||||||
* **bazel:** Install packages after `ng add` when invoked independently ([#29852](https://github.com/angular/angular/issues/29852)) ([bd2ce9c](https://github.com/angular/angular/commit/bd2ce9c))
|
* **bazel:** Install packages after `ng add` when invoked independently ([#29852](https://github.com/angular/angular/issues/29852)) ([bd2ce9c](https://github.com/angular/angular/commit/bd2ce9c))
|
||||||
* **compiler-cli:** pass config path to ts.parseJsonConfigFileContent ([#29872](https://github.com/angular/angular/issues/29872)) ([86a3f90](https://github.com/angular/angular/commit/86a3f90)), closes [/github.com/Microsoft/TypeScript/blob/025d82633915b67003ea38ba40b9239a19721c13/src/compiler/emitter.ts#L56-L57](https://github.com//github.com/Microsoft/TypeScript/blob/025d82633915b67003ea38ba40b9239a19721c13/src/compiler/emitter.ts/issues/L56-L57)
|
* **compiler-cli:** pass config path to `ts.parseJsonConfigFileContent` ([#29872](https://github.com/angular/angular/issues/29872)) ([86a3f90](https://github.com/angular/angular/commit/86a3f90))
|
||||||
* **router:** support non-NgFactory promise in loadChildren typings ([#29832](https://github.com/angular/angular/issues/29832)) ([2bfb6a0](https://github.com/angular/angular/commit/2bfb6a0))
|
* **router:** support non-NgFactory promise in loadChildren typings ([#29832](https://github.com/angular/angular/issues/29832)) ([2bfb6a0](https://github.com/angular/angular/commit/2bfb6a0))
|
||||||
* **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//[@angular](https://github.com/angular)/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
|
* **bazel:** add `configuration_env_vars = ["compile"]` to generated `@npm//@angular/bazel/bin:ngc-wrapped` `nodejs_binary` ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
|
||||||
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
|
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
|
||||||
* **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
|
* **bazel:** remove karma-jasmine from `ts_web_test_suite` ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
|
||||||
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
|
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
|
||||||
* **common:** add `@Injectable()` to common pipes ([#29834](https://github.com/angular/angular/issues/29834)) ([387fbb8](https://github.com/angular/angular/commit/387fbb8))
|
* **common:** add `@Injectable()` to common pipes ([#29834](https://github.com/angular/angular/issues/29834)) ([387fbb8](https://github.com/angular/angular/commit/387fbb8))
|
||||||
* **compiler-cli:** ensure LogicalProjectPaths always start with a slash ([#29627](https://github.com/angular/angular/issues/29627)) ([e02684e](https://github.com/angular/angular/commit/e02684e))
|
* **compiler-cli:** ensure `LogicalProjectPaths` always start with a slash ([#29627](https://github.com/angular/angular/issues/29627)) ([e02684e](https://github.com/angular/angular/commit/e02684e))
|
||||||
* **core:** add missing migration to npm package ([#29705](https://github.com/angular/angular/issues/29705)) ([96b76dc](https://github.com/angular/angular/commit/96b76dc))
|
* **core:** add missing migration to npm package ([#29705](https://github.com/angular/angular/issues/29705)) ([96b76dc](https://github.com/angular/angular/commit/96b76dc))
|
||||||
* **core:** call ngOnDestroy for tree-shakeable providers ([#28943](https://github.com/angular/angular/issues/28943)) ([30b0442](https://github.com/angular/angular/commit/30b0442)), closes [#28927](https://github.com/angular/angular/issues/28927)
|
* **core:** call `ngOnDestroy` for tree-shakeable providers ([#28943](https://github.com/angular/angular/issues/28943)) ([30b0442](https://github.com/angular/angular/commit/30b0442)), closes [#28927](https://github.com/angular/angular/issues/28927)
|
||||||
* **core:** Deprecate TestBed.get(...):any ([#29290](https://github.com/angular/angular/issues/29290)) ([609024f](https://github.com/angular/angular/commit/609024f)), closes [#13785](https://github.com/angular/angular/issues/13785) [#26491](https://github.com/angular/angular/issues/26491)
|
* **core:** Deprecate `TestBed.get(...):any` ([#29290](https://github.com/angular/angular/issues/29290)) ([609024f](https://github.com/angular/angular/commit/609024f)), closes [#13785](https://github.com/angular/angular/issues/13785) [#26491](https://github.com/angular/angular/issues/26491)
|
||||||
* **core:** resolve ts compile issues due to lenient tsconfig ([#29843](https://github.com/angular/angular/issues/29843)) ([54058ba](https://github.com/angular/angular/commit/54058ba))
|
* **core:** resolve ts compile issues due to lenient tsconfig ([#29843](https://github.com/angular/angular/issues/29843)) ([54058ba](https://github.com/angular/angular/commit/54058ba))
|
||||||
* **platform-browser:** insert APP_ID in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([712d60e](https://github.com/angular/angular/commit/712d60e))
|
* **platform-browser:** insert `APP_ID` in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([712d60e](https://github.com/angular/angular/commit/712d60e))
|
||||||
* **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([#29711](https://github.com/angular/angular/issues/29711)) ([9e33dc3](https://github.com/angular/angular/commit/9e33dc3))
|
|
||||||
* **platform-browser:** insert APP_ID in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([ca14509](https://github.com/angular/angular/commit/ca14509))
|
|
||||||
* **bazel:** Update schematics to support routing ([#29548](https://github.com/angular/angular/issues/29548)) ([401b8ee](https://github.com/angular/angular/commit/401b8ee))
|
* **bazel:** Update schematics to support routing ([#29548](https://github.com/angular/angular/issues/29548)) ([401b8ee](https://github.com/angular/angular/commit/401b8ee))
|
||||||
* **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
|
* **bazel:** use `//:tsconfig.json` as the default for `ng_module` ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
|
||||||
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
|
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
|
||||||
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
|
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
|
||||||
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
|
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
|
||||||
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
|
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
|
||||||
* **bazel:** allow ng_module users to set createExternalSymbolFactoryReexports ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
|
* **bazel:** allow `ng_module` users to set `createExternalSymbolFactoryReexports` ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
|
||||||
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
|
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
|
||||||
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
|
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
|
||||||
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([dafbbf8](https://github.com/angular/angular/commit/dafbbf8)), closes [#29231](https://github.com/angular/angular/issues/29231)
|
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([dafbbf8](https://github.com/angular/angular/commit/dafbbf8)), closes [#29231](https://github.com/angular/angular/issues/29231)
|
||||||
* **core:** static-query schematic should detect queries in "ngDoCheck" and "ngOnChanges" ([#29492](https://github.com/angular/angular/issues/29492)) ([09fab58](https://github.com/angular/angular/commit/09fab58))
|
* **core:** static-query schematic should detect queries in `ngDoCheck` and `ngOnChanges` ([#29492](https://github.com/angular/angular/issues/29492)) ([09fab58](https://github.com/angular/angular/commit/09fab58))
|
||||||
* **router:** support NgFactory promise in loadChildren typings ([#29392](https://github.com/angular/angular/issues/29392)) ([26a8c59](https://github.com/angular/angular/commit/26a8c59))
|
* **router:** support `NgFactory` promise in loadChildren typings ([#29392](https://github.com/angular/angular/issues/29392)) ([26a8c59](https://github.com/angular/angular/commit/26a8c59))
|
||||||
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
|
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
|
||||||
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
|
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
|
||||||
* **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
|
* **bazel:** fix strict null checks compile error in `packages/bazel/src/schematics/ng-add/index.ts` ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
|
||||||
* **bazel:** Remove [@angular](https://github.com/angular)/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
|
* **bazel:** Remove @angular/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
|
||||||
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
|
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
|
||||||
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
|
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
|
||||||
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
|
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf))
|
||||||
* **core:** don't wrap `<tr>` and `<col>` elements into a required parent ([#29219](https://github.com/angular/angular/issues/29219)) ([f2dc32e](https://github.com/angular/angular/commit/f2dc32e))
|
* **core:** don't wrap `<tr>` and `<col>` elements into a required parent ([#29219](https://github.com/angular/angular/issues/29219)) ([f2dc32e](https://github.com/angular/angular/commit/f2dc32e))
|
||||||
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([4605df8](https://github.com/angular/angular/commit/4605df8)), closes [#29231](https://github.com/angular/angular/issues/29231)
|
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([4605df8](https://github.com/angular/angular/commit/4605df8)), closes [#29231](https://github.com/angular/angular/issues/29231)
|
||||||
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([cf8d934](https://github.com/angular/angular/commit/cf8d934)), closes [github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85)
|
|
||||||
* **bazel:** add missing binary path for api-extractor ([#29202](https://github.com/angular/angular/issues/29202)) ([df354d1](https://github.com/angular/angular/commit/df354d1))
|
* **bazel:** add missing binary path for api-extractor ([#29202](https://github.com/angular/angular/issues/29202)) ([df354d1](https://github.com/angular/angular/commit/df354d1))
|
||||||
* **bazel:** ng build should produce prod bundle ([#29136](https://github.com/angular/angular/issues/29136)) ([14ce8a9](https://github.com/angular/angular/commit/14ce8a9))
|
* **bazel:** ng build should produce prod bundle ([#29136](https://github.com/angular/angular/issues/29136)) ([14ce8a9](https://github.com/angular/angular/commit/14ce8a9))
|
||||||
* **compiler:** ensure template is updated if an output is transformed ([#29041](https://github.com/angular/angular/issues/29041)) ([c7e4931](https://github.com/angular/angular/commit/c7e4931))
|
* **compiler:** ensure template is updated if an output is transformed ([#29041](https://github.com/angular/angular/issues/29041)) ([c7e4931](https://github.com/angular/angular/commit/c7e4931))
|
||||||
@ -161,16 +404,16 @@
|
|||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
* **bazel:** @bazel/typescript is now a peerDependency of @angular/bazel so user's of @angular/bazel must add @bazel/typescript to their package.json
|
* **bazel:** @bazel/typescript is now a peerDependency of @angular/bazel so users of @angular/bazel must add @bazel/typescript to their package.json
|
||||||
* **bazel:** ng_module now depends on a minimum of build_bazel_rules_nodejs 0.27.12
|
* **bazel:** `ng_module` now depends on a minimum of build_bazel_rules_nodejs 0.27.12
|
||||||
* **core:** In Angular version 8, it's required that all @ViewChild and @ContentChild
|
* **core:** In Angular version 8, it's required that all `@ViewChild` and `@ContentChild`
|
||||||
queries have a 'static' flag specifying whether the query is 'static' or
|
queries have a `'static'` flag specifying whether the query is 'static' or
|
||||||
'dynamic'. The compiler previously sorted queries automatically, but in
|
'dynamic'. The compiler previously sorted queries automatically, but in
|
||||||
8.0 developers are required to explicitly specify which behavior is wanted.
|
8.0 developers are required to explicitly specify which behavior is wanted.
|
||||||
This is a temporary requirement as part of a migration; see
|
This is a temporary requirement as part of a migration; see
|
||||||
https://v8.angular.io/guide/static-query-migration for more details.
|
[static query migration guide](https://v8.angular.io/guide/static-query-migration) for more details.
|
||||||
|
|
||||||
@ViewChildren and @ContentChildren queries are always dynamic, and so are
|
`@ViewChildren` and `@ContentChildren` queries are always dynamic, and so are
|
||||||
unaffected.
|
unaffected.
|
||||||
|
|
||||||
* `TestBed.get()` has two signatures, one which is typed and another which accepts and returns `any`. The signature for `any` is deprecated; all usage of `TestBed.get()` should go through the typed API. This mainly affects string tokens
|
* `TestBed.get()` has two signatures, one which is typed and another which accepts and returns `any`. The signature for `any` is deprecated; all usage of `TestBed.get()` should go through the typed API. This mainly affects string tokens
|
||||||
@ -204,8 +447,8 @@ https://v8.angular.io/guide/static-query-migration for more details.
|
|||||||
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
|
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
|
||||||
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
|
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
|
||||||
|
|
||||||
This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
|
This mechanism of automatic wrapping / auto-correcting was problematic for several reasons:
|
||||||
- it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
|
- it is non-obvious and arbitrary (ex. there are more HTML elements that have rules for parent type);
|
||||||
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
|
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -217,10 +460,13 @@ https://v8.angular.io/guide/static-query-migration for more details.
|
|||||||
In the above example the `<projecting-tr-inside-tbody>` component could be "surprised" to see additional
|
In the above example the `<projecting-tr-inside-tbody>` component could be "surprised" to see additional
|
||||||
`<tbody>` elements inserted by Angular HTML parser.
|
`<tbody>` elements inserted by Angular HTML parser.
|
||||||
|
|
||||||
|
* **http:** The deprecated @angular/http package has been removed, the @angular/common/http package should be used instead.
|
||||||
|
For details on how to migrate, please refer to [the deprecations guide](https://angular.io/guide/deprecations#angularhttp).
|
||||||
|
|
||||||
|
|
||||||
* TypeScript 3.1 and 3.2 are no longer supported.
|
* TypeScript 3.1 and 3.2 are no longer supported.
|
||||||
|
|
||||||
Please update your TypeScript version to 3.3
|
Please update your TypeScript version to 3.4, as version 3.3 is also not supported.
|
||||||
|
|
||||||
|
|
||||||
<a name="8.0.0-rc.5"></a>
|
<a name="8.0.0-rc.5"></a>
|
||||||
@ -306,6 +552,17 @@ unaffected.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="7.2.15"></a>
|
||||||
|
## [7.2.15](https://github.com/angular/angular/compare/7.2.14...7.2.15) (2019-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([#30107](https://github.com/angular/angular/issues/30107)) ([1084c19](https://github.com/angular/angular/commit/1084c19)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="8.0.0-rc.2"></a>
|
<a name="8.0.0-rc.2"></a>
|
||||||
# [8.0.0-rc.2](https://github.com/angular/angular/compare/8.0.0-rc.1...8.0.0-rc.2) (2019-04-29)
|
# [8.0.0-rc.2](https://github.com/angular/angular/compare/8.0.0-rc.1...8.0.0-rc.2) (2019-04-29)
|
||||||
|
|
||||||
@ -335,9 +592,9 @@ unaffected.
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
|
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
|
||||||
* **bazel:** Make sure only single copy of `[@angular](https://github.com/angular)/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
|
* **bazel:** Make sure only single copy of `@angular/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
|
||||||
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
|
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
|
||||||
* **common:** add upgrade sub-package to ng_package rule for [@angular](https://github.com/angular)/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
|
* **common:** add upgrade sub-package to ng_package rule for @angular/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
|
||||||
* **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
|
* **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
|
||||||
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
|
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
|
||||||
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
|
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
|
||||||
@ -345,7 +602,7 @@ unaffected.
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* **common:** add [@angular](https://github.com/angular)/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
* **common:** add @angular/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
|
||||||
* **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
|
* **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
|
||||||
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
|
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
|
||||||
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
|
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
|
||||||
@ -408,7 +665,7 @@ unaffected.
|
|||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//[@angular](https://github.com/angular)/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
|
* **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//@angular/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
|
||||||
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
|
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
|
||||||
* **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
|
* **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
|
||||||
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
|
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
|
||||||
@ -483,7 +740,7 @@ let service = TestBed.get(SERVICE_TOKEN); // type Service
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* remove [@angular](https://github.com/angular)/http dependency from [@angular](https://github.com/angular)/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
|
* remove @angular/http dependency from @angular/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
|
||||||
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
|
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
|
||||||
* **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
|
* **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
|
||||||
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
|
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
|
||||||
@ -543,7 +800,7 @@ This release contains various API docs improvements.
|
|||||||
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
|
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
|
||||||
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
|
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
|
||||||
* **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
|
* **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
|
||||||
* **bazel:** Remove [@angular](https://github.com/angular)/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
|
* **bazel:** Remove @angular/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
|
||||||
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
|
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
|
||||||
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
|
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
|
||||||
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
|
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
|
||||||
@ -564,8 +821,8 @@ This release contains various API docs improvements.
|
|||||||
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
|
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
|
||||||
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
|
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
|
||||||
|
|
||||||
This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
|
This mechanism of automatic wrapping / auto-correcting was problematic for several reasons:
|
||||||
- it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
|
- it is non-obvious and arbitrary (ex. there are more HTML elements that have rules for parent type);
|
||||||
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
|
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -966,7 +1223,7 @@ This release contains various API docs improvements.
|
|||||||
* **bazel:** unable to launch protractor test on windows ([#27850](https://github.com/angular/angular/issues/27850)) ([1e6c9be](https://github.com/angular/angular/commit/1e6c9be))
|
* **bazel:** unable to launch protractor test on windows ([#27850](https://github.com/angular/angular/issues/27850)) ([1e6c9be](https://github.com/angular/angular/commit/1e6c9be))
|
||||||
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([f57916c](https://github.com/angular/angular/commit/f57916c))
|
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([f57916c](https://github.com/angular/angular/commit/f57916c))
|
||||||
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([522919a](https://github.com/angular/angular/commit/522919a))
|
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([522919a](https://github.com/angular/angular/commit/522919a))
|
||||||
* **bazel:** fix major/minor semver check between [@angular](https://github.com/angular)/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([1cc08b4](https://github.com/angular/angular/commit/1cc08b4))
|
* **bazel:** fix major/minor semver check between @angular/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([1cc08b4](https://github.com/angular/angular/commit/1cc08b4))
|
||||||
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([8313ffc](https://github.com/angular/angular/commit/8313ffc))
|
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([8313ffc](https://github.com/angular/angular/commit/8313ffc))
|
||||||
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([44dfa60](https://github.com/angular/angular/commit/44dfa60)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
|
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([44dfa60](https://github.com/angular/angular/commit/44dfa60)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
|
||||||
* **bazel:** Set module_name and enable ng test ([#27715](https://github.com/angular/angular/issues/27715)) ([85866de](https://github.com/angular/angular/commit/85866de))
|
* **bazel:** Set module_name and enable ng test ([#27715](https://github.com/angular/angular/issues/27715)) ([85866de](https://github.com/angular/angular/commit/85866de))
|
||||||
@ -986,7 +1243,7 @@ This release contains various API docs improvements.
|
|||||||
* **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251)
|
* **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251)
|
||||||
* **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942)
|
* **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942)
|
||||||
* **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561))
|
* **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561))
|
||||||
* **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154)
|
* **platform-server:** add @angular/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154)
|
||||||
* **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27523](https://github.com/angular/angular/issues/27523)) ([ad26cd6](https://github.com/angular/angular/commit/ad26cd6)), closes [#27116](https://github.com/angular/angular/issues/27116)
|
* **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27523](https://github.com/angular/angular/issues/27523)) ([ad26cd6](https://github.com/angular/angular/commit/ad26cd6)), closes [#27116](https://github.com/angular/angular/issues/27116)
|
||||||
* **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076)
|
* **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076)
|
||||||
* **upgrade:** allow nesting components from different downgraded modules ([#27217](https://github.com/angular/angular/issues/27217)) ([bc0ee01](https://github.com/angular/angular/commit/bc0ee01))
|
* **upgrade:** allow nesting components from different downgraded modules ([#27217](https://github.com/angular/angular/issues/27217)) ([bc0ee01](https://github.com/angular/angular/commit/bc0ee01))
|
||||||
@ -1006,7 +1263,7 @@ This release contains various API docs improvements.
|
|||||||
* **animations:** mark actual descendant node as disabled ([#26180](https://github.com/angular/angular/issues/26180)) ([453589f](https://github.com/angular/angular/commit/453589f))
|
* **animations:** mark actual descendant node as disabled ([#26180](https://github.com/angular/angular/issues/26180)) ([453589f](https://github.com/angular/angular/commit/453589f))
|
||||||
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([b108e9a](https://github.com/angular/angular/commit/b108e9a))
|
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([b108e9a](https://github.com/angular/angular/commit/b108e9a))
|
||||||
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([0d8528b](https://github.com/angular/angular/commit/0d8528b))
|
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([0d8528b](https://github.com/angular/angular/commit/0d8528b))
|
||||||
* **bazel:** fix major/minor semver check between [@angular](https://github.com/angular)/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([3ed1e84](https://github.com/angular/angular/commit/3ed1e84))
|
* **bazel:** fix major/minor semver check between @angular/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([3ed1e84](https://github.com/angular/angular/commit/3ed1e84))
|
||||||
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([89ace1a](https://github.com/angular/angular/commit/89ace1a))
|
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([89ace1a](https://github.com/angular/angular/commit/89ace1a))
|
||||||
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([ef056c5](https://github.com/angular/angular/commit/ef056c5)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
|
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([ef056c5](https://github.com/angular/angular/commit/ef056c5)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
|
||||||
* **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27591](https://github.com/angular/angular/issues/27591)) ([93078e3](https://github.com/angular/angular/commit/93078e3))
|
* **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27591](https://github.com/angular/angular/issues/27591)) ([93078e3](https://github.com/angular/angular/commit/93078e3))
|
||||||
@ -1038,7 +1295,7 @@ This release contains various API docs improvements.
|
|||||||
* **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([fc2c23e](https://github.com/angular/angular/commit/fc2c23e)), closes [#25510](https://github.com/angular/angular/issues/25510)
|
* **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([fc2c23e](https://github.com/angular/angular/commit/fc2c23e)), closes [#25510](https://github.com/angular/angular/issues/25510)
|
||||||
* **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([8087b6b](https://github.com/angular/angular/commit/8087b6b))
|
* **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([8087b6b](https://github.com/angular/angular/commit/8087b6b))
|
||||||
* **compiler-cli:** ngtsc shim files not being generated on case-insensitive platforms ([#27466](https://github.com/angular/angular/issues/27466)) ([84f2928](https://github.com/angular/angular/commit/84f2928)), closes [/github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts#L681-L682](https://github.com//github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts/issues/L681-L682)
|
* **compiler-cli:** ngtsc shim files not being generated on case-insensitive platforms ([#27466](https://github.com/angular/angular/issues/27466)) ([84f2928](https://github.com/angular/angular/commit/84f2928)), closes [/github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts#L681-L682](https://github.com//github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts/issues/L681-L682)
|
||||||
* **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([236ac06](https://github.com/angular/angular/commit/236ac06)), closes [#26154](https://github.com/angular/angular/issues/26154)
|
* **platform-server:** add @angular/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([236ac06](https://github.com/angular/angular/commit/236ac06)), closes [#26154](https://github.com/angular/angular/issues/26154)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1065,7 +1322,7 @@ This release contains various API docs improvements.
|
|||||||
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
|
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
|
||||||
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
|
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
|
||||||
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
|
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
|
||||||
* **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
|
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
|
||||||
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
|
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
|
||||||
* **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([aed95fd](https://github.com/angular/angular/commit/aed95fd))
|
* **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([aed95fd](https://github.com/angular/angular/commit/aed95fd))
|
||||||
* **core:** ensure that `ɵdefineNgModule` is available in flat-file formats ([#26403](https://github.com/angular/angular/issues/26403)) ([a64859b](https://github.com/angular/angular/commit/a64859b))
|
* **core:** ensure that `ɵdefineNgModule` is available in flat-file formats ([#26403](https://github.com/angular/angular/issues/26403)) ([a64859b](https://github.com/angular/angular/commit/a64859b))
|
||||||
@ -1172,7 +1429,7 @@ This release contains various API docs improvements.
|
|||||||
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
|
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
|
||||||
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
|
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
|
||||||
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
|
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
|
||||||
* **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
|
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
|
||||||
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
|
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
|
||||||
|
|
||||||
|
|
||||||
@ -1184,7 +1441,7 @@ This release contains various API docs improvements.
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340))
|
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340))
|
||||||
* **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83))
|
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83))
|
||||||
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409))
|
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409))
|
||||||
|
|
||||||
|
|
||||||
@ -1261,7 +1518,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
|
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
|
||||||
* **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039))
|
* **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039))
|
||||||
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
|
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
|
||||||
* **core:** add missing `peerDependency ` to `[@angular](https://github.com/angular)/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54)
|
* **core:** add missing `peerDependency ` to `@angular/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54)
|
||||||
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
|
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
|
||||||
* **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb))
|
* **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb))
|
||||||
* **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f))
|
* **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f))
|
||||||
@ -1707,7 +1964,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
* **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([a2330ff](https://github.com/angular/angular/commit/a2330ff)), closes [#22723](https://github.com/angular/angular/issues/22723)
|
* **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([a2330ff](https://github.com/angular/angular/commit/a2330ff)), closes [#22723](https://github.com/angular/angular/issues/22723)
|
||||||
* **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([2b3de63](https://github.com/angular/angular/commit/2b3de63)), closes [#22734](https://github.com/angular/angular/issues/22734)
|
* **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([2b3de63](https://github.com/angular/angular/commit/2b3de63)), closes [#22734](https://github.com/angular/angular/issues/22734)
|
||||||
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([8a85888](https://github.com/angular/angular/commit/8a85888)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([8a85888](https://github.com/angular/angular/commit/8a85888)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||||
* **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([f089bf5](https://github.com/angular/angular/commit/f089bf5))
|
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([f089bf5](https://github.com/angular/angular/commit/f089bf5))
|
||||||
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([13ab91e](https://github.com/angular/angular/commit/13ab91e)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([13ab91e](https://github.com/angular/angular/commit/13ab91e)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||||
|
|
||||||
|
|
||||||
@ -1842,7 +2099,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
||||||
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280)
|
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280)
|
||||||
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||||
* **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
||||||
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||||
|
|
||||||
|
|
||||||
@ -1856,7 +2113,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
|||||||
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235)
|
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235)
|
||||||
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
|
||||||
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
|
||||||
* **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
|
||||||
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
|
||||||
|
|
||||||
|
|
||||||
@ -2303,7 +2560,7 @@ Note: Due to an animation fix back in 5.1.1 ([c2b3792](https://github.com/angula
|
|||||||
* **platform-server:** provide a way to hook into renderModule* ([#19023](https://github.com/angular/angular/issues/19023)) ([8dfc3c3](https://github.com/angular/angular/commit/8dfc3c3))
|
* **platform-server:** provide a way to hook into renderModule* ([#19023](https://github.com/angular/angular/issues/19023)) ([8dfc3c3](https://github.com/angular/angular/commit/8dfc3c3))
|
||||||
* **router:** add ActivationStart/End events ([8f79150](https://github.com/angular/angular/commit/8f79150))
|
* **router:** add ActivationStart/End events ([8f79150](https://github.com/angular/angular/commit/8f79150))
|
||||||
* **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851))
|
* **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851))
|
||||||
* **service-worker:** introduce the [@angular](https://github.com/angular)/service-worker package ([#19274](https://github.com/angular/angular/issues/19274)) ([d442b68](https://github.com/angular/angular/commit/d442b68))
|
* **service-worker:** introduce the @angular/service-worker package ([#19274](https://github.com/angular/angular/issues/19274)) ([d442b68](https://github.com/angular/angular/commit/d442b68))
|
||||||
* **upgrade:** propagate touched state of NgModelController ([59c23c7](https://github.com/angular/angular/commit/59c23c7))
|
* **upgrade:** propagate touched state of NgModelController ([59c23c7](https://github.com/angular/angular/commit/59c23c7))
|
||||||
* **upgrade:** support lazy-loading Angular module into AngularJS app ([30e76fc](https://github.com/angular/angular/commit/30e76fc))
|
* **upgrade:** support lazy-loading Angular module into AngularJS app ([30e76fc](https://github.com/angular/angular/commit/30e76fc))
|
||||||
* update angular to support TypeScript 2.4 ([ca5aeba](https://github.com/angular/angular/commit/ca5aeba))
|
* update angular to support TypeScript 2.4 ([ca5aeba](https://github.com/angular/angular/commit/ca5aeba))
|
||||||
@ -2527,7 +2784,7 @@ Because of multiple bugs and browser inconsistencies, we have dropped the intl a
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **animations:** do not leak DOM nodes/styling for host triggered animations ([#18853](https://github.com/angular/angular/issues/18853)) ([1cc3fe2](https://github.com/angular/angular/commit/1cc3fe2)), closes [#18606](https://github.com/angular/angular/issues/18606)
|
* **animations:** do not leak DOM nodes/styling for host triggered animations ([#18853](https://github.com/angular/angular/issues/18853)) ([1cc3fe2](https://github.com/angular/angular/commit/1cc3fe2)), closes [#18606](https://github.com/angular/angular/issues/18606)
|
||||||
* **common:** fix improper packaging for [@angular](https://github.com/angular)/common/http ([#18613](https://github.com/angular/angular/issues/18613)) ([a203a95](https://github.com/angular/angular/commit/a203a95))
|
* **common:** fix improper packaging for @angular/common/http ([#18613](https://github.com/angular/angular/issues/18613)) ([a203a95](https://github.com/angular/angular/commit/a203a95))
|
||||||
* **common:** fix XSSI prefix stripping by using JSON.parse always ([#18466](https://github.com/angular/angular/issues/18466)) ([8821723](https://github.com/angular/angular/commit/8821723)), closes [#18396](https://github.com/angular/angular/issues/18396) [#18453](https://github.com/angular/angular/issues/18453)
|
* **common:** fix XSSI prefix stripping by using JSON.parse always ([#18466](https://github.com/angular/angular/issues/18466)) ([8821723](https://github.com/angular/angular/commit/8821723)), closes [#18396](https://github.com/angular/angular/issues/18396) [#18453](https://github.com/angular/angular/issues/18453)
|
||||||
* **compiler:** normalize the locale name ([#18963](https://github.com/angular/angular/issues/18963)) ([497e017](https://github.com/angular/angular/commit/497e017))
|
* **compiler:** normalize the locale name ([#18963](https://github.com/angular/angular/issues/18963)) ([497e017](https://github.com/angular/angular/commit/497e017))
|
||||||
* **core:** complete EventEmitter in QueryList on component destroy ([#18902](https://github.com/angular/angular/issues/18902)) ([7d137d7](https://github.com/angular/angular/commit/7d137d7)), closes [#18741](https://github.com/angular/angular/issues/18741)
|
* **core:** complete EventEmitter in QueryList on component destroy ([#18902](https://github.com/angular/angular/issues/18902)) ([7d137d7](https://github.com/angular/angular/commit/7d137d7)), closes [#18741](https://github.com/angular/angular/issues/18741)
|
||||||
@ -2868,7 +3125,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
* **compiler-cli:** allow '==' to compare nullable types ([#16731](https://github.com/angular/angular/issues/16731)) ([d761059](https://github.com/angular/angular/commit/d761059))
|
* **compiler-cli:** allow '==' to compare nullable types ([#16731](https://github.com/angular/angular/issues/16731)) ([d761059](https://github.com/angular/angular/commit/d761059))
|
||||||
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([f0f6544](https://github.com/angular/angular/commit/f0f6544)), closes [#15578](https://github.com/angular/angular/issues/15578)
|
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([f0f6544](https://github.com/angular/angular/commit/f0f6544)), closes [#15578](https://github.com/angular/angular/issues/15578)
|
||||||
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([fcc91d8](https://github.com/angular/angular/commit/fcc91d8)), closes [#14321](https://github.com/angular/angular/issues/14321)
|
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([fcc91d8](https://github.com/angular/angular/commit/fcc91d8)), closes [#14321](https://github.com/angular/angular/issues/14321)
|
||||||
* **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9da6340](https://github.com/angular/angular/commit/9da6340)), closes [#15521](https://github.com/angular/angular/issues/15521)
|
* **http:** flatten metadata for @angular/http/testing ([9da6340](https://github.com/angular/angular/commit/9da6340)), closes [#15521](https://github.com/angular/angular/issues/15521)
|
||||||
* **http:** honor RequestArgs.search and RequestArgs.params map type ([aef5245](https://github.com/angular/angular/commit/aef5245)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
|
* **http:** honor RequestArgs.search and RequestArgs.params map type ([aef5245](https://github.com/angular/angular/commit/aef5245)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
|
||||||
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([7ae7a84](https://github.com/angular/angular/commit/7ae7a84)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
|
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([7ae7a84](https://github.com/angular/angular/commit/7ae7a84)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
|
||||||
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([5d4b36f](https://github.com/angular/angular/commit/5d4b36f)), closes [#16310](https://github.com/angular/angular/issues/16310)
|
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([5d4b36f](https://github.com/angular/angular/commit/5d4b36f)), closes [#16310](https://github.com/angular/angular/issues/16310)
|
||||||
@ -2924,7 +3181,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
|
|||||||
* **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([d0e1688](https://github.com/angular/angular/commit/d0e1688))
|
* **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([d0e1688](https://github.com/angular/angular/commit/d0e1688))
|
||||||
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([ee6705a](https://github.com/angular/angular/commit/ee6705a)), closes [#15578](https://github.com/angular/angular/issues/15578)
|
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([ee6705a](https://github.com/angular/angular/commit/ee6705a)), closes [#15578](https://github.com/angular/angular/issues/15578)
|
||||||
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([9218812](https://github.com/angular/angular/commit/9218812)), closes [#14321](https://github.com/angular/angular/issues/14321)
|
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([9218812](https://github.com/angular/angular/commit/9218812)), closes [#14321](https://github.com/angular/angular/issues/14321)
|
||||||
* **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9c70a3c](https://github.com/angular/angular/commit/9c70a3c)), closes [#15521](https://github.com/angular/angular/issues/15521)
|
* **http:** flatten metadata for @angular/http/testing ([9c70a3c](https://github.com/angular/angular/commit/9c70a3c)), closes [#15521](https://github.com/angular/angular/issues/15521)
|
||||||
* **http:** honor RequestArgs.search and RequestArgs.params map type ([63066f7](https://github.com/angular/angular/commit/63066f7)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
|
* **http:** honor RequestArgs.search and RequestArgs.params map type ([63066f7](https://github.com/angular/angular/commit/63066f7)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
|
||||||
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([ec3b6e9](https://github.com/angular/angular/commit/ec3b6e9)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
|
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([ec3b6e9](https://github.com/angular/angular/commit/ec3b6e9)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
|
||||||
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([915eae5](https://github.com/angular/angular/commit/915eae5)), closes [#16310](https://github.com/angular/angular/issues/16310)
|
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([915eae5](https://github.com/angular/angular/commit/915eae5)), closes [#16310](https://github.com/angular/angular/issues/16310)
|
||||||
@ -3554,7 +3811,7 @@ Note: the 4.0.0-rc.0 release on npm accidentally omitted one bug fix, so we cut
|
|||||||
* **core:** add isStable Observable property to ApplicationRef to indicate when it's stable and unstable ([#14337](https://github.com/angular/angular/issues/14337)) ([c481798](https://github.com/angular/angular/commit/c481798))
|
* **core:** add isStable Observable property to ApplicationRef to indicate when it's stable and unstable ([#14337](https://github.com/angular/angular/issues/14337)) ([c481798](https://github.com/angular/angular/commit/c481798))
|
||||||
* **platform-server:** add API to render Module and ModuleFactory to string ([#14381](https://github.com/angular/angular/issues/14381)) ([b4d444a](https://github.com/angular/angular/commit/b4d444a))
|
* **platform-server:** add API to render Module and ModuleFactory to string ([#14381](https://github.com/angular/angular/issues/14381)) ([b4d444a](https://github.com/angular/angular/commit/b4d444a))
|
||||||
* **platform-server:** Implement PlatformLocation for platformServer() ([#14405](https://github.com/angular/angular/issues/14405)) ([9e28568](https://github.com/angular/angular/commit/9e28568))
|
* **platform-server:** Implement PlatformLocation for platformServer() ([#14405](https://github.com/angular/angular/issues/14405)) ([9e28568](https://github.com/angular/angular/commit/9e28568))
|
||||||
* **platform-server:** support [@angular](https://github.com/angular)/http from [@angular](https://github.com/angular)/platform-server ([9559d3e](https://github.com/angular/angular/commit/9559d3e))
|
* **platform-server:** support @angular/http from @angular/platform-server ([9559d3e](https://github.com/angular/angular/commit/9559d3e))
|
||||||
* **tsc-wrapped:** add an option to `ngc` to bundle metadata ([#14509](https://github.com/angular/angular/issues/14509)) ([3b89670](https://github.com/angular/angular/commit/3b89670))
|
* **tsc-wrapped:** add an option to `ngc` to bundle metadata ([#14509](https://github.com/angular/angular/issues/14509)) ([3b89670](https://github.com/angular/angular/commit/3b89670))
|
||||||
|
|
||||||
|
|
||||||
@ -4515,7 +4772,7 @@ Note: The 2.2.0-beta.0 release also contains all the changes present in the 2.1.
|
|||||||
* **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165)
|
* **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165)
|
||||||
* **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14))
|
* **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14))
|
||||||
* **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2))
|
* **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2))
|
||||||
* **compiler-cli:** remove peerDependency on [@angular](https://github.com/angular)/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654))
|
* **compiler-cli:** remove peerDependency on @angular/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654))
|
||||||
* **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69))
|
* **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69))
|
||||||
* **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7))
|
* **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7))
|
||||||
* **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da))
|
* **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da))
|
||||||
|
@ -222,6 +222,7 @@ The following is the list of supported scopes:
|
|||||||
* **router**
|
* **router**
|
||||||
* **service-worker**
|
* **service-worker**
|
||||||
* **upgrade**
|
* **upgrade**
|
||||||
|
* **zone.js**
|
||||||
|
|
||||||
There are currently a few exceptions to the "use package name" rule:
|
There are currently a few exceptions to the "use package name" rule:
|
||||||
|
|
||||||
@ -231,6 +232,7 @@ There are currently a few exceptions to the "use package name" rule:
|
|||||||
* **changelog**: used for updating the release notes in CHANGELOG.md
|
* **changelog**: used for updating the release notes in CHANGELOG.md
|
||||||
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
||||||
repo
|
repo
|
||||||
|
* **ivy**: used for changes to the [Ivy renderer](https://github.com/angular/angular/issues/21706).
|
||||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
||||||
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
||||||
specific package (e.g. `docs: fix typo in tutorial`).
|
specific package (e.g. `docs: fix typo in tutorial`).
|
||||||
|
50
WORKSPACE
50
WORKSPACE
@ -18,8 +18,11 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
|||||||
# Fetch rules_nodejs so we can install our npm dependencies
|
# Fetch rules_nodejs so we can install our npm dependencies
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
sha256 = "e04a82a72146bfbca2d0575947daa60fda1878c8d3a3afe868a8ec39a6b968bb",
|
patch_args = ["-p1"],
|
||||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.31.1/rules_nodejs-0.31.1.tar.gz"],
|
# Patch https://github.com/bazelbuild/rules_nodejs/pull/903
|
||||||
|
patches = ["//tools:rollup_bundle_commonjs_ignoreGlobal.patch"],
|
||||||
|
sha256 = "7c4a690268be97c96f04d505224ec4cb1ae53c2c2b68be495c9bd2634296a5cd",
|
||||||
|
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.34.0/rules_nodejs-0.34.0.tar.gz"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check the bazel version and download npm dependencies
|
# Check the bazel version and download npm dependencies
|
||||||
@ -27,6 +30,7 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "check_rules
|
|||||||
|
|
||||||
# Bazel version must be at least the following version because:
|
# Bazel version must be at least the following version because:
|
||||||
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
|
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
|
||||||
|
# - 0.27.0 has a fix for managed_directories after `rm -rf node_modules`
|
||||||
check_bazel_version(
|
check_bazel_version(
|
||||||
message = """
|
message = """
|
||||||
You no longer need to install Bazel on your machine.
|
You no longer need to install Bazel on your machine.
|
||||||
@ -35,7 +39,7 @@ Try running `yarn bazel` instead.
|
|||||||
(If you did run that, check that you've got a fresh `yarn install`)
|
(If you did run that, check that you've got a fresh `yarn install`)
|
||||||
|
|
||||||
""",
|
""",
|
||||||
minimum_bazel_version = "0.26.0",
|
minimum_bazel_version = "0.27.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
# The NodeJS rules version must be at least the following version because:
|
# The NodeJS rules version must be at least the following version because:
|
||||||
@ -46,7 +50,11 @@ Try running `yarn bazel` instead.
|
|||||||
# - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support
|
# - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support
|
||||||
# - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature
|
# - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature
|
||||||
# - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label
|
# - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label
|
||||||
check_rules_nodejs_version(minimum_version_string = "0.31.1")
|
# - 0.32.0 yarn_install and npm_install no longer puts build files under symlinked node_modules
|
||||||
|
# - 0.32.1 remove override of @bazel/tsetse & exclude typescript lib declarations in node_module_library transitive_declarations
|
||||||
|
# - 0.32.2 resolves bug in @bazel/hide-bazel-files postinstall step
|
||||||
|
# - 0.34.0 introduces protractor rule
|
||||||
|
check_rules_nodejs_version(minimum_version_string = "0.34.0")
|
||||||
|
|
||||||
# Setup the Node.js toolchain
|
# Setup the Node.js toolchain
|
||||||
node_repositories(
|
node_repositories(
|
||||||
@ -70,19 +78,7 @@ node_repositories(
|
|||||||
|
|
||||||
yarn_install(
|
yarn_install(
|
||||||
name = "npm",
|
name = "npm",
|
||||||
data = [
|
|
||||||
"//:tools/npm/@angular_bazel/index.js",
|
|
||||||
"//:tools/npm/@angular_bazel/package.json",
|
|
||||||
"//:tools/postinstall-patches.js",
|
|
||||||
"//:tools/yarn/check-yarn.js",
|
|
||||||
],
|
|
||||||
package_json = "//:package.json",
|
package_json = "//:package.json",
|
||||||
# Don't install devDependencies, they are large and not used under Bazel
|
|
||||||
prod_only = True,
|
|
||||||
# Temporarily disable node_modules symlinking until the fix for
|
|
||||||
# https://github.com/bazelbuild/bazel/issues/8487 makes it into a
|
|
||||||
# future Bazel release
|
|
||||||
symlink_node_modules = False,
|
|
||||||
yarn_lock = "//:yarn.lock",
|
yarn_lock = "//:yarn.lock",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -96,6 +92,11 @@ load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
|
|||||||
|
|
||||||
rules_angular_dev_dependencies()
|
rules_angular_dev_dependencies()
|
||||||
|
|
||||||
|
# Load protractor dependencies
|
||||||
|
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
|
||||||
|
|
||||||
|
npm_bazel_protractor_dependencies()
|
||||||
|
|
||||||
# Load karma dependencies
|
# Load karma dependencies
|
||||||
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
|
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
|
||||||
|
|
||||||
@ -132,17 +133,20 @@ load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig")
|
|||||||
|
|
||||||
rbe_autoconfig(
|
rbe_autoconfig(
|
||||||
name = "rbe_ubuntu1604_angular",
|
name = "rbe_ubuntu1604_angular",
|
||||||
# The sha256 of marketplace.gcr.io/google/rbe-ubuntu16-04 container that is
|
# Need to specify a base container digest in order to ensure that we can use the checked-in
|
||||||
# used by rbe_autoconfig() to pair toolchain configs in the @bazel_toolchains repo.
|
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
|
||||||
base_container_digest = "sha256:677c1317f14c6fd5eba2fd8ec645bfdc5119f64b3e5e944e13c89e0525cc8ad1",
|
# need to pull the image and run it in order determine the toolchain configuration. See:
|
||||||
|
# https://github.com/bazelbuild/bazel-toolchains/blob/0.27.0/configs/ubuntu16_04_clang/versions.bzl
|
||||||
|
base_container_digest = "sha256:94d7d8552902d228c32c8c148cc13f0effc2b4837757a6e95b73fdc5c5e4b07b",
|
||||||
# Note that if you change the `digest`, you might also need to update the
|
# Note that if you change the `digest`, you might also need to update the
|
||||||
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
||||||
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
||||||
# the same Clang and JDK installed.
|
# the same Clang and JDK installed. Clang is needed because of the dependency on
|
||||||
# Clang is needed because of the dependency on @com_google_protobuf.
|
# @com_google_protobuf. Java is needed for the Bazel's test executor Java tool.
|
||||||
# Java is needed for the Bazel's test executor Java tool.
|
digest = "sha256:76e2e4a894f9ffbea0a0cb2fbde741b5d223d40f265dbb9bca78655430173990",
|
||||||
digest = "sha256:74a8e9dca4781d5f277a7bd8e7ea7ed0f5906c79c9cd996205b6d32f090c62f3",
|
|
||||||
env = clang_env(),
|
env = clang_env(),
|
||||||
registry = "marketplace.gcr.io",
|
registry = "marketplace.gcr.io",
|
||||||
|
# We can't use the default "ubuntu16_04" RBE image provided by the autoconfig because we need
|
||||||
|
# a specific Linux kernel that comes with "libx11" in order to run headless browser tests.
|
||||||
repository = "google/rbe-ubuntu16-04-webtest",
|
repository = "google/rbe-ubuntu16-04-webtest",
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ The Angular CLI is a command-line interface tool that you use to initialize, dev
|
|||||||
Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.
|
Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.
|
||||||
|
|
||||||
Install the CLI using the `npm` package manager:
|
Install the CLI using the `npm` package manager:
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
npm install -g @angular/cli
|
npm install -g @angular/cli
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -20,14 +20,14 @@ Invoke the tool on the command line through the `ng` executable.
|
|||||||
Online help is available on the command line.
|
Online help is available on the command line.
|
||||||
Enter the following to list commands or options for a given command (such as [generate](cli/generate)) with a short description.
|
Enter the following to list commands or options for a given command (such as [generate](cli/generate)) with a short description.
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng help
|
ng help
|
||||||
ng generate --help
|
ng generate --help
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
To create, build, and serve a new, basic Angular project on a development server, go to the parent directory of your new workspace use the following commands:
|
To create, build, and serve a new, basic Angular project on a development server, go to the parent directory of your new workspace use the following commands:
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng new my-first-project
|
ng new my-first-project
|
||||||
cd my-first-project
|
cd my-first-project
|
||||||
ng serve
|
ng serve
|
||||||
@ -36,6 +36,14 @@ ng serve
|
|||||||
In your browser, open http://localhost:4200/ to see the new app run.
|
In your browser, open http://localhost:4200/ to see the new app run.
|
||||||
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
|
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
|
||||||
|
|
||||||
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
|
When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory. Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.
|
||||||
|
|
||||||
|
If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>` first.
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
## Workspaces and project files
|
## Workspaces and project files
|
||||||
|
|
||||||
The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton.
|
The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton.
|
||||||
@ -75,7 +83,7 @@ Command syntax is shown as follows:
|
|||||||
Option aliases are prefixed with a single dash (-).
|
Option aliases are prefixed with a single dash (-).
|
||||||
Arguments are not prefixed.
|
Arguments are not prefixed.
|
||||||
For example:
|
For example:
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng build my-app -c production
|
ng build my-app -c production
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ describe('Attribute directives', () => {
|
|||||||
greenRb.click();
|
greenRb.click();
|
||||||
browser.actions().mouseMove(highlightedEle).perform();
|
browser.actions().mouseMove(highlightedEle).perform();
|
||||||
|
|
||||||
// Wait for up to 2s for the background color to be updated,
|
// Wait for up to 4s for the background color to be updated,
|
||||||
// to account for slow environments (e.g. CI).
|
// to account for slow environments (e.g. CI).
|
||||||
browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 2000);
|
browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 4000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 32 KiB |
@ -18,7 +18,7 @@ export class AppComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteItem(item: Item) {
|
deleteItem(item: Item) {
|
||||||
alert(`Delete the ${item}.`);
|
alert(`Delete the ${item.name}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickMe(event?: KeyboardEvent) {
|
onClickMe(event?: KeyboardEvent) {
|
||||||
|
@ -16,13 +16,17 @@
|
|||||||
<!-- #enddocregion checkout-form-1 -->
|
<!-- #enddocregion checkout-form-1 -->
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>Name</label>
|
<label for="name">
|
||||||
<input type="text" formControlName="name">
|
Name
|
||||||
|
</label>
|
||||||
|
<input id="name" type="text" formControlName="name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>Address</label>
|
<label for="address">
|
||||||
<input type="text" formControlName="address">
|
Address
|
||||||
|
</label>
|
||||||
|
<input id="address" type="text" formControlName="address">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="button" type="submit">Purchase</button>
|
<button class="button" type="submit">Purchase</button>
|
||||||
|
@ -21,18 +21,21 @@ export class HeroesComponent implements OnInit {
|
|||||||
|
|
||||||
getHeroes(): void {
|
getHeroes(): void {
|
||||||
this.heroesService.getHeroes()
|
this.heroesService.getHeroes()
|
||||||
.subscribe(heroes => this.heroes = heroes);
|
.subscribe(heroes => (this.heroes = heroes));
|
||||||
}
|
}
|
||||||
|
|
||||||
add(name: string): void {
|
add(name: string): void {
|
||||||
this.editHero = undefined;
|
this.editHero = undefined;
|
||||||
name = name.trim();
|
name = name.trim();
|
||||||
if (!name) { return; }
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The server will generate the id for this new hero
|
// The server will generate the id for this new hero
|
||||||
const newHero: Hero = { name } as Hero;
|
const newHero: Hero = { name } as Hero;
|
||||||
// #docregion add-hero-subscribe
|
// #docregion add-hero-subscribe
|
||||||
this.heroesService.addHero(newHero)
|
this.heroesService
|
||||||
|
.addHero(newHero)
|
||||||
.subscribe(hero => this.heroes.push(hero));
|
.subscribe(hero => this.heroes.push(hero));
|
||||||
// #enddocregion add-hero-subscribe
|
// #enddocregion add-hero-subscribe
|
||||||
}
|
}
|
||||||
@ -40,7 +43,9 @@ export class HeroesComponent implements OnInit {
|
|||||||
delete(hero: Hero): void {
|
delete(hero: Hero): void {
|
||||||
this.heroes = this.heroes.filter(h => h !== hero);
|
this.heroes = this.heroes.filter(h => h !== hero);
|
||||||
// #docregion delete-hero-subscribe
|
// #docregion delete-hero-subscribe
|
||||||
this.heroesService.deleteHero(hero.id).subscribe();
|
this.heroesService
|
||||||
|
.deleteHero(hero.id)
|
||||||
|
.subscribe();
|
||||||
// #enddocregion delete-hero-subscribe
|
// #enddocregion delete-hero-subscribe
|
||||||
/*
|
/*
|
||||||
// #docregion delete-hero-no-subscribe
|
// #docregion delete-hero-no-subscribe
|
||||||
@ -50,25 +55,29 @@ export class HeroesComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
edit(hero) {
|
edit(hero: Hero) {
|
||||||
this.editHero = hero;
|
this.editHero = hero;
|
||||||
}
|
}
|
||||||
|
|
||||||
search(searchTerm: string) {
|
search(searchTerm: string) {
|
||||||
this.editHero = undefined;
|
this.editHero = undefined;
|
||||||
if (searchTerm) {
|
if (searchTerm) {
|
||||||
this.heroesService.searchHeroes(searchTerm)
|
this.heroesService
|
||||||
.subscribe(heroes => this.heroes = heroes);
|
.searchHeroes(searchTerm)
|
||||||
|
.subscribe(heroes => (this.heroes = heroes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
if (this.editHero) {
|
if (this.editHero) {
|
||||||
this.heroesService.updateHero(this.editHero)
|
this.heroesService
|
||||||
|
.updateHero(this.editHero)
|
||||||
.subscribe(hero => {
|
.subscribe(hero => {
|
||||||
// replace the hero in the heroes list with update from server
|
// replace the hero in the heroes list with update from server
|
||||||
const ix = hero ? this.heroes.findIndex(h => h.id === hero.id) : -1;
|
const ix = hero ? this.heroes.findIndex(h => h.id === hero.id) : -1;
|
||||||
if (ix > -1) { this.heroes[ix] = hero; }
|
if (ix > -1) {
|
||||||
|
this.heroes[ix] = hero;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.editHero = undefined;
|
this.editHero = undefined;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ export class PackageSearchService {
|
|||||||
// TODO: Add error handling
|
// TODO: Add error handling
|
||||||
return this.http.get(searchUrl, options).pipe(
|
return this.http.get(searchUrl, options).pipe(
|
||||||
map((data: any) => {
|
map((data: any) => {
|
||||||
return data.results.map(entry => ({
|
return data.results.map((entry: any) => ({
|
||||||
name: entry.name[0],
|
name: entry.name[0],
|
||||||
version: entry.version[0],
|
version: entry.version[0],
|
||||||
description: entry.description[0]
|
description: entry.description[0]
|
||||||
|
@ -10,7 +10,6 @@ export class AppComponent {
|
|||||||
gender = 'female';
|
gender = 'female';
|
||||||
fly = true;
|
fly = true;
|
||||||
logo = 'https://angular.io/assets/images/logos/angular/angular.png';
|
logo = 'https://angular.io/assets/images/logos/angular/angular.png';
|
||||||
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
|
||||||
inc(i: number) {
|
inc(i: number) {
|
||||||
this.minutes = Math.min(5, Math.max(0, this.minutes + i));
|
this.minutes = Math.min(5, Math.max(0, this.minutes + i));
|
||||||
}
|
}
|
||||||
|
14
aio/content/examples/ngmodules/src/app/app.module.1.ts
Normal file
14
aio/content/examples/ngmodules/src/app/app.module.1.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// imports
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
// @NgModule decorator with its metadata
|
||||||
|
@NgModule({
|
||||||
|
declarations: [AppComponent],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
@ -2,42 +2,49 @@
|
|||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
// Not yet complete
|
// TODO Not yet complete
|
||||||
describe('Template Syntax', function () {
|
describe('Template Syntax', () => {
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to use interpolation with a hero', function () {
|
it('should be able to use interpolation with a hero', () => {
|
||||||
let heroInterEle = element.all(by.css('h2+p')).get(0);
|
const heroInterEle = element.all(by.css('h2+p')).get(0);
|
||||||
expect(heroInterEle.getText()).toEqual('My current hero is Hercules');
|
expect(heroInterEle.getText()).toEqual('My current hero is Hercules');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to use interpolation with a calculation', function () {
|
it('should be able to use interpolation with a calculation', () => {
|
||||||
let theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of'));
|
const theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of'));
|
||||||
expect(theSumEles.count()).toBe(2);
|
expect(theSumEles.count()).toBe(2);
|
||||||
expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2');
|
expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2');
|
||||||
expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4');
|
expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to use class binding syntax', function () {
|
it('should be able to use class binding syntax', () => {
|
||||||
let specialEle = element(by.cssContainingText('div', 'Special'));
|
const specialEle = element(by.cssContainingText('div', 'Special'));
|
||||||
expect(specialEle.getAttribute('class')).toMatch('special');
|
expect(specialEle.getAttribute('class')).toMatch('special');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to use style binding syntax', function () {
|
it('should be able to use style binding syntax', () => {
|
||||||
let specialButtonEle = element(by.cssContainingText('div.special~button', 'button'));
|
const specialButtonEle = element(by.cssContainingText('div.special~button', 'button'));
|
||||||
expect(specialButtonEle.getAttribute('style')).toMatch('color: red');
|
expect(specialButtonEle.getAttribute('style')).toMatch('color: red');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should two-way bind to sizer', async () => {
|
it('should two-way bind to sizer', async () => {
|
||||||
let div = element(by.css('div#two-way-1'));
|
const div = element(by.css('div#two-way-1'));
|
||||||
let incButton = div.element(by.buttonText('+'));
|
const incButton = div.element(by.buttonText('+'));
|
||||||
let input = div.element(by.css('input'));
|
const input = div.element(by.css('input'));
|
||||||
let initSize = await input.getAttribute('value');
|
const initSize = await input.getAttribute('value');
|
||||||
incButton.click();
|
incButton.click();
|
||||||
expect(input.getAttribute('value')).toEqual((+initSize + 1).toString());
|
expect(input.getAttribute('value')).toEqual((+initSize + 1).toString());
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
it('should change SVG rectangle\'s fill color on click', async () => {
|
||||||
|
const div = element(by.css('app-svg'));
|
||||||
|
const colorSquare = div.element(by.css('rect'));
|
||||||
|
const initialColor = await colorSquare.getAttribute('fill');
|
||||||
|
colorSquare.click();
|
||||||
|
expect(colorSquare.getAttribute('fill')).not.toEqual(initialColor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
|
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
|
||||||
<a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br>
|
<a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br>
|
||||||
<a href="#enums">Enums</a><br>
|
<a href="#enums">Enums</a><br>
|
||||||
|
<a href="#svg-templates">SVG Templates</a><br>
|
||||||
|
|
||||||
<!-- Interpolation and expressions -->
|
<!-- Interpolation and expressions -->
|
||||||
<hr><h2 id="interpolation">Interpolation</h2>
|
<hr><h2 id="interpolation">Interpolation</h2>
|
||||||
@ -442,7 +443,7 @@ button</button>
|
|||||||
|
|
||||||
<!-- #docregion without-NgModel -->
|
<!-- #docregion without-NgModel -->
|
||||||
<input [value]="currentHero.name"
|
<input [value]="currentHero.name"
|
||||||
(input)="currentHero.name=$event.target.value" >
|
(input)="updateCurrentHeroName($event)">
|
||||||
<!-- #enddocregion without-NgModel -->
|
<!-- #enddocregion without-NgModel -->
|
||||||
without NgModel
|
without NgModel
|
||||||
<br>
|
<br>
|
||||||
@ -752,7 +753,7 @@ bindon-ngModel
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<!-- pipe price to USD and display the $ symbol -->
|
<!-- pipe price to USD and display the $ symbol -->
|
||||||
<label>Price: </label>{{product.price | currency:'USD':true}}
|
<label>Price: </label>{{product.price | currency:'USD':'symbol'}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="to-toc" href="#toc">top</a>
|
<a class="to-toc" href="#toc">top</a>
|
||||||
@ -857,3 +858,9 @@ The null hero's name is {{nullHero && nullHero.name}}
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a class="to-toc" href="#toc">top</a>
|
<a class="to-toc" href="#toc">top</a>
|
||||||
|
|
||||||
|
<hr><h2 id="svg-templates">SVG Templates</h2>
|
||||||
|
<!-- #docregion svg-templates -->
|
||||||
|
<app-svg></app-svg>
|
||||||
|
<!-- #enddocregion svg-templates -->
|
||||||
|
<a class="to-toc" href="#toc">top</a>
|
||||||
|
@ -5,7 +5,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren }
|
|||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export enum Color {Red, Green, Blue};
|
export enum Color {Red, Green, Blue}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Giant grab bag of stuff to drive the chapter
|
* Giant grab bag of stuff to drive the chapter
|
||||||
@ -66,6 +66,10 @@ export class AppComponent implements AfterViewInit, OnInit {
|
|||||||
|
|
||||||
currentHero: Hero;
|
currentHero: Hero;
|
||||||
|
|
||||||
|
updateCurrentHeroName(event: Event) {
|
||||||
|
this.currentHero.name = (event.target as any).value;
|
||||||
|
}
|
||||||
|
|
||||||
deleteHero(hero?: Hero) {
|
deleteHero(hero?: Hero) {
|
||||||
this.alert(`Delete ${hero ? hero.name : 'the hero'}.`);
|
this.alert(`Delete ${hero ? hero.name : 'the hero'}.`);
|
||||||
}
|
}
|
||||||
@ -105,13 +109,13 @@ export class AppComponent implements AfterViewInit, OnInit {
|
|||||||
|
|
||||||
get nullHero(): Hero { return null; }
|
get nullHero(): Hero { return null; }
|
||||||
|
|
||||||
onClickMe(event?: KeyboardEvent) {
|
onClickMe(event?: MouseEvent) {
|
||||||
let evtMsg = event ? ' Event target class is ' + (<HTMLElement>event.target).className : '';
|
const evtMsg = event ? ' Event target class is ' + (event.target as HTMLElement).className : '';
|
||||||
this.alert('Click me.' + evtMsg);
|
this.alert('Click me.' + evtMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave(event?: KeyboardEvent) {
|
onSave(event?: MouseEvent) {
|
||||||
let evtMsg = event ? ' Event target is ' + (<HTMLElement>event.target).textContent : '';
|
const evtMsg = event ? ' Event target is ' + (event.target as HTMLElement).textContent : '';
|
||||||
this.alert('Saved.' + evtMsg);
|
this.alert('Saved.' + evtMsg);
|
||||||
if (event) { event.stopPropagation(); }
|
if (event) { event.stopPropagation(); }
|
||||||
}
|
}
|
||||||
@ -140,9 +144,9 @@ export class AppComponent implements AfterViewInit, OnInit {
|
|||||||
setCurrentClasses() {
|
setCurrentClasses() {
|
||||||
// CSS classes: added/removed per current state of component properties
|
// CSS classes: added/removed per current state of component properties
|
||||||
this.currentClasses = {
|
this.currentClasses = {
|
||||||
'saveable': this.canSave,
|
saveable: this.canSave,
|
||||||
'modified': !this.isUnchanged,
|
modified: !this.isUnchanged,
|
||||||
'special': this.isSpecial
|
special: this.isSpecial
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// #enddocregion setClasses
|
// #enddocregion setClasses
|
||||||
@ -164,7 +168,7 @@ export class AppComponent implements AfterViewInit, OnInit {
|
|||||||
// #enddocregion trackByHeroes
|
// #enddocregion trackByHeroes
|
||||||
|
|
||||||
// #docregion trackById
|
// #docregion trackById
|
||||||
trackById(index: number, item: any): number { return item['id']; }
|
trackById(index: number, item: any): number { return item.id; }
|
||||||
// #enddocregion trackById
|
// #enddocregion trackById
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import { ClickDirective, ClickDirective2 } from './click.directive';
|
|||||||
import { HeroFormComponent } from './hero-form.component';
|
import { HeroFormComponent } from './hero-form.component';
|
||||||
import { heroSwitchComponents } from './hero-switch.components';
|
import { heroSwitchComponents } from './hero-switch.components';
|
||||||
import { SizerComponent } from './sizer.component';
|
import { SizerComponent } from './sizer.component';
|
||||||
|
import { SvgComponent } from './svg.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -22,7 +23,8 @@ import { SizerComponent } from './sizer.component';
|
|||||||
heroSwitchComponents,
|
heroSwitchComponents,
|
||||||
ClickDirective,
|
ClickDirective,
|
||||||
ClickDirective2,
|
ClickDirective2,
|
||||||
SizerComponent
|
SizerComponent,
|
||||||
|
SvgComponent
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ]
|
bootstrap: [ AppComponent ]
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* tslint:disable use-output-property-decorator directive-class-suffix */
|
/* tslint:disable directive-selector directive-class-suffix */
|
||||||
// #docplaster
|
// #docplaster
|
||||||
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
|
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@ -15,10 +15,11 @@ export class HeroFormComponent {
|
|||||||
@Input() hero: Hero;
|
@Input() hero: Hero;
|
||||||
@ViewChild('heroForm', {static: false}) form: NgForm;
|
@ViewChild('heroForm', {static: false}) form: NgForm;
|
||||||
|
|
||||||
|
// tslint:disable-next-line:variable-name
|
||||||
private _submitMessage = '';
|
private _submitMessage = '';
|
||||||
|
|
||||||
get submitMessage() {
|
get submitMessage() {
|
||||||
if (!this.form.valid) {
|
if (this.form && !this.form.valid) {
|
||||||
this._submitMessage = '';
|
this._submitMessage = '';
|
||||||
}
|
}
|
||||||
return this._submitMessage;
|
return this._submitMessage;
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<svg>
|
||||||
|
<g>
|
||||||
|
<rect x="0" y="0" width="100" height="100" [attr.fill]="fillColor" (click)="changeColor()" />
|
||||||
|
<text x="120" y="50">click the rectangle to change the fill color</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 201 B |
@ -0,0 +1,17 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-svg',
|
||||||
|
templateUrl: './svg.component.svg',
|
||||||
|
styleUrls: ['./svg.component.css']
|
||||||
|
})
|
||||||
|
export class SvgComponent {
|
||||||
|
fillColor = 'rgb(255, 0, 0)';
|
||||||
|
|
||||||
|
changeColor() {
|
||||||
|
const r = Math.floor(Math.random() * 256);
|
||||||
|
const g = Math.floor(Math.random() * 256);
|
||||||
|
const b = Math.floor(Math.random() * 256);
|
||||||
|
this.fillColor = `rgb(${r}, ${g}, ${b})`;
|
||||||
|
}
|
||||||
|
}
|
35
aio/content/examples/testing/e2e/src/app.e2e-spec.ts
Normal file
35
aio/content/examples/testing/e2e/src/app.e2e-spec.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
'use strict'; // necessary for es6 output in node
|
||||||
|
|
||||||
|
import { browser, element, by, ElementFinder } from 'protractor';
|
||||||
|
|
||||||
|
describe('Testing Example', () => {
|
||||||
|
const expectedViewNames = ['Dashboard', 'Heroes', 'About'];
|
||||||
|
|
||||||
|
beforeAll(() => browser.get(''));
|
||||||
|
|
||||||
|
function getPageElts() {
|
||||||
|
let navElts = element.all(by.css('app-root nav a'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
navElts: navElts,
|
||||||
|
|
||||||
|
appDashboard: element(by.css('app-root app-dashboard')),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it('has title', async() => {
|
||||||
|
expect(await browser.getTitle()).toEqual('App Under Test');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`has views ${expectedViewNames}`, async () => {
|
||||||
|
let viewNames = getPageElts().navElts.map(async(el: ElementFinder) => await el.getText());
|
||||||
|
|
||||||
|
expect(viewNames).toEqual(expectedViewNames);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has dashboard as the active view', () => {
|
||||||
|
let page = getPageElts();
|
||||||
|
|
||||||
|
expect(page.appDashboard.isPresent()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -20,7 +20,7 @@ describe('DashboardHeroComponent class only', () => {
|
|||||||
const hero: Hero = { id: 42, name: 'Test' };
|
const hero: Hero = { id: 42, name: 'Test' };
|
||||||
comp.hero = hero;
|
comp.hero = hero;
|
||||||
|
|
||||||
comp.selected.subscribe(selectedHero => expect(selectedHero).toBe(hero));
|
comp.selected.subscribe((selectedHero: Hero) => expect(selectedHero).toBe(hero));
|
||||||
comp.click();
|
comp.click();
|
||||||
});
|
});
|
||||||
// #enddocregion class-only
|
// #enddocregion class-only
|
||||||
@ -95,7 +95,7 @@ describe('DashboardHeroComponent when tested directly', () => {
|
|||||||
// #docregion click-test-3
|
// #docregion click-test-3
|
||||||
it('should raise selected event when clicked (click helper)', () => {
|
it('should raise selected event when clicked (click helper)', () => {
|
||||||
let selectedHero: Hero;
|
let selectedHero: Hero;
|
||||||
comp.selected.subscribe(hero => selectedHero = hero);
|
comp.selected.subscribe((hero: Hero) => selectedHero = hero);
|
||||||
|
|
||||||
click(heroDe); // click helper with DebugElement
|
click(heroDe); // click helper with DebugElement
|
||||||
click(heroEl); // click helper with native element
|
click(heroEl); // click helper with native element
|
||||||
|
@ -19,7 +19,7 @@ export class Hero {
|
|||||||
// #docregion ValueService
|
// #docregion ValueService
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ValueService {
|
export class ValueService {
|
||||||
protected value = 'real value';
|
value = 'real value';
|
||||||
|
|
||||||
getValue() { return this.value; }
|
getValue() { return this.value; }
|
||||||
setValue(value: string) { this.value = value; }
|
setValue(value: string) { this.value = value; }
|
||||||
|
@ -2,7 +2,3 @@ export interface Hero {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemJS bug:
|
|
||||||
// TS file must export something real in JS, not just interfaces
|
|
||||||
export const _dummy = undefined;
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, AfterViewInit, ViewChild } from '@angular/core';
|
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'sample-canvas',
|
selector: 'sample-canvas',
|
||||||
@ -6,7 +6,7 @@ import { Component, AfterViewInit, ViewChild } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class CanvasComponent implements AfterViewInit {
|
export class CanvasComponent implements AfterViewInit {
|
||||||
blobSize: number;
|
blobSize: number;
|
||||||
@ViewChild('sampleCanvas', {static: false}) sampleCanvas;
|
@ViewChild('sampleCanvas', {static: false}) sampleCanvas: ElementRef;
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms';
|
|||||||
|
|
||||||
import { HighlightDirective } from './highlight.directive';
|
import { HighlightDirective } from './highlight.directive';
|
||||||
import { TitleCasePipe } from './title-case.pipe';
|
import { TitleCasePipe } from './title-case.pipe';
|
||||||
|
import { CanvasComponent } from './canvas.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [ CommonModule ],
|
imports: [ CommonModule ],
|
||||||
@ -12,8 +13,9 @@ import { TitleCasePipe } from './title-case.pipe';
|
|||||||
// SharedModule importers won't have to import FormsModule too
|
// SharedModule importers won't have to import FormsModule too
|
||||||
FormsModule,
|
FormsModule,
|
||||||
HighlightDirective,
|
HighlightDirective,
|
||||||
TitleCasePipe
|
TitleCasePipe,
|
||||||
|
CanvasComponent
|
||||||
],
|
],
|
||||||
declarations: [ HighlightDirective, TitleCasePipe ]
|
declarations: [ HighlightDirective, TitleCasePipe, CanvasComponent ]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
import { Observable, of, throwError } from 'rxjs';
|
import { Observable, of, throwError, Observer } from 'rxjs';
|
||||||
import { concat, map, retryWhen, switchMap, take, tap } from 'rxjs/operators';
|
import { concat, map, retryWhen, switchMap, take, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Quote } from './quote';
|
import { Quote } from './quote';
|
||||||
@ -14,7 +14,7 @@ export class TwainService {
|
|||||||
private nextId = 1;
|
private nextId = 1;
|
||||||
|
|
||||||
getQuote(): Observable<string> {
|
getQuote(): Observable<string> {
|
||||||
return Observable.create(observer => observer.next(this.nextId++)).pipe(
|
return Observable.create((observer: Observer<number>) => observer.next(this.nextId++)).pipe(
|
||||||
|
|
||||||
// tap((id: number) => console.log(id)),
|
// tap((id: number) => console.log(id)),
|
||||||
// tap((id: number) => { throw new Error('Simulated server error'); }),
|
// tap((id: number) => { throw new Error('Simulated server error'); }),
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js';
|
const jasmineRequire = require('jasmine-core/lib/jasmine-core/jasmine.js');
|
||||||
|
|
||||||
window['jasmineRequire'] = jasmineRequire;
|
window['jasmineRequire'] = jasmineRequire;
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
/* HeroesComponent's private CSS styles */
|
/* HeroesComponent's private CSS styles */
|
||||||
.selected {
|
|
||||||
background-color: #CFD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes {
|
.heroes {
|
||||||
margin: 0 0 2em 0;
|
margin: 0 0 2em 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@ -19,18 +15,18 @@
|
|||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.heroes li.selected:hover {
|
|
||||||
background-color: #BBD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes li:hover {
|
.heroes li:hover {
|
||||||
color: #607D8B;
|
color: #607D8B;
|
||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
left: .1em;
|
left: .1em;
|
||||||
}
|
}
|
||||||
.heroes .text {
|
.heroes li.selected {
|
||||||
position: relative;
|
background-color: #CFD8DC;
|
||||||
top: -3px;
|
color: white;
|
||||||
|
}
|
||||||
|
.heroes li.selected:hover {
|
||||||
|
background-color: #BBD8DC;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
.heroes .badge {
|
.heroes .badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -34,4 +34,7 @@ export class HeroesComponent implements OnInit {
|
|||||||
this.selectedHero = hero;
|
this.selectedHero = hero;
|
||||||
}
|
}
|
||||||
// #enddocregion on-select
|
// #enddocregion on-select
|
||||||
|
// #docregion component
|
||||||
}
|
}
|
||||||
|
// #enddocregion component
|
||||||
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
/* HeroesComponent's private CSS styles */
|
/* HeroesComponent's private CSS styles */
|
||||||
.selected {
|
|
||||||
background-color: #CFD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes {
|
.heroes {
|
||||||
margin: 0 0 2em 0;
|
margin: 0 0 2em 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@ -19,18 +15,18 @@
|
|||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.heroes li.selected:hover {
|
|
||||||
background-color: #BBD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes li:hover {
|
.heroes li:hover {
|
||||||
color: #607D8B;
|
color: #607D8B;
|
||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
left: .1em;
|
left: .1em;
|
||||||
}
|
}
|
||||||
.heroes .text {
|
.heroes li.selected {
|
||||||
position: relative;
|
background-color: #CFD8DC;
|
||||||
top: -3px;
|
color: white;
|
||||||
|
}
|
||||||
|
.heroes li.selected:hover {
|
||||||
|
background-color: #BBD8DC;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
.heroes .badge {
|
.heroes .badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
/* HeroesComponent's private CSS styles */
|
/* HeroesComponent's private CSS styles */
|
||||||
.selected {
|
|
||||||
background-color: #CFD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes {
|
.heroes {
|
||||||
margin: 0 0 2em 0;
|
margin: 0 0 2em 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@ -19,18 +15,18 @@
|
|||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.heroes li.selected:hover {
|
|
||||||
background-color: #BBD8DC !important;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.heroes li:hover {
|
.heroes li:hover {
|
||||||
color: #607D8B;
|
color: #607D8B;
|
||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
left: .1em;
|
left: .1em;
|
||||||
}
|
}
|
||||||
.heroes .text {
|
.heroes li.selected {
|
||||||
position: relative;
|
background-color: #CFD8DC;
|
||||||
top: -3px;
|
color: white;
|
||||||
|
}
|
||||||
|
.heroes li.selected:hover {
|
||||||
|
background-color: #BBD8DC;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
.heroes .badge {
|
.heroes .badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -43,8 +39,6 @@
|
|||||||
left: -1px;
|
left: -1px;
|
||||||
top: -4px;
|
top: -4px;
|
||||||
height: 1.8em;
|
height: 1.8em;
|
||||||
min-width: 16px;
|
|
||||||
text-align: right;
|
|
||||||
margin-right: .8em;
|
margin-right: .8em;
|
||||||
border-radius: 4px 0 0 4px;
|
border-radius: 4px 0 0 4px;
|
||||||
}
|
}
|
||||||
|
13
aio/content/examples/toh-pt5/src/app/app-routing.module.1.ts
Normal file
13
aio/content/examples/toh-pt5/src/app/app-routing.module.1.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { HeroesComponent } from './heroes/heroes.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: 'heroes', component: HeroesComponent }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
@ -7,9 +7,7 @@ import { RouterModule, Routes } from '@angular/router';
|
|||||||
// #docregion import-dashboard
|
// #docregion import-dashboard
|
||||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
// #enddocregion import-dashboard
|
// #enddocregion import-dashboard
|
||||||
// #docregion heroes-route
|
|
||||||
import { HeroesComponent } from './heroes/heroes.component';
|
import { HeroesComponent } from './heroes/heroes.component';
|
||||||
// #enddocregion heroes-route
|
|
||||||
// #docregion import-herodetail
|
// #docregion import-herodetail
|
||||||
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
|
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
|
||||||
// #enddocregion import-herodetail
|
// #enddocregion import-herodetail
|
||||||
@ -39,7 +37,9 @@ const routes: Routes = [
|
|||||||
imports: [ RouterModule.forRoot(routes) ],
|
imports: [ RouterModule.forRoot(routes) ],
|
||||||
// #enddocregion ngmodule-imports
|
// #enddocregion ngmodule-imports
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
|
// #docregion export-routermodule
|
||||||
exports: [ RouterModule ]
|
exports: [ RouterModule ]
|
||||||
|
// #enddocregion export-routermodule
|
||||||
})
|
})
|
||||||
export class AppRoutingModule {}
|
export class AppRoutingModule {}
|
||||||
// #enddocregion , v1
|
// #enddocregion , v1
|
||||||
|
@ -23,13 +23,17 @@ import { HeroSearchComponent } from './hero-search/hero-search.component';
|
|||||||
// #docregion v1
|
// #docregion v1
|
||||||
import { MessagesComponent } from './messages/messages.component';
|
import { MessagesComponent } from './messages/messages.component';
|
||||||
|
|
||||||
|
// #docregion import-httpclientmodule
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
// #enddocregion import-httpclientmodule
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
// #docregion in-mem-web-api-imports
|
// #docregion in-mem-web-api-imports
|
||||||
|
// #docregion import-httpclientmodule
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
// #enddocregion import-httpclientmodule
|
||||||
|
|
||||||
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
|
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
|
||||||
// and returns simulated server responses.
|
// and returns simulated server responses.
|
||||||
@ -38,7 +42,9 @@ import { MessagesComponent } from './messages/messages.component';
|
|||||||
InMemoryDataService, { dataEncapsulation: false }
|
InMemoryDataService, { dataEncapsulation: false }
|
||||||
)
|
)
|
||||||
// #enddocregion in-mem-web-api-imports
|
// #enddocregion in-mem-web-api-imports
|
||||||
|
// #docregion import-httpclientmodule
|
||||||
],
|
],
|
||||||
|
// #enddocregion import-httpclientmodule
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
@ -50,6 +56,9 @@ import { MessagesComponent } from './messages/messages.component';
|
|||||||
// #docregion v1
|
// #docregion v1
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ]
|
bootstrap: [ AppComponent ]
|
||||||
|
// #docregion import-httpclientmodule
|
||||||
})
|
})
|
||||||
|
// #enddocregion import-httpclientmodule
|
||||||
|
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
// #enddocregion , v1
|
// #enddocregion , v1
|
||||||
|
@ -13,11 +13,6 @@ import { catchError, map, tap } from 'rxjs/operators';
|
|||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
import { MessageService } from './message.service';
|
import { MessageService } from './message.service';
|
||||||
|
|
||||||
// #docregion http-options
|
|
||||||
const httpOptions = {
|
|
||||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
|
|
||||||
};
|
|
||||||
// #enddocregion http-options
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class HeroService {
|
export class HeroService {
|
||||||
@ -26,6 +21,12 @@ export class HeroService {
|
|||||||
private heroesUrl = 'api/heroes'; // URL to web api
|
private heroesUrl = 'api/heroes'; // URL to web api
|
||||||
// #enddocregion heroesUrl
|
// #enddocregion heroesUrl
|
||||||
|
|
||||||
|
// #docregion http-options
|
||||||
|
httpOptions = {
|
||||||
|
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
|
||||||
|
};
|
||||||
|
// #enddocregion http-options
|
||||||
|
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
@ -96,7 +97,7 @@ export class HeroService {
|
|||||||
// #docregion addHero
|
// #docregion addHero
|
||||||
/** POST: add a new hero to the server */
|
/** POST: add a new hero to the server */
|
||||||
addHero (hero: Hero): Observable<Hero> {
|
addHero (hero: Hero): Observable<Hero> {
|
||||||
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
|
return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe(
|
||||||
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
|
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
|
||||||
catchError(this.handleError<Hero>('addHero'))
|
catchError(this.handleError<Hero>('addHero'))
|
||||||
);
|
);
|
||||||
@ -109,7 +110,7 @@ export class HeroService {
|
|||||||
const id = typeof hero === 'number' ? hero : hero.id;
|
const id = typeof hero === 'number' ? hero : hero.id;
|
||||||
const url = `${this.heroesUrl}/${id}`;
|
const url = `${this.heroesUrl}/${id}`;
|
||||||
|
|
||||||
return this.http.delete<Hero>(url, httpOptions).pipe(
|
return this.http.delete<Hero>(url, this.httpOptions).pipe(
|
||||||
tap(_ => this.log(`deleted hero id=${id}`)),
|
tap(_ => this.log(`deleted hero id=${id}`)),
|
||||||
catchError(this.handleError<Hero>('deleteHero'))
|
catchError(this.handleError<Hero>('deleteHero'))
|
||||||
);
|
);
|
||||||
@ -119,7 +120,7 @@ export class HeroService {
|
|||||||
// #docregion updateHero
|
// #docregion updateHero
|
||||||
/** PUT: update the hero on the server */
|
/** PUT: update the hero on the server */
|
||||||
updateHero (hero: Hero): Observable<any> {
|
updateHero (hero: Hero): Observable<any> {
|
||||||
return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
|
return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
|
||||||
tap(_ => this.log(`updated hero id=${hero.id}`)),
|
tap(_ => this.log(`updated hero id=${hero.id}`)),
|
||||||
catchError(this.handleError<any>('updateHero'))
|
catchError(this.handleError<any>('updateHero'))
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import { browser, element, by, ExpectedConditions } from 'protractor';
|
||||||
|
|
||||||
|
describe('Lazy Loading AngularJS Tests', function () {
|
||||||
|
const pageElements = {
|
||||||
|
homePageHref: element(by.cssContainingText('app-root nav a', 'Home')),
|
||||||
|
homePageParagraph: element(by.css('app-root app-home p')),
|
||||||
|
ajsUsersPageHref: element(by.cssContainingText('app-root nav a', 'Users')),
|
||||||
|
ajsUsersPageParagraph: element(by.css('app-root app-angular-js div p')),
|
||||||
|
notFoundPageHref: element(by.cssContainingText('app-root nav a', '404 Page')),
|
||||||
|
notFoundPageParagraph: element(by.css('app-root app-app404 p')),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
await browser.get('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display \'Angular Home\' when visiting the home page', async() => {
|
||||||
|
await pageElements.homePageHref.click();
|
||||||
|
|
||||||
|
const paragraphText = await pageElements.homePageParagraph.getText();
|
||||||
|
|
||||||
|
expect(paragraphText).toEqual('Angular Home');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display \'Users Page\' page when visiting the AngularJS page at /users', async() => {
|
||||||
|
await pageElements.ajsUsersPageHref.click();
|
||||||
|
await loadAngularJS();
|
||||||
|
|
||||||
|
const paragraphText = await pageElements.ajsUsersPageParagraph.getText();
|
||||||
|
|
||||||
|
expect(paragraphText).toEqual('Users Page');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display \'Angular 404\' when visiting an invalid URL', async() => {
|
||||||
|
await pageElements.notFoundPageHref.click();
|
||||||
|
|
||||||
|
const paragraphText = await pageElements.notFoundPageParagraph.getText();
|
||||||
|
|
||||||
|
expect(paragraphText).toEqual('Angular 404');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Workaround for https://github.com/angular/protractor/issues/4724
|
||||||
|
async function loadAngularJS() {
|
||||||
|
// Abort if `resumeBootstrap` has already occured
|
||||||
|
if (await browser.executeScript(`return '__TESTABILITY__NG1_APP_ROOT_INJECTOR__' in window;`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Might have to re-insert the 'NG_DEFER_BOOTSTRAP!' if the name has been changed since protractor loaded the page
|
||||||
|
if (!await browser.executeScript('window.name.includes(\'NG_DEFER_BOOTSTRAP!\')')) {
|
||||||
|
await browser.executeScript('window.name = \'NG_DEFER_BOOTSTRAP!\' + name');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the AngularJS bundle to download and initialize
|
||||||
|
await browser.wait(ExpectedConditions.presenceOf(element(by.css('app-root app-angular-js'))), 5000, 'AngularJS app');
|
||||||
|
|
||||||
|
// Run the protractor pre-bootstrap logic and resumeBootstrap
|
||||||
|
// Based on https://github.com/angular/protractor/blob/5.3.0/lib/browser.ts#L950-L969
|
||||||
|
{
|
||||||
|
let moduleNames = [];
|
||||||
|
for (const {name, script, args} of browser.mockModules_) {
|
||||||
|
moduleNames.push(name);
|
||||||
|
await browser.executeScriptWithDescription(script, 'add mock module ' + name, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.executeScriptWithDescription(
|
||||||
|
// TODO: must manually assign __TESTABILITY__NG1_APP_ROOT_INJECTOR__ (https://github.com/angular/angular/issues/22723)
|
||||||
|
`window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = angular.resumeBootstrap(arguments[0]) `
|
||||||
|
+ `|| angular.element('app-angular-js').injector();`,
|
||||||
|
'resume bootstrap',
|
||||||
|
moduleNames
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the initial AngularJS page to finish loading
|
||||||
|
await browser.waitForAngular();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"projectType": "cli-ajs"
|
||||||
|
}
|
@ -1,14 +1,22 @@
|
|||||||
import { Component, OnInit, ElementRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ElementRef } from '@angular/core';
|
||||||
import { LazyLoaderService } from '../lazy-loader.service';
|
import { LazyLoaderService } from '../lazy-loader.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-angular-js',
|
selector: 'app-angular-js',
|
||||||
template: '<div ng-view></div>'
|
template: '<div ng-view></div>'
|
||||||
})
|
})
|
||||||
export class AngularJSComponent implements OnInit {
|
export class AngularJSComponent implements OnInit, OnDestroy {
|
||||||
constructor(private lazyLoader: LazyLoaderService, private elRef: ElementRef) {}
|
constructor(
|
||||||
|
private lazyLoader: LazyLoaderService,
|
||||||
|
private elRef: ElementRef
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.lazyLoader.load(this.elRef.nativeElement);
|
this.lazyLoader.load(this.elRef.nativeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.lazyLoader.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import { App404Component } from './app404/app404.component';
|
|||||||
BrowserModule,
|
BrowserModule,
|
||||||
AppRoutingModule
|
AppRoutingModule
|
||||||
],
|
],
|
||||||
providers: [],
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import * as angular from 'angular';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class LazyLoaderService {
|
export class LazyLoaderService {
|
||||||
bootstrapped = false;
|
private app: angular.auto.IInjectorService;
|
||||||
|
|
||||||
load(el: HTMLElement): void {
|
load(el: HTMLElement): void {
|
||||||
if (this.bootstrapped) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
import('./angularjs-app').then(app => {
|
import('./angularjs-app').then(app => {
|
||||||
try {
|
try {
|
||||||
app.bootstrap(el);
|
this.app = app.bootstrap(el);
|
||||||
this.bootstrapped = true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this.app) {
|
||||||
|
this.app.get('$rootScope').$destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
181
aio/content/guide/accessibility.md
Normal file
181
aio/content/guide/accessibility.md
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
# Accessibility in Angular
|
||||||
|
|
||||||
|
The web is used by a wide variety of people, including those who have visual or motor impairments.
|
||||||
|
A variety of assistive technologies are available that make it much easier for these groups to
|
||||||
|
interact with web-based software applications.
|
||||||
|
In addition, designing an application to be more accessible generally improves the user experience for all users.
|
||||||
|
|
||||||
|
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals/).
|
||||||
|
|
||||||
|
This page discusses best practices for designing Angular applications that
|
||||||
|
work well for all users, including those who rely on assistive technologies.
|
||||||
|
|
||||||
|
## Accessibility attributes
|
||||||
|
|
||||||
|
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria)
|
||||||
|
to provide semantic meaning where it might otherwise be missing.
|
||||||
|
Use [attribute binding](guide/template-syntax#attribute-binding) template syntax to control the values of accessibility-related attributes.
|
||||||
|
|
||||||
|
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA
|
||||||
|
specification depends specifically on HTML attributes rather than properties on DOM elements.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Use attr. when binding to an ARIA attribute -->
|
||||||
|
<button [attr.aria-label]="myActionLabel">...</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this syntax is only necessary for attribute _bindings_.
|
||||||
|
Static ARIA attributes require no extra syntax.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Static ARIA attributes require no extra syntax -->
|
||||||
|
<button aria-label="Save document">...</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
|
By convention, HTML attributes use lowercase names (`tabindex`), while properties use camelCase names (`tabIndex`).
|
||||||
|
|
||||||
|
See the [Template Syntax](https://angular.io/guide/template-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Angular UI components
|
||||||
|
|
||||||
|
The [Angular Material](https://material.angular.io/) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
|
||||||
|
The [Component Development Kit (CDK)](https://material.angular.io/cdk/categories) includes the `a11y` package that provides tools to support various areas of accessibility.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region. See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
|
||||||
|
|
||||||
|
* The `cdkTrapFocus` directive traps Tab-key focus within an element. Use it to create accessible experience for components like modal dialogs, where focus must be constrained.
|
||||||
|
|
||||||
|
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.io/cdk/a11y/overview).
|
||||||
|
|
||||||
|
|
||||||
|
### Augmenting native elements
|
||||||
|
|
||||||
|
Native HTML elements capture a number of standard interaction patterns that are important to accessibility.
|
||||||
|
When authoring Angular components, you should re-use these native elements directly when possible, rather than re-implementing well-supported behaviors.
|
||||||
|
|
||||||
|
For example, instead of creating a custom element for a new variety of button, you can create a component that uses an attribute selector with a native `<button>` element.
|
||||||
|
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
|
||||||
|
|
||||||
|
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/master/src/material/button/button.ts#L66-L68), [`MatTabNav`](https://github.com/angular/components/blob/master/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L67), [`MatTable`](https://github.com/angular/components/blob/master/src/material/table/table.ts#L17).
|
||||||
|
|
||||||
|
### Using containers for native elements
|
||||||
|
|
||||||
|
Sometimes using the appropriate native element requires a container element.
|
||||||
|
For example, the native `<input>` element cannot have children, so any custom text entry components need
|
||||||
|
to wrap an `<input>` with additional elements.
|
||||||
|
While you might just include the `<input>` in your custom component's template,
|
||||||
|
this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
|
||||||
|
Instead, you can create a container component that uses content projection to include the native control in the
|
||||||
|
component's API.
|
||||||
|
|
||||||
|
You can see [`MatFormField`](https://material.angular.io/components/form-field/overview) as an example of this pattern.
|
||||||
|
|
||||||
|
## Case study: Building a custom progress bar
|
||||||
|
|
||||||
|
The following example shows how to make a simple progress bar accessible by using host binding to control accessibility-related attributes.
|
||||||
|
|
||||||
|
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes. The ARIA attribute `aria-valuenow` is bound to the user's input.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
/**
|
||||||
|
* Example progressbar component.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'example-progressbar',
|
||||||
|
template: `<div class="bar" [style.width.%]="value"></div>`,
|
||||||
|
styleUrls: ['./progress-bar.css'],
|
||||||
|
host: {
|
||||||
|
// Sets the role for this component to "progressbar"
|
||||||
|
role: 'progressbar',
|
||||||
|
|
||||||
|
// Sets the minimum and maximum values for the progressbar role.
|
||||||
|
'aria-valuemin': '0',
|
||||||
|
'aria-valuemax': '0',
|
||||||
|
|
||||||
|
// Binding that updates the current value of the progressbar.
|
||||||
|
'[attr.aria-valuenow]': 'value',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class ExampleProgressbar {
|
||||||
|
/** Current value of the progressbar. */
|
||||||
|
@Input() value: number = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<label>
|
||||||
|
Enter an example progress value
|
||||||
|
<input type="number" min="0" max="100"
|
||||||
|
[value]="progress" (input)="progress = $event.target.value">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
|
||||||
|
<example-progressbar [value]="progress" aria-label="Example of a progress bar">
|
||||||
|
</example-progressbar>
|
||||||
|
```
|
||||||
|
|
||||||
|
[See the full example in StackBlitz](https://stackblitz.com/edit/angular-kn5jdi?file=src%2Fapp%2Fapp.component.html).
|
||||||
|
|
||||||
|
## Routing and focus management
|
||||||
|
|
||||||
|
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus/) in a UI is an important consideration in designing for accessibility.
|
||||||
|
When using Angular routing, you should decide where page focus goes upon navigation.
|
||||||
|
|
||||||
|
To avoid relying solely on visual cues, you need to make sure your routing code updates focus after page navigation.
|
||||||
|
Use the `NavigationEnd` event from the `Router` service to know when to update
|
||||||
|
focus.
|
||||||
|
|
||||||
|
The following example shows how to find and focus the main content header in the DOM after navigation.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
|
||||||
|
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
|
||||||
|
const mainHeader = document.querySelector('#main-content-header')
|
||||||
|
if (mainHeader) {
|
||||||
|
mainHeader.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
In a real application, the element that receives focus will depend on your specific
|
||||||
|
application structure and layout.
|
||||||
|
The focused element should put users in a position to immediately move into the main content that has just been routed into view.
|
||||||
|
You should avoid situations where focus returns to the `body` element after a route change.
|
||||||
|
|
||||||
|
|
||||||
|
## Additional resources
|
||||||
|
|
||||||
|
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
|
||||||
|
|
||||||
|
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria/)
|
||||||
|
|
||||||
|
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
|
||||||
|
|
||||||
|
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
|
||||||
|
|
||||||
|
* [Inclusive Components](https://inclusive-components.design/)
|
||||||
|
|
||||||
|
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources/)
|
||||||
|
|
||||||
|
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web/)
|
||||||
|
|
||||||
|
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
|
||||||
|
|
||||||
|
* [Codelyzer](http://codelyzer.com/rules/) provides linting rules that can help you make sure your code meets accessibility standards.
|
||||||
|
|
||||||
|
Books
|
||||||
|
|
||||||
|
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
|
||||||
|
|
||||||
|
* "Inclusive Design Patterns", Heydon Pickering
|
@ -66,7 +66,7 @@ The following table lists some of the key AngularJS template features with their
|
|||||||
|
|
||||||
### Bindings/interpolation
|
### Bindings/interpolation
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, a template expression in curly braces still denotes one-way binding.
|
In Angular, a template expression in curly braces still denotes one-way binding.
|
||||||
@ -102,7 +102,7 @@ The following table lists some of the key AngularJS template features with their
|
|||||||
|
|
||||||
### Pipes
|
### Pipes
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular you use similar syntax with the pipe (|) character to filter output, but now you call them **pipes**.
|
In Angular you use similar syntax with the pipe (|) character to filter output, but now you call them **pipes**.
|
||||||
@ -136,7 +136,7 @@ The following table lists some of the key AngularJS template features with their
|
|||||||
|
|
||||||
### Input variables
|
### Input variables
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular has true template input variables that are explicitly defined using the `let` keyword.
|
Angular has true template input variables that are explicitly defined using the `let` keyword.
|
||||||
@ -202,10 +202,10 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Bootstrapping
|
### Bootstrapping
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts"></code-example>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular doesn't have a bootstrap directive.
|
Angular doesn't have a bootstrap directive.
|
||||||
@ -245,7 +245,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### ngClass
|
### ngClass
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, the `ngClass` directive works similarly.
|
In Angular, the `ngClass` directive works similarly.
|
||||||
@ -291,7 +291,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Bind to the `click` event
|
### Bind to the `click` event
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding"></code-example>
|
||||||
|
|
||||||
|
|
||||||
AngularJS event-based directives do not exist in Angular.
|
AngularJS event-based directives do not exist in Angular.
|
||||||
@ -338,7 +338,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Component decorator
|
### Component decorator
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, the template no longer specifies its associated controller.
|
In Angular, the template no longer specifies its associated controller.
|
||||||
@ -401,7 +401,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Bind to the `href` property
|
### Bind to the `href` property
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular uses property binding; there is no built-in *href* directive.
|
Angular uses property binding; there is no built-in *href* directive.
|
||||||
@ -412,7 +412,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
|
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link"></code-example>
|
||||||
|
|
||||||
|
|
||||||
For more information on routing, see the [RouterLink binding](guide/router#router-link)
|
For more information on routing, see the [RouterLink binding](guide/router#router-link)
|
||||||
@ -445,7 +445,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### *ngIf
|
### *ngIf
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
|
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
|
||||||
@ -480,7 +480,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### ngModel
|
### ngModel
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
|
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
|
||||||
@ -516,7 +516,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### *ngFor
|
### *ngFor
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats
|
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats
|
||||||
@ -559,7 +559,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Bind to the `hidden` property
|
### Bind to the `hidden` property
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular uses property binding; there is no built-in *show* directive.
|
Angular uses property binding; there is no built-in *show* directive.
|
||||||
@ -598,7 +598,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### Bind to the `src` property
|
### Bind to the `src` property
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular uses property binding; there is no built-in *src* directive.
|
Angular uses property binding; there is no built-in *src* directive.
|
||||||
@ -635,7 +635,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### ngStyle
|
### ngStyle
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression.
|
In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression.
|
||||||
@ -690,7 +690,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
|||||||
|
|
||||||
### ngSwitch
|
### ngSwitch
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, the `ngSwitch` directive works similarly.
|
In Angular, the `ngSwitch` directive works similarly.
|
||||||
@ -765,7 +765,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### currency
|
### currency
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The Angular `currency` pipe is similar although some of the parameters have changed.
|
The Angular `currency` pipe is similar although some of the parameters have changed.
|
||||||
@ -793,7 +793,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### date
|
### date
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The Angular `date` pipe is similar.
|
The Angular `date` pipe is similar.
|
||||||
@ -847,7 +847,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### json
|
### json
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The Angular `json` pipe does the same thing.
|
The Angular `json` pipe does the same thing.
|
||||||
@ -876,7 +876,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### slice
|
### slice
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The `SlicePipe` does the same thing but the *order of the parameters is reversed*, in keeping
|
The `SlicePipe` does the same thing but the *order of the parameters is reversed*, in keeping
|
||||||
@ -907,7 +907,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### lowercase
|
### lowercase
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The Angular `lowercase` pipe does the same thing.
|
The Angular `lowercase` pipe does the same thing.
|
||||||
@ -935,7 +935,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
|
|
||||||
### number
|
### number
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number"></code-example>
|
||||||
|
|
||||||
|
|
||||||
The Angular `number` pipe is similar.
|
The Angular `number` pipe is similar.
|
||||||
@ -1068,7 +1068,7 @@ The Angular code is shown using TypeScript.
|
|||||||
|
|
||||||
### NgModules
|
### NgModules
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts"></code-example>
|
||||||
|
|
||||||
|
|
||||||
NgModules, defined with the `NgModule` decorator, serve the same purpose:
|
NgModules, defined with the `NgModule` decorator, serve the same purpose:
|
||||||
@ -1109,7 +1109,7 @@ The Angular code is shown using TypeScript.
|
|||||||
|
|
||||||
### Component decorator
|
### Component decorator
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||||
|
|
||||||
|
|
||||||
Angular adds a decorator to the component class to provide any required metadata.
|
Angular adds a decorator to the component class to provide any required metadata.
|
||||||
@ -1145,7 +1145,7 @@ The Angular code is shown using TypeScript.
|
|||||||
|
|
||||||
### Component class
|
### Component class
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, you create a component class.
|
In Angular, you create a component class.
|
||||||
@ -1184,7 +1184,7 @@ The Angular code is shown using TypeScript.
|
|||||||
|
|
||||||
### Dependency injection
|
### Dependency injection
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di"></code-example>
|
||||||
|
|
||||||
|
|
||||||
In Angular, you pass in dependencies as arguments to the component class constructor.
|
In Angular, you pass in dependencies as arguments to the component class constructor.
|
||||||
@ -1254,7 +1254,7 @@ also encapsulate a style sheet within a specific component.
|
|||||||
|
|
||||||
|
|
||||||
### Styles configuration
|
### Styles configuration
|
||||||
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles"></code-example>
|
||||||
|
|
||||||
With the Angular CLI, you can configure your global styles in the `angular.json` file.
|
With the Angular CLI, you can configure your global styles in the `angular.json` file.
|
||||||
You can rename the extension to `.scss` to use sass.
|
You can rename the extension to `.scss` to use sass.
|
||||||
@ -1263,7 +1263,7 @@ also encapsulate a style sheet within a specific component.
|
|||||||
In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define
|
In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define
|
||||||
a style sheet for a particular component.
|
a style sheet for a particular component.
|
||||||
|
|
||||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url" linenums="false"></code-example>
|
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url"></code-example>
|
||||||
|
|
||||||
|
|
||||||
This allows you to set appropriate styles for individual components that won’t leak into
|
This allows you to set appropriate styles for individual components that won’t leak into
|
||||||
|
@ -37,8 +37,7 @@ To get started with adding Angular animations to your project, import the animat
|
|||||||
|
|
||||||
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||||
|
|
||||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
|
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -129,7 +128,7 @@ The third argument, `easing`, controls how the animation [accelerates and decele
|
|||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
**Note:** See the Angular Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
|
**Note:** See the Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
This example provides a state transition from `open` to `closed` with a one second transition between states.
|
This example provides a state transition from `open` to `closed` with a one second transition between states.
|
||||||
@ -180,9 +179,7 @@ In this example, we'll name the trigger `openClose`, and attach it to the `butto
|
|||||||
|
|
||||||
Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator.
|
Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator.
|
||||||
|
|
||||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript" region="component"></code-example>
|
||||||
region="component" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
When you've defined an animation trigger for a component, you can attach it to an element in that component's template by wrapping the trigger name in brackets and preceding it with an `@` symbol. Then, you can bind the trigger to a template expression using standard Angular property binding syntax as shown below, where `triggerName` is the name of the trigger, and `expression` evaluates to a defined animation state.
|
When you've defined an animation trigger for a component, you can attach it to an element in that component's template by wrapping the trigger name in brackets and preceding it with an `@` symbol. Then, you can bind the trigger to a template expression using standard Angular property binding syntax as shown below, where `triggerName` is the name of the trigger, and `expression` evaluates to a defined animation state.
|
||||||
|
|
||||||
|
@ -945,7 +945,7 @@ import { calculateValue } from './utilities';
|
|||||||
|
|
||||||
To correct this error, export a function from the module and refer to the function in a `useFactory` provider instead.
|
To correct this error, export a function from the module and refer to the function in a `useFactory` provider instead.
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// CORRECTED
|
// CORRECTED
|
||||||
import { calculateValue } from './utilities';
|
import { calculateValue } from './utilities';
|
||||||
|
|
||||||
@ -978,7 +978,7 @@ The compiler does not support references to variables assigned by [destructuring
|
|||||||
|
|
||||||
For example, you cannot write something like this:
|
For example, you cannot write something like this:
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// ERROR
|
// ERROR
|
||||||
import { configuration } from './configuration';
|
import { configuration } from './configuration';
|
||||||
|
|
||||||
@ -994,7 +994,7 @@ const {foo, bar} = configuration;
|
|||||||
|
|
||||||
To correct this error, refer to non-destructured values.
|
To correct this error, refer to non-destructured values.
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// CORRECTED
|
// CORRECTED
|
||||||
import { configuration } from './configuration';
|
import { configuration } from './configuration';
|
||||||
...
|
...
|
||||||
@ -1041,7 +1041,7 @@ you can finesse the problem in four steps:
|
|||||||
|
|
||||||
Here's an illustrative example.
|
Here's an illustrative example.
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// CORRECTED
|
// CORRECTED
|
||||||
import { Inject } from '@angular/core';
|
import { Inject } from '@angular/core';
|
||||||
|
|
||||||
@ -1064,7 +1064,7 @@ uses the `@Inject(WINDOW)` to generate the injection code.
|
|||||||
|
|
||||||
Angular does something similar with the `DOCUMENT` token so you can inject the browser's `document` object (or an abstraction of it, depending upon the platform in which the application runs).
|
Angular does something similar with the `DOCUMENT` token so you can inject the browser's `document` object (or an abstraction of it, depending upon the platform in which the application runs).
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
import { Inject } from '@angular/core';
|
import { Inject } from '@angular/core';
|
||||||
import { DOCUMENT } from '@angular/platform-browser';
|
import { DOCUMENT } from '@angular/platform-browser';
|
||||||
|
|
||||||
@ -1101,7 +1101,7 @@ that you referenced in metadata.
|
|||||||
|
|
||||||
The compiler can understand simple enum values but not complex values such as those derived from computed properties.
|
The compiler can understand simple enum values but not complex values such as those derived from computed properties.
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// ERROR
|
// ERROR
|
||||||
enum Colors {
|
enum Colors {
|
||||||
Red = 1,
|
Red = 1,
|
||||||
|
@ -10,7 +10,7 @@ Learn more in [The App Shell Model](https://developers.google.com/web/fundamenta
|
|||||||
## Step 1: Prepare the application
|
## Step 1: Prepare the application
|
||||||
|
|
||||||
You can do this with the following CLI command:
|
You can do this with the following CLI command:
|
||||||
<code-example format="." language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
ng new my-app --routing
|
ng new my-app --routing
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ For an existing application, you have to manually add the `RouterModule` and def
|
|||||||
|
|
||||||
Use the CLI to automatically create the app shell.
|
Use the CLI to automatically create the app shell.
|
||||||
|
|
||||||
<code-example format="." language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
ng generate app-shell --client-project my-app --universal-project server-app
|
ng generate app-shell --client-project my-app --universal-project server-app
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ ng generate app-shell --client-project my-app --universal-project server-app
|
|||||||
|
|
||||||
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
||||||
|
|
||||||
<code-example format="." language="none" linenums="false">
|
<code-example language="json">
|
||||||
"server": {
|
"server": {
|
||||||
"builder": "@angular-devkit/build-angular:server",
|
"builder": "@angular-devkit/build-angular:server",
|
||||||
"options": {
|
"options": {
|
||||||
@ -52,7 +52,7 @@ After running this command you will notice that the `angular.json` configuration
|
|||||||
|
|
||||||
Use the CLI to build the `app-shell` target.
|
Use the CLI to build the `app-shell` target.
|
||||||
|
|
||||||
<code-example format="." language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
ng run my-app:app-shell
|
ng run my-app:app-shell
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ Its `selectHero()` method sets a `selectedHero` property when the user clicks to
|
|||||||
The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor.
|
The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor.
|
||||||
The service is provided to the component through the dependency injection system.
|
The service is provided to the component through the dependency injection system.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`.
|
Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`.
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ In addition to containing or pointing to the template, the `@Component` metadata
|
|||||||
|
|
||||||
Here's an example of basic metadata for `HeroListComponent`.
|
Here's an example of basic metadata for `HeroListComponent`.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||||
|
|
||||||
This example shows some of the most useful `@Component` configuration options:
|
This example shows some of the most useful `@Component` configuration options:
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ The following diagram shows the four forms of data binding markup. Each form has
|
|||||||
|
|
||||||
This example from the `HeroListComponent` template uses three of these forms.
|
This example from the `HeroListComponent` template uses three of these forms.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
||||||
|
|
||||||
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
||||||
displays the component's `hero.name` property value within the `<li>` element.
|
displays the component's `hero.name` property value within the `<li>` element.
|
||||||
@ -101,7 +101,7 @@ Two-way data binding (used mainly in [template-driven forms](guide/forms))
|
|||||||
combines property and event binding in a single notation.
|
combines property and event binding in a single notation.
|
||||||
Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive.
|
Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
<code-example path="architecture/src/app/hero-detail.component.html" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||||
|
|
||||||
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
||||||
The user's changes also flow back to the component, resetting the property to the latest value,
|
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||||
@ -164,7 +164,7 @@ Just as for components, the metadata for a directive associates the decorated cl
|
|||||||
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
|
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
|
||||||
The example template uses two built-in structural directives to add application logic to how the view is rendered.
|
The example template uses two built-in structural directives to add application logic to how the view is rendered.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
||||||
|
|
||||||
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||||||
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
|
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
|
||||||
@ -176,7 +176,7 @@ In templates they look like regular HTML attributes, hence the name.
|
|||||||
|
|
||||||
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically `<input>`) by setting its display value property and responding to change events.
|
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically `<input>`) by setting its display value property and responding to change events.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
<code-example path="architecture/src/app/hero-detail.component.html" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||||
|
|
||||||
Angular has more pre-defined directives that either alter the layout structure
|
Angular has more pre-defined directives that either alter the layout structure
|
||||||
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
|
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
|
||||||
|
@ -23,7 +23,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
|
|||||||
|
|
||||||
Here's a simple root NgModule definition.
|
Here's a simple root NgModule definition.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts"></code-example>
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ In JavaScript each *file* is a module and all objects defined in the file belong
|
|||||||
The module declares some objects to be public by marking them with the `export` key word.
|
The module declares some objects to be public by marking them with the `export` key word.
|
||||||
Other JavaScript modules use *import statements* to access public objects from other modules.
|
Other JavaScript modules use *import statements* to access public objects from other modules.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.module.ts" region="imports"></code-example>
|
||||||
|
|
||||||
<code-example path="architecture/src/app/app.module.ts" region="export" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.module.ts" region="export"></code-example>
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
|
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
|
||||||
@ -87,17 +87,17 @@ Angular loads as a collection of JavaScript modules. You can think of them as li
|
|||||||
|
|
||||||
For example, import Angular's `Component` decorator from the `@angular/core` library like this.
|
For example, import Angular's `Component` decorator from the `@angular/core` library like this.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.component.ts" region="import"></code-example>
|
||||||
|
|
||||||
You also import NgModules from Angular *libraries* using JavaScript import statements.
|
You also import NgModules from Angular *libraries* using JavaScript import statements.
|
||||||
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library.
|
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module"></code-example>
|
||||||
|
|
||||||
In the example of the simple root module above, the application module needs material from within
|
In the example of the simple root module above, the application module needs material from within
|
||||||
`BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
`BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports"></code-example>
|
||||||
|
|
||||||
In this way you're using the Angular and JavaScript module systems *together*. Although it's easy to confuse the two systems, which share the common vocabulary of "imports" and "exports", you will become familiar with the different contexts in which they are used.
|
In this way you're using the Angular and JavaScript module systems *together*. Although it's easy to confuse the two systems, which share the common vocabulary of "imports" and "exports", you will become familiar with the different contexts in which they are used.
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ available to components through *dependency injection*.
|
|||||||
|
|
||||||
Here's an example of a service class that logs to the browser console.
|
Here's an example of a service class that logs to the browser console.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/logger.service.ts" linenums="false" header="src/app/logger.service.ts (class)" region="class"></code-example>
|
<code-example path="architecture/src/app/logger.service.ts" header="src/app/logger.service.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
|
Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero.service.ts" linenums="false" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
<code-example path="architecture/src/app/hero.service.ts" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
## Dependency injection (DI)
|
## Dependency injection (DI)
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ A dependency doesn't have to be a service—it could be a function, for exam
|
|||||||
|
|
||||||
When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the constructor parameter types. For example, the constructor of `HeroListComponent` needs `HeroService`.
|
When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the constructor parameter types. For example, the constructor of `HeroListComponent` needs `HeroService`.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
||||||
|
|
||||||
When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular.
|
When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular.
|
||||||
|
|
||||||
@ -111,6 +111,6 @@ or in the `@NgModule()` or `@Component()` metadata
|
|||||||
service with each new instance of that component.
|
service with each new instance of that component.
|
||||||
At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
|
At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
||||||
|
|
||||||
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.
|
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.
|
||||||
|
@ -37,13 +37,13 @@ This page demonstrates building a simple _appHighlight_ attribute
|
|||||||
directive to set an element's background color
|
directive to set an element's background color
|
||||||
when the user hovers over that element. You can apply it like this:
|
when the user hovers over that element. You can apply it like this:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
||||||
|
|
||||||
{@a write-directive}
|
{@a write-directive}
|
||||||
|
|
||||||
Please note that directives _do not_ support namespaces.
|
Please note that directives _do not_ support namespaces.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" linenums="false" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.avoid.html" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||||
|
|
||||||
### Write the directive code
|
### Write the directive code
|
||||||
|
|
||||||
@ -140,12 +140,12 @@ and respond by setting or clearing the highlight color.
|
|||||||
|
|
||||||
Begin by adding `HostListener` to the list of imported symbols.
|
Begin by adding `HostListener` to the list of imported symbols.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||||
|
|
||||||
Then add two eventhandlers that respond when the mouse enters or leaves,
|
Then add two eventhandlers that respond when the mouse enters or leaves,
|
||||||
each adorned by the `HostListener` decorator.
|
each adorned by the `HostListener` decorator.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
||||||
|
|
||||||
The `@HostListener` decorator lets you subscribe to events of the DOM
|
The `@HostListener` decorator lets you subscribe to events of the DOM
|
||||||
element that hosts an attribute directive, the `<p>` in this case.
|
element that hosts an attribute directive, the `<p>` in this case.
|
||||||
@ -166,7 +166,7 @@ The handlers delegate to a helper method that sets the color on the host DOM ele
|
|||||||
The helper method, `highlight`, was extracted from the constructor.
|
The helper method, `highlight`, was extracted from the constructor.
|
||||||
The revised constructor simply declares the injected `el: ElementRef`.
|
The revised constructor simply declares the injected `el: ElementRef`.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
||||||
|
|
||||||
Here's the updated directive in full:
|
Here's the updated directive in full:
|
||||||
|
|
||||||
@ -187,11 +187,11 @@ Currently the highlight color is hard-coded _within_ the directive. That's infle
|
|||||||
In this section, you give the developer the power to set the highlight color while applying the directive.
|
In this section, you give the developer the power to set the highlight color while applying the directive.
|
||||||
|
|
||||||
Begin by adding `Input` to the list of symbols imported from `@angular/core`.
|
Begin by adding `Input` to the list of symbols imported from `@angular/core`.
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||||
|
|
||||||
Add a `highlightColor` property to the directive class like this:
|
Add a `highlightColor` property to the directive class like this:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||||
|
|
||||||
{@a input}
|
{@a input}
|
||||||
|
|
||||||
@ -204,19 +204,19 @@ Without that input metadata, Angular rejects the binding; see [below](guide/attr
|
|||||||
|
|
||||||
Try it by adding the following directive binding variations to the `AppComponent` template:
|
Try it by adding the following directive binding variations to the `AppComponent` template:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
||||||
|
|
||||||
Add a `color` property to the `AppComponent`.
|
Add a `color` property to the `AppComponent`.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.1.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
Let it control the highlight color with a property binding.
|
Let it control the highlight color with a property binding.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-2"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (excerpt)" region="color-2"></code-example>
|
||||||
|
|
||||||
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
|
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||||
|
|
||||||
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
||||||
and sets the directive's highlight color with a property binding.
|
and sets the directive's highlight color with a property binding.
|
||||||
@ -225,7 +225,7 @@ That's a crisp, compact syntax.
|
|||||||
|
|
||||||
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
|
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
|
||||||
|
|
||||||
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
||||||
|
|
||||||
@ -237,23 +237,23 @@ Fortunately you can name the directive property whatever you want _and_ **_alias
|
|||||||
|
|
||||||
Restore the original property name and specify the selector as the alias in the argument to `@Input`.
|
Restore the original property name and specify the selector as the alias in the argument to `@Input`.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
||||||
|
|
||||||
_Inside_ the directive the property is known as `highlightColor`.
|
_Inside_ the directive the property is known as `highlightColor`.
|
||||||
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
|
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
|
||||||
|
|
||||||
You get the best of both worlds: the property name you want and the binding syntax you want:
|
You get the best of both worlds: the property name you want and the binding syntax you want:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||||
|
|
||||||
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
|
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
|
||||||
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
|
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||||
|
|
||||||
Here's the latest version of the directive class.
|
Here's the latest version of the directive class.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
## Write a harness to try it
|
## Write a harness to try it
|
||||||
|
|
||||||
@ -263,11 +263,11 @@ lets you pick the highlight color with a radio button and bind your color choice
|
|||||||
|
|
||||||
Update <code>app.component.html</code> as follows:
|
Update <code>app.component.html</code> as follows:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||||
|
|
||||||
Revise the `AppComponent.color` so that it has no initial value.
|
Revise the `AppComponent.color` so that it has no initial value.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
Here are the harness and directive in action.
|
Here are the harness and directive in action.
|
||||||
|
|
||||||
@ -287,12 +287,12 @@ Let the template developer set the default color.
|
|||||||
|
|
||||||
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
||||||
|
|
||||||
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
||||||
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
||||||
|
|
||||||
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
|
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ As with components, you can add as many directive property bindings as you need
|
|||||||
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
||||||
and fall back to "violet" as the default color.
|
and fall back to "violet" as the default color.
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||||
|
|
||||||
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
||||||
because you made it _public_ with the `@Input` decorator.
|
because you made it _public_ with the `@Input` decorator.
|
||||||
@ -342,11 +342,11 @@ You can also experience and download the <live-example title="Attribute Directiv
|
|||||||
In this demo, the `highlightColor` property is an ***input*** property of
|
In this demo, the `highlightColor` property is an ***input*** property of
|
||||||
the `HighlightDirective`. You've seen it applied without an alias:
|
the `HighlightDirective`. You've seen it applied without an alias:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||||
|
|
||||||
You've seen it with an alias:
|
You've seen it with an alias:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||||
|
|
||||||
Either way, the `@Input` decorator tells Angular that this property is
|
Either way, the `@Input` decorator tells Angular that this property is
|
||||||
_public_ and available for binding by a parent component.
|
_public_ and available for binding by a parent component.
|
||||||
@ -378,7 +378,7 @@ You can tell if `@Input` is needed by the position of the property name in a bin
|
|||||||
|
|
||||||
Now apply that reasoning to the following example:
|
Now apply that reasoning to the following example:
|
||||||
|
|
||||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||||
|
|
||||||
* The `color` property in the expression on the right belongs to the template's component.
|
* The `color` property in the expression on the right belongs to the template's component.
|
||||||
The template and its component trust each other.
|
The template and its component trust each other.
|
||||||
|
@ -106,19 +106,16 @@ To use a directive, component, or pipe in a module, you must do a few things:
|
|||||||
Those three steps look like the following. In the file where you create your directive, export it.
|
Those three steps look like the following. In the file where you create your directive, export it.
|
||||||
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
|
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
|
||||||
|
|
||||||
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts" linenums="false">
|
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The key point here is that you have to export it so you can import it elsewhere. Next, import it
|
The key point here is that you have to export it so you can import it elsewhere. Next, import it
|
||||||
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
|
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
|
||||||
|
|
||||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts" linenums="false">
|
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
And in the same file, add it to the `@NgModule` `declarations` array:
|
And in the same file, add it to the `@NgModule` `declarations` array:
|
||||||
|
|
||||||
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts" linenums="false">
|
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components.
|
Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components.
|
||||||
|
@ -53,7 +53,7 @@ Angular supports most recent browsers. This includes the following specific vers
|
|||||||
IE
|
IE
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
11<br>10<br>9
|
11, 10, 9
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -89,7 +89,7 @@ Angular supports most recent browsers. This includes the following specific vers
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
Nougat (7.0)<br>Marshmallow (6.0)<br>Lollipop (5.0, 5.1)<br>KitKat (4.4)
|
Nougat (7.0), Marshmallow (6.0), Lollipop (5.0, 5.1), KitKat (4.4)
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -103,12 +103,10 @@ using <a href="https://saucelabs.com/">SauceLabs</a> and
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Polyfills
|
## Polyfills
|
||||||
|
|
||||||
Angular is built on the latest standards of the web platform.
|
Angular is built on the latest standards of the web platform.
|
||||||
Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers.
|
Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers.
|
||||||
|
|
||||||
You compensate by loading polyfill scripts ("polyfills") for the browsers that you must support.
|
You compensate by loading polyfill scripts ("polyfills") for the browsers that you must support.
|
||||||
The [table below](#polyfill-libs) identifies most of the polyfills you might need.
|
The [table below](#polyfill-libs) identifies most of the polyfills you might need.
|
||||||
|
|
||||||
@ -120,25 +118,36 @@ Note that polyfills cannot magically transform an old, slow browser into a moder
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Enabling polyfills
|
In Angular CLI version 8 and higher, applications are built using *differential loading*, a strategy where the CLI builds two separate bundles as part of your deployed application.
|
||||||
|
|
||||||
[Angular CLI](cli) users enable polyfills through the `src/polyfills.ts` file that
|
* The first bundle contains modern ES2015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size.
|
||||||
the CLI created with your project.
|
|
||||||
|
|
||||||
|
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers.
|
||||||
|
|
||||||
|
This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs.
|
||||||
|
For more information about how this works, see [Differential Loading](guide/deployment#differential-loading) in the [Deployment guide](guide/deployment).
|
||||||
|
|
||||||
|
## Enabling polyfills with CLI projects
|
||||||
|
|
||||||
|
The [Angular CLI](cli) provides support for polyfills.
|
||||||
|
If you are not using the CLI to create your projects, see [Polyfill instructions for non-CLI users](#non-cli).
|
||||||
|
|
||||||
|
When you create a project with the `ng new` command, a `src/polyfills.ts` configuration file is created as part of your project folder.
|
||||||
This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements.
|
This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements.
|
||||||
|
|
||||||
The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and their corresponding `import` statements are ready to go. You probably won't touch these.
|
* The npm packages for the [_mandatory_ polyfills](#polyfill-libs) (such as `zone.js`) are installed automatically for you when you create your project with `ng new`, and their corresponding `import` statements are already enabled in the `src/polyfills.ts` configuration file.
|
||||||
|
|
||||||
But if you need an optional polyfill, you'll have to install its npm package.
|
* If you need an _optional_ polyfill, you must install its npm package, then uncomment or create the corresponding import statement in the `src/polyfills.ts` configuration file.
|
||||||
For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
|
|
||||||
|
For example, if you need the optional [web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
|
||||||
|
|
||||||
<code-example language="sh" class="code-shell">
|
<code-example language="sh" class="code-shell">
|
||||||
# note that the web-animations-js polyfill is only here as an example
|
# install the optional web animations polyfill
|
||||||
# it isn't a strict requirement of Angular anymore (more below)
|
|
||||||
npm install --save web-animations-js
|
npm install --save web-animations-js
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
|
You can then add the import statement in the `src/polyfills.ts` file.
|
||||||
|
For many polyfills, you can simply un-comment the corresponding `import` statement in the file, as in the following example.
|
||||||
|
|
||||||
<code-example header="src/polyfills.ts">
|
<code-example header="src/polyfills.ts">
|
||||||
/**
|
/**
|
||||||
@ -148,23 +157,14 @@ Then open the `polyfills.ts` file and un-comment the corresponding `import` stat
|
|||||||
import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
If you can't find the polyfill you want in `polyfills.ts`,
|
If the polyfill you want is not already in `polyfills.ts` file, add the `import` statement by hand.
|
||||||
add it yourself, following the same pattern:
|
|
||||||
|
|
||||||
1. install the npm package
|
|
||||||
1. `import` the file in `polyfills.ts`
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
|
||||||
|
|
||||||
Non-CLI users should follow the instructions [below](#non-cli).
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{@a polyfill-libs}
|
{@a polyfill-libs}
|
||||||
|
|
||||||
### Mandatory polyfills
|
### Mandatory polyfills
|
||||||
These are the polyfills required to run an Angular application on each supported browser:
|
These are the polyfills required to run an Angular application on each supported browser:
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
@ -182,26 +182,13 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
Chrome, Firefox, Edge, Safari 9+
|
Chrome, Firefox, Edge, <br>
|
||||||
|
Safari, Android, IE10+
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[ES7/reflect](guide/browser-support#core-es7-reflect) (JIT only)
|
[ES2015](guide/browser-support#core-es6)
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
|
||||||
|
|
||||||
<td>
|
|
||||||
Safari 7 & 8, IE10 & 11, Android 4.1+
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[ES6](guide/browser-support#core-es6)
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -215,7 +202,7 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[ES6<br>classList](guide/browser-support#classlist)
|
ES2015<br>[classList](guide/browser-support#classlist)
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -228,12 +215,6 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
|
|
||||||
Some features of Angular may require additional polyfills.
|
Some features of Angular may require additional polyfills.
|
||||||
|
|
||||||
For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today.
|
|
||||||
(note that the dependency of web-animations-js in Angular is only necessary if `AnimationBuilder` is used.)
|
|
||||||
|
|
||||||
Here are the features which may require additional polyfills:
|
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
@ -256,31 +237,8 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[JIT compilation](guide/aot-compiler).
|
[AnimationBuilder](api/animations/AnimationBuilder).
|
||||||
|
(Standard animation support does not require polyfills.)
|
||||||
Required to reflect for metadata.
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[ES7/reflect](guide/browser-support#core-es7-reflect)
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
All current browsers. Enabled by default.
|
|
||||||
Can remove if you always use AOT and only use Angular decorators.
|
|
||||||
</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Animations](guide/animations)
|
|
||||||
<br>Only if `Animation Builder` is used within the application--standard
|
|
||||||
animation support in Angular doesn't require any polyfills (as of NG6).
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -291,8 +249,9 @@ Here are the features which may require additional polyfills:
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<p>If AnimationBuilder is used then the polyfill will enable scrubbing
|
<p>If AnimationBuilder is used, enables scrubbing
|
||||||
support for IE/Edge and Safari (Chrome and Firefox support this natively).</p>
|
support for IE/Edge and Safari.
|
||||||
|
(Chrome and Firefox support this natively).</p>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@ -302,14 +261,9 @@ Here are the features which may require additional polyfills:
|
|||||||
<td>
|
<td>
|
||||||
|
|
||||||
If you use the following deprecated i18n pipes:
|
If you use the following deprecated i18n pipes:
|
||||||
|
|
||||||
|
|
||||||
[date](api/common/DeprecatedDatePipe),
|
[date](api/common/DeprecatedDatePipe),
|
||||||
|
|
||||||
[currency](api/common/DeprecatedCurrencyPipe),
|
[currency](api/common/DeprecatedCurrencyPipe),
|
||||||
|
|
||||||
[decimal](api/common/DeprecatedDecimalPipe),
|
[decimal](api/common/DeprecatedDecimalPipe),
|
||||||
|
|
||||||
[percent](api/common/DeprecatedPercentPipe)
|
[percent](api/common/DeprecatedPercentPipe)
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
@ -330,9 +284,7 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[NgClass](api/common/NgClass)
|
[NgClass](api/common/NgClass) on SVG elements
|
||||||
|
|
||||||
on SVG elements
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -351,9 +303,7 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[Http](guide/http)
|
[Http](guide/http) when sending and receiving binary data
|
||||||
|
|
||||||
when sending and receiving binary data
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -376,9 +326,8 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[Router](guide/router)
|
[Router](guide/router) when using
|
||||||
|
[hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
|
||||||
when using [hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -397,8 +346,9 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Suggested polyfills ##
|
### Suggested polyfills
|
||||||
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
|
|
||||||
|
The following polyfills are used to test the framework itself. They are a good starting point for an application.
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -419,24 +369,6 @@ Below are the polyfills which are used to test the framework itself. They are a
|
|||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<a id='core-es7-reflect' href="https://github.com/zloirock/core-js/tree/v2/fn/reflect">ES7/reflect</a>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
MIT
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
0.5KB
|
|
||||||
</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -459,7 +391,7 @@ Below are the polyfills which are used to test the framework itself. They are a
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<a id='core-es6' href="https://github.com/zloirock/core-js">ES6</a>
|
<a id='core-es6' href="https://github.com/zloirock/core-js">ES2015</a>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -588,11 +520,14 @@ Below are the polyfills which are used to test the framework itself. They are a
|
|||||||
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
|
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
|
||||||
|
|
||||||
{@a non-cli}
|
{@a non-cli}
|
||||||
|
|
||||||
## Polyfills for non-CLI users
|
## Polyfills for non-CLI users
|
||||||
|
|
||||||
If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
|
If you are not using the CLI, add your polyfill scripts directly to the host web page (`index.html`).
|
||||||
|
|
||||||
<code-example header="src/index.html">
|
For example:
|
||||||
|
|
||||||
|
<code-example header="src/index.html" language="html">
|
||||||
<!-- pre-zone polyfills -->
|
<!-- pre-zone polyfills -->
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||||
<script src="node_modules/web-animations-js/web-animations.min.js"></script>
|
<script src="node_modules/web-animations-js/web-animations.min.js"></script>
|
||||||
|
@ -185,8 +185,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
|
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
|
||||||
<td><p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
|
<td><p>Declares that a class can be provided and injected by other classes. Without this decorator, the compiler won't generate enough metadata to allow the class to be created properly when it's injected somewhere.</p>
|
||||||
</p>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
|
@ -191,7 +191,7 @@ For our example builder, we expect the `options` value to be a `JsonObject` with
|
|||||||
|
|
||||||
We can provide the following schema for type validation of these values.
|
We can provide the following schema for type validation of these values.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
|
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
@ -222,7 +222,7 @@ To link our builder implementation with its schema and name, we need to create a
|
|||||||
|
|
||||||
Create a file named `builders.json` file that looks like this.
|
Create a file named `builders.json` file that looks like this.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
|
|
||||||
{
|
{
|
||||||
"builders": {
|
"builders": {
|
||||||
@ -238,7 +238,7 @@ Create a file named `builders.json` file that looks like this.
|
|||||||
|
|
||||||
In the `package.json` file, add a `builders` key that tells the Architect tool where to find our builder definition file.
|
In the `package.json` file, add a `builders` key that tells the Architect tool where to find our builder definition file.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "@example/command-runner",
|
"name": "@example/command-runner",
|
||||||
@ -257,7 +257,7 @@ The first part of this is the package name (resolved using node resolution), an
|
|||||||
|
|
||||||
Using one of our `options` is very straightforward, we did this in the previous section when we accessed `options.command`.
|
Using one of our `options` is very straightforward, we did this in the previous section when we accessed `options.command`.
|
||||||
|
|
||||||
<code-example format="." language="typescript" linenums="false">
|
<code-example language="typescript">
|
||||||
context.reportStatus(`Executing "${options.command}"...`);
|
context.reportStatus(`Executing "${options.command}"...`);
|
||||||
const child = childProcess.spawn(options.command, options.args, { stdio: 'pipe' });
|
const child = childProcess.spawn(options.command, options.args, { stdio: 'pipe' });
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ The Architect tool uses the target definition to resolve input options for a giv
|
|||||||
The `angular.json` file has a section for each project, and the "architect" section of each project configures targets for builders used by CLI commands such as 'build', 'test', and 'lint'.
|
The `angular.json` file has a section for each project, and the "architect" section of each project configures targets for builders used by CLI commands such as 'build', 'test', and 'lint'.
|
||||||
By default, for example, the `build` command runs the builder `@angular-devkit/build-angular:browser` to perform the build task, and passes in default option values as specified for the `build` target in `angular.json`.
|
By default, for example, the `build` command runs the builder `@angular-devkit/build-angular:browser` to perform the build task, and passes in default option values as specified for the `build` target in `angular.json`.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
{
|
{
|
||||||
"myApp": {
|
"myApp": {
|
||||||
...
|
...
|
||||||
@ -361,7 +361,7 @@ npm install @example/command-runner
|
|||||||
|
|
||||||
If we create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations.
|
If we create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
|
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
@ -413,7 +413,7 @@ We need to update the `angular.json` file to add a target for this builder to th
|
|||||||
|
|
||||||
* The configurations key is optional, we'll leave it out for now.
|
* The configurations key is optional, we'll leave it out for now.
|
||||||
|
|
||||||
<code-example format="." language="json" linenums="false">
|
<code-example language="json">
|
||||||
|
|
||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
@ -495,7 +495,7 @@ Use integration testing for your builder, so that you can use the Architect sche
|
|||||||
Here’s an example of a test that runs the command builder.
|
Here’s an example of a test that runs the command builder.
|
||||||
The test uses the builder to run the `ls` command, then validates that it ran successfully and listed the proper files.
|
The test uses the builder to run the `ls` command, then validates that it ran successfully and listed the proper files.
|
||||||
|
|
||||||
<code-example format="." language="typescript" linenums="false">
|
<code-example language="typescript">
|
||||||
|
|
||||||
import { Architect, ArchitectHost } from '@angular-devkit/architect';
|
import { Architect, ArchitectHost } from '@angular-devkit/architect';
|
||||||
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
||||||
|
@ -38,7 +38,7 @@ The following example demonstrates how to use `query()` and `stagger()` function
|
|||||||
|
|
||||||
* Animate each element on screen for 0.5 seconds using a custom-defined easing curve, simultaneously fading it in and un-transforming it.
|
* Animate each element on screen for 0.5 seconds using a custom-defined easing curve, simultaneously fading it in and un-transforming it.
|
||||||
|
|
||||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript" linenums="false"></code-example>
|
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript"></code-example>
|
||||||
|
|
||||||
## Parallel animation using group() function
|
## Parallel animation using group() function
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ You've seen how to add a delay between each successive animation. But you may al
|
|||||||
|
|
||||||
In the following example, using groups on both `:enter` and `:leave` allow for two different timing configurations. They're applied to the same element in parallel, but run independently.
|
In the following example, using groups on both `:enter` and `:leave` allow for two different timing configurations. They're applied to the same element in parallel, but run independently.
|
||||||
|
|
||||||
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript" linenums="false"></code-example>
|
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript"></code-example>
|
||||||
|
|
||||||
## Sequential vs. parallel animations
|
## Sequential vs. parallel animations
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ The HTML template contains a trigger called `filterAnimation`.
|
|||||||
|
|
||||||
The component file contains three transitions.
|
The component file contains three transitions.
|
||||||
|
|
||||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript" linenums="false"></code-example>
|
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript"></code-example>
|
||||||
|
|
||||||
The animation does the following:
|
The animation does the following:
|
||||||
|
|
||||||
|
@ -21,8 +21,7 @@ One way to do this is to set the `styles` property in the component metadata.
|
|||||||
The `styles` property takes an array of strings that contain CSS code.
|
The `styles` property takes an array of strings that contain CSS code.
|
||||||
Usually you give it one string, as in the following example:
|
Usually you give it one string, as in the following example:
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts" linenums="false">
|
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
## Style scope
|
## Style scope
|
||||||
|
|
||||||
@ -71,8 +70,7 @@ Use the `:host` pseudo-class selector to target styles in the element that *host
|
|||||||
targeting elements *inside* the component's template).
|
targeting elements *inside* the component's template).
|
||||||
|
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css" linenums="false">
|
<code-example path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The `:host` selector is the only way to target the host element. You can't reach
|
The `:host` selector is the only way to target the host element. You can't reach
|
||||||
the host element from inside the component with other selectors because it's not part of the
|
the host element from inside the component with other selectors because it's not part of the
|
||||||
@ -83,8 +81,7 @@ including another selector inside parentheses after `:host`.
|
|||||||
|
|
||||||
The next example targets the host element again, but only when it also has the `active` CSS class.
|
The next example targets the host element again, but only when it also has the `active` CSS class.
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css" linenums="false">
|
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
### :host-context
|
### :host-context
|
||||||
|
|
||||||
@ -99,8 +96,7 @@ up to the document root. The `:host-context()` selector is useful when combined
|
|||||||
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
|
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
|
||||||
if some ancestor element has the CSS class `theme-light`.
|
if some ancestor element has the CSS class `theme-light`.
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css" linenums="false">
|
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
|
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
|
||||||
|
|
||||||
@ -115,9 +111,7 @@ can bleed into other components.
|
|||||||
The following example targets all `<h3>` elements, from the host element down
|
The following example targets all `<h3>` elements, from the host element down
|
||||||
through this component to all of its child elements in the DOM.
|
through this component to all of its child elements in the DOM.
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css" linenums="false">
|
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
||||||
|
|
||||||
@ -304,8 +298,7 @@ Choose from the following modes:
|
|||||||
|
|
||||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||||
|
|
||||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts" linenums="false">
|
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||||
|
@ -12,7 +12,7 @@ A simple example might be a button that sends users to your company website, tha
|
|||||||
|
|
||||||
Use the Angular CLI to generate a new library skeleton with the following command:
|
Use the Angular CLI to generate a new library skeleton with the following command:
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng generate library my-lib
|
ng generate library my-lib
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ The workspace configuration file, `angular.json`, is updated with a project of t
|
|||||||
|
|
||||||
You can build, test, and lint the project with CLI commands:
|
You can build, test, and lint the project with CLI commands:
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng build my-lib
|
ng build my-lib
|
||||||
ng test my-lib
|
ng test my-lib
|
||||||
ng lint my-lib
|
ng lint my-lib
|
||||||
@ -106,7 +106,7 @@ To learn more, see [Schematics Overview](guide/schematics) and [Schematics for
|
|||||||
Use the Angular CLI and the npm package manager to build and publish your library as an npm package.
|
Use the Angular CLI and the npm package manager to build and publish your library as an npm package.
|
||||||
Libraries are built in [AoT mode](guide/aot-compiler) by default, so you do not need to specify the `-prod` flag when building for publication.
|
Libraries are built in [AoT mode](guide/aot-compiler) by default, so you do not need to specify the `-prod` flag when building for publication.
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng build my-lib
|
ng build my-lib
|
||||||
cd dist/my-lib
|
cd dist/my-lib
|
||||||
npm publish
|
npm publish
|
||||||
@ -158,7 +158,7 @@ You don't have to publish your library to the npm package manager in order to us
|
|||||||
To use your own library in an app:
|
To use your own library in an app:
|
||||||
|
|
||||||
* Build the library. You cannot use a library before it is built.
|
* Build the library. You cannot use a library before it is built.
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng build my-lib
|
ng build my-lib
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -190,6 +190,6 @@ Every time a file is changed a partial build is performed that emits the amended
|
|||||||
|
|
||||||
Incremental builds can be run as a backround process in your dev environment. To take advantage of this feature add the `--watch` flag to the build command:
|
Incremental builds can be run as a backround process in your dev environment. To take advantage of this feature add the `--watch` flag to the build command:
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
ng build my-lib --watch
|
ng build my-lib --watch
|
||||||
</code-example>
|
</code-example>
|
||||||
|
@ -21,18 +21,14 @@ constructor, and lets the framework provide them.
|
|||||||
|
|
||||||
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`.
|
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
`UserContext` in turn depends on both `LoggerService` and
|
`UserContext` in turn depends on both `LoggerService` and
|
||||||
`UserService`, another service that gathers information about a particular user.
|
`UserService`, another service that gathers information about a particular user.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
When Angular creates `AppComponent`, the DI framework creates an instance of `LoggerService` and starts to create `UserContextService`.
|
When Angular creates `AppComponent`, the DI framework creates an instance of `LoggerService` and starts to create `UserContextService`.
|
||||||
@ -185,17 +181,13 @@ This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which y
|
|||||||
|
|
||||||
Focus on the template:
|
Focus on the template:
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
|
Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
|
||||||
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
|
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
|
||||||
placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
|
placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
||||||
|
|
||||||
@ -212,9 +204,7 @@ Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
|
|||||||
|
|
||||||
Focus on the constructor parameters.
|
Focus on the constructor parameters.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The `@Host()` function decorating the `heroCache` constructor property ensures that
|
The `@Host()` function decorating the `heroCache` constructor property ensures that
|
||||||
you get a reference to the cache service from the parent `HeroBioComponent`.
|
you get a reference to the cache service from the parent `HeroBioComponent`.
|
||||||
@ -299,9 +289,7 @@ whose `nativeElement` property exposes the DOM element for the directive to mani
|
|||||||
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
|
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
|
||||||
first without a value (yielding the default color) and then with an assigned color value.
|
first without a value (yielding the default color) and then with an assigned color value.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
|
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
|
||||||
@ -325,9 +313,7 @@ Angular passes this token to the injector and assigns the result to the paramete
|
|||||||
The following is a typical example.
|
The following is a typical example.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Angular asks the injector for the service associated with `LoggerService`
|
Angular asks the injector for the service associated with `LoggerService`
|
||||||
@ -386,9 +372,7 @@ You can also use a value provider in a unit test to provide mock data in place o
|
|||||||
|
|
||||||
The `HeroOfTheMonthComponent` example has two value providers.
|
The `HeroOfTheMonthComponent` example has two value providers.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
* The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than
|
* The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than
|
||||||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||||
@ -427,9 +411,7 @@ extend the default class, or emulate the behavior of the real class in a test ca
|
|||||||
|
|
||||||
The following code shows two examples in `HeroOfTheMonthComponent`.
|
The following code shows two examples in `HeroOfTheMonthComponent`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The first provider is the *de-sugared*, expanded form of the most typical case in which the
|
The first provider is the *de-sugared*, expanded form of the most typical case in which the
|
||||||
class to be created (`HeroService`) is also the provider's dependency injection token.
|
class to be created (`HeroService`) is also the provider's dependency injection token.
|
||||||
@ -448,9 +430,7 @@ Components outside the tree continue to receive the original `LoggerService` ins
|
|||||||
|
|
||||||
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
|
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a useexisting}
|
{@a useexisting}
|
||||||
|
|
||||||
@ -472,15 +452,11 @@ You might want to shrink that API surface to just the members you actually need.
|
|||||||
In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members:
|
In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`.
|
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger`, so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor.
|
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger`, so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor.
|
||||||
|
|
||||||
@ -532,9 +508,7 @@ The `runnersUpFactory()` returns the *provider factory function*, which can use
|
|||||||
the passed-in state value and the injected services `Hero` and `HeroService`.
|
the passed-in state value and the injected services `Hero` and `HeroService`.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
||||||
the string of names.
|
the string of names.
|
||||||
@ -578,9 +552,7 @@ as the token for a provider of `LoggerService`.
|
|||||||
|
|
||||||
`MinimalLogger` is an abstract class.
|
`MinimalLogger` is an abstract class.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
An abstract class is usually a base class that you can extend.
|
An abstract class is usually a base class that you can extend.
|
||||||
In this app, however there is no class that inherits from `MinimalLogger`.
|
In this app, however there is no class that inherits from `MinimalLogger`.
|
||||||
@ -606,9 +578,7 @@ Using a class as an interface gives you the characteristics of an interface in a
|
|||||||
To minimize memory cost, however, the class should have *no implementation*.
|
To minimize memory cost, however, the class should have *no implementation*.
|
||||||
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function.
|
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
||||||
as long as those members are typed but not implemented.
|
as long as those members are typed but not implemented.
|
||||||
@ -635,15 +605,11 @@ another token that happens to have the same name.
|
|||||||
You encountered them twice in the *Hero of the Month* example,
|
You encountered them twice in the *Hero of the Month* example,
|
||||||
in the *title* value provider and in the *runnersUp* factory provider.
|
in the *title* value provider and in the *runnersUp* factory provider.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You created the `TITLE` token like this:
|
You created the `TITLE` token like this:
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||||
The token description is another developer aid.
|
The token description is another developer aid.
|
||||||
@ -733,9 +699,7 @@ appear *above* the class definition.
|
|||||||
|
|
||||||
Break the circularity with `forwardRef`.
|
Break the circularity with `forwardRef`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
<!--- Waiting for good examples
|
<!--- Waiting for good examples
|
||||||
|
@ -40,18 +40,14 @@ In the following example, the parent `AlexComponent` has several children includ
|
|||||||
{@a alex}
|
{@a alex}
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Cathy* reports whether or not she has access to *Alex*
|
*Cathy* reports whether or not she has access to *Alex*
|
||||||
after injecting an `AlexComponent` into her constructor:
|
after injecting an `AlexComponent` into her constructor:
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -98,17 +94,13 @@ inject its parent via the parent's base class*.
|
|||||||
The sample's `CraigComponent` explores this question. [Looking back](#alex),
|
The sample's `CraigComponent` explores this question. [Looking back](#alex),
|
||||||
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`.
|
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (Alex class signature)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (Alex class signature)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded.
|
The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -138,9 +130,7 @@ and add that provider to the `providers` array of the `@Component()` metadata fo
|
|||||||
{@a alex-providers}
|
{@a alex-providers}
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
[Parent](#parent-token) is the provider's class interface token.
|
[Parent](#parent-token) is the provider's class interface token.
|
||||||
@ -149,9 +139,7 @@ The [*forwardRef*](guide/dependency-injection-in-action#forwardref) breaks the c
|
|||||||
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
|
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
|
||||||
the same way you've done it before.
|
the same way you've done it before.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" header="parent-finder.component.ts (CarolComponent class)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" header="parent-finder.component.ts (CarolComponent class)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -177,9 +165,7 @@ That means he must both *inject* the `Parent` class interface to get *Alice* and
|
|||||||
|
|
||||||
Here's *Barry*.
|
Here's *Barry*.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -229,9 +215,7 @@ You [learned earlier](guide/dependency-injection-in-action#class-interface) that
|
|||||||
|
|
||||||
The example defines a `Parent` class interface.
|
The example defines a `Parent` class interface.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -241,9 +225,7 @@ Such a narrow interface helps decouple the child component class from its parent
|
|||||||
|
|
||||||
A component that could serve as a parent *should* implement the class interface as the `AliceComponent` does.
|
A component that could serve as a parent *should* implement the class interface as the `AliceComponent` does.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -251,9 +233,7 @@ Doing so adds clarity to the code. But it's not technically necessary.
|
|||||||
Although `AlexComponent` has a `name` property, as required by its `Base` class,
|
Although `AlexComponent` has a `name` property, as required by its `Base` class,
|
||||||
its class signature doesn't mention `Parent`.
|
its class signature doesn't mention `Parent`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -277,21 +257,15 @@ It doesn't in this example *only* to demonstrate that the code will compile and
|
|||||||
Writing variations of the same parent *alias provider* gets old quickly,
|
Writing variations of the same parent *alias provider* gets old quickly,
|
||||||
especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref).
|
especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref).
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You can extract that logic into a helper function like the following.
|
You can extract that logic into a helper function like the following.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now you can add a simpler, more meaningful parent provider to your components.
|
Now you can add a simpler, more meaningful parent provider to your components.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
You can do better. The current version of the helper function can only alias the `Parent` class interface.
|
You can do better. The current version of the helper function can only alias the `Parent` class interface.
|
||||||
@ -299,14 +273,10 @@ The application might have a variety of parent types, each with its own class in
|
|||||||
|
|
||||||
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
|
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
And here's how you could use it with a different parent type.
|
And here's how you could use it with a different parent type.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
@ -68,13 +68,11 @@ using the `Logger` token.
|
|||||||
Another class, `EvenBetterLogger`, might display the user name in the log message.
|
Another class, `EvenBetterLogger`, might display the user name in the log message.
|
||||||
This logger gets the user from an injected `UserService` instance.
|
This logger gets the user from an injected `UserService` instance.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The injector needs providers for both this new logging service and its dependent `UserService`. Configure this alternative logger with the `useClass` provider-definition key, like `BetterLogger`. The following array specifies both providers in the `providers` metadata option of the parent module or component.
|
The injector needs providers for both this new logging service and its dependent `UserService`. Configure this alternative logger with the `useClass` provider-definition key, like `BetterLogger`. The following array specifies both providers in the `providers` metadata option of the parent module or component.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a aliased-class-providers}
|
{@a aliased-class-providers}
|
||||||
|
|
||||||
@ -92,13 +90,11 @@ when a component asks for either the new or the old logger.
|
|||||||
|
|
||||||
If you try to alias `OldLogger` to `NewLogger` with `useClass`, you end up with two different `NewLogger` instances in your app.
|
If you try to alias `OldLogger` to `NewLogger` with `useClass`, you end up with two different `NewLogger` instances in your app.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
To make sure there is only one instance of `NewLogger`, alias `OldLogger` with the `useExisting` option.
|
To make sure there is only one instance of `NewLogger`, alias `OldLogger` with the `useExisting` option.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a value-provider}
|
{@a value-provider}
|
||||||
|
|
||||||
@ -110,13 +106,11 @@ configure the injector with the `useValue` option
|
|||||||
|
|
||||||
The following code defines a variable that creates such an object to play the logger role.
|
The following code defines a variable that creates such an object to play the logger role.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The following provider object uses the `useValue` key to associate the variable with the `Logger` token.
|
The following provider object uses the `useValue` key to associate the variable with the `Logger` token.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a non-class-dependencies}
|
{@a non-class-dependencies}
|
||||||
|
|
||||||
@ -130,8 +124,7 @@ like the title of the application or the address of a web API endpoint.
|
|||||||
These configuration objects aren't always instances of a class.
|
These configuration objects aren't always instances of a class.
|
||||||
They can be object literals, as shown in the following example.
|
They can be object literals, as shown in the following example.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)" linenums="false">
|
<code-example path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a interface-not-valid-token}
|
{@a interface-not-valid-token}
|
||||||
|
|
||||||
@ -141,11 +134,9 @@ The `HERO_DI_CONFIG` constant conforms to the `AppConfig` interface.
|
|||||||
Unfortunately, you cannot use a TypeScript interface as a token.
|
Unfortunately, you cannot use a TypeScript interface as a token.
|
||||||
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation (token) that the DI framework can use.
|
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation (token) that the DI framework can use.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -163,22 +154,19 @@ Another solution to choosing a provider token for non-class dependencies is
|
|||||||
to define and use an `InjectionToken` object.
|
to define and use an `InjectionToken` object.
|
||||||
The following example shows how to define such a token.
|
The following example shows how to define such a token.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts" linenums="false">
|
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||||
The token description is another developer aid.
|
The token description is another developer aid.
|
||||||
|
|
||||||
Register the dependency provider using the `InjectionToken` object:
|
Register the dependency provider using the `InjectionToken` object:
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now you can inject the configuration object into any constructor that needs it, with
|
Now you can inject the configuration object into any constructor that needs it, with
|
||||||
the help of an `@Inject()` parameter decorator.
|
the help of an `@Inject()` parameter decorator.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
|
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -215,22 +203,19 @@ who is authorized and who isn't.
|
|||||||
|
|
||||||
To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes.
|
To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
|
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You can inject `Logger`, but you can't inject the `isAuthorized` flag. Instead, you can use a factory provider to create a new logger instance for `HeroService`.
|
You can inject `Logger`, but you can't inject the `isAuthorized` flag. Instead, you can use a factory provider to create a new logger instance for `HeroService`.
|
||||||
|
|
||||||
A factory provider needs a factory function.
|
A factory provider needs a factory function.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Although `HeroService` has no access to `UserService`, the factory function does.
|
Although `HeroService` has no access to `UserService`, the factory function does.
|
||||||
You inject both `Logger` and `UserService` into the factory provider
|
You inject both `Logger` and `UserService` into the factory provider
|
||||||
and let the injector pass them along to the factory function.
|
and let the injector pass them along to the factory function.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
|
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
|
||||||
|
|
||||||
@ -322,13 +307,13 @@ Thus, services in the NgModule `providers` array or at component level are not t
|
|||||||
|
|
||||||
The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule.
|
The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" header="src/app/tree-shaking/service-and-modules.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" header="src/app/tree-shaking/service-and-modules.ts"></code-example>
|
||||||
|
|
||||||
You can then import this module into your application module
|
You can then import this module into your application module
|
||||||
to make the service available for injection in your app,
|
to make the service available for injection in your app,
|
||||||
as in the following example.
|
as in the following example.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts"></code-example>
|
||||||
|
|
||||||
When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services.
|
When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services.
|
||||||
|
|
||||||
@ -340,11 +325,11 @@ You can make a provider tree-shakable by specifying it in the `@Injectable()` de
|
|||||||
|
|
||||||
The following example shows the tree-shakable equivalent to the `ServiceModule` example above.
|
The following example shows the tree-shakable equivalent to the `ServiceModule` example above.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts"></code-example>
|
||||||
|
|
||||||
The service can be instantiated by configuring a factory function, as in the following example.
|
The service can be instantiated by configuring a factory function, as in the following example.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" header="src/app/tree-shaking/service.0.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" header="src/app/tree-shaking/service.0.ts"></code-example>
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
|
@ -196,8 +196,7 @@ Listing dependencies as constructor parameters may be all you need to test appli
|
|||||||
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
|
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
|
||||||
under test.
|
under test.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
|
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -259,8 +258,7 @@ In simple examples, the dependency value is an *instance*, and
|
|||||||
the class *type* serves as its own lookup key.
|
the class *type* serves as its own lookup key.
|
||||||
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
|
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts" linenums="false">
|
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The behavior is similar when you write a constructor that requires an injected class-based dependency.
|
The behavior is similar when you write a constructor that requires an injected class-based dependency.
|
||||||
When you define a constructor parameter with the `HeroService` class type,
|
When you define a constructor parameter with the `HeroService` class type,
|
||||||
@ -287,8 +285,7 @@ constructor parameter with `@Optional()`.
|
|||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
|
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
When using `@Optional()`, your code must be prepared for a null value. If you
|
When using `@Optional()`, your code must be prepared for a null value. If you
|
||||||
don't register a logger provider anywhere, the injector sets the
|
don't register a logger provider anywhere, the injector sets the
|
||||||
|
@ -30,7 +30,9 @@ You will need two terminals to get the live-reload experience.
|
|||||||
* On the first terminal, run the [`ng build` command](cli/build) in *watch* mode to compile the application to the `dist` folder.
|
* On the first terminal, run the [`ng build` command](cli/build) in *watch* mode to compile the application to the `dist` folder.
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
ng build --watch
|
ng build --watch
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Like the `ng serve` command, this regenerates output files when source files change.
|
Like the `ng serve` command, this regenerates output files when source files change.
|
||||||
@ -38,7 +40,9 @@ You will need two terminals to get the live-reload experience.
|
|||||||
* On the second terminal, install a web server (such as [lite-server](https://github.com/johnpapa/lite-server)), and run it against the output folder. For example:
|
* On the second terminal, install a web server (such as [lite-server](https://github.com/johnpapa/lite-server)), and run it against the output folder. For example:
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
lite-server --baseDir="dist"
|
lite-server --baseDir="dist"
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The server will automatically reload your browser when new files are output.
|
The server will automatically reload your browser when new files are output.
|
||||||
@ -56,7 +60,9 @@ For the simplest deployment, create a production build and copy the output direc
|
|||||||
1. Start with the production build:
|
1. Start with the production build:
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
ng build --prod
|
ng build --prod
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
@ -77,8 +83,11 @@ Another simple way to deploy your Angular app is to use [GitHub Pages](https://h
|
|||||||
Make a note of the user name and project name in GitHub.
|
Make a note of the user name and project name in GitHub.
|
||||||
|
|
||||||
1. Build your project using Github project name, with the Angular CLI command [`ng build`](cli/build) and the options shown here:
|
1. Build your project using Github project name, with the Angular CLI command [`ng build`](cli/build) and the options shown here:
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
ng build --prod --output-path docs --base-href /<project_name>/
|
|
||||||
|
ng build --prod --output-path docs --base-href /<project_name>/
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`.
|
1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`.
|
||||||
@ -143,13 +152,12 @@ The list is by no means exhaustive, but should provide you with a good starting
|
|||||||
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
|
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
|
||||||
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
|
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
|
||||||
|
|
||||||
<code-example format=".">
|
<code-example>
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
# If an existing asset or directory is requested go to it as it is
|
# If an existing asset or directory is requested go to it as it is
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
|
||||||
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
|
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
|
||||||
RewriteRule ^ - [L]
|
RewriteRule ^ - [L]<br>
|
||||||
|
|
||||||
# If the requested resource doesn't exist, use index.html
|
# If the requested resource doesn't exist, use index.html
|
||||||
RewriteRule ^ /index.html
|
RewriteRule ^ /index.html
|
||||||
</code-example>
|
</code-example>
|
||||||
@ -159,15 +167,15 @@ The list is by no means exhaustive, but should provide you with a good starting
|
|||||||
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
|
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
|
||||||
modified to serve `index.html`:
|
modified to serve `index.html`:
|
||||||
|
|
||||||
<code-example format=".">
|
```
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
</code-example>
|
```
|
||||||
|
|
||||||
|
|
||||||
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
|
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
|
||||||
[here](http://stackoverflow.com/a/26152011/2116927):
|
[here](http://stackoverflow.com/a/26152011/2116927):
|
||||||
|
|
||||||
<code-example format='.'>
|
<code-example format='.' language="xml">
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
@ -182,7 +190,6 @@ modified to serve `index.html`:
|
|||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
@ -200,12 +207,11 @@ and to
|
|||||||
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
|
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
|
||||||
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
|
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
|
||||||
|
|
||||||
<code-example format=".">
|
<code-example language="json">
|
||||||
"rewrites": [ {
|
"rewrites": [ {
|
||||||
"source": "**",
|
"source": "**",
|
||||||
"destination": "/index.html"
|
"destination": "/index.html"
|
||||||
} ]
|
} ]
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
{@a cors}
|
{@a cors}
|
||||||
@ -248,7 +254,9 @@ See [`ng build`](cli/build) for more about CLI build options and what they do.
|
|||||||
In addition to build optimizations, Angular also has a runtime production mode. Angular apps run in development mode by default, as you can see by the following message on the browser console:
|
In addition to build optimizations, Angular also has a runtime production mode. Angular apps run in development mode by default, as you can see by the following message on the browser console:
|
||||||
|
|
||||||
<code-example format="nocode">
|
<code-example format="nocode">
|
||||||
|
|
||||||
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
|
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Switching to _production mode_ makes it run faster by disabling development specific checks such as the dual change detection cycles.
|
Switching to _production mode_ makes it run faster by disabling development specific checks such as the dual change detection cycles.
|
||||||
@ -267,9 +275,9 @@ Configure the Angular Router to defer loading of all other modules (and their as
|
|||||||
or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading")
|
or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading")
|
||||||
them on demand.
|
them on demand.
|
||||||
|
|
||||||
<div class="alert is-helpful>
|
<div class="callout is-helpful>
|
||||||
|
|
||||||
#### Don't eagerly import something from a lazy-loaded module
|
<header>Don't eagerly import something from a lazy-loaded module</header>
|
||||||
|
|
||||||
If you mean to lazy-load a module, be careful not import it
|
If you mean to lazy-load a module, be careful not import it
|
||||||
in a file that's eagerly loaded when the app starts (such as the root `AppModule`).
|
in a file that's eagerly loaded when the app starts (such as the root `AppModule`).
|
||||||
@ -313,26 +321,34 @@ tool is a great way to inspect the generated JavaScript bundles after a producti
|
|||||||
Install `source-map-explorer`:
|
Install `source-map-explorer`:
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
npm install source-map-explorer --save-dev
|
npm install source-map-explorer --save-dev
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Build your app for production _including the source maps_
|
Build your app for production _including the source maps_
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
ng build --prod --source-map
|
ng build --prod --source-map
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
List the generated bundles in the `dist/` folder.
|
List the generated bundles in the `dist/` folder.
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
ls dist/*.bundle.js
|
ls dist/*.bundle.js
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Run the explorer to generate a graphical representation of one of the bundles.
|
Run the explorer to generate a graphical representation of one of the bundles.
|
||||||
The following example displays the graph for the _main_ bundle.
|
The following example displays the graph for the _main_ bundle.
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
node_modules/.bin/source-map-explorer dist/main.*.bundle.js
|
node_modules/.bin/source-map-explorer dist/main.*.bundle.js
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
|
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
|
||||||
@ -370,56 +386,77 @@ the subfolder is `my/app/` and you should add `<base href="/my/app/">` to the se
|
|||||||
When the `base` tag is mis-configured, the app fails to load and the browser console displays `404 - Not Found` errors
|
When the `base` tag is mis-configured, the app fails to load and the browser console displays `404 - Not Found` errors
|
||||||
for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately.
|
for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately.
|
||||||
|
|
||||||
|
{@a differential-loading}
|
||||||
|
|
||||||
## Differential Loading
|
## Differential Loading
|
||||||
|
|
||||||
When building web applications, making sure your application is compatible with the majority of browsers is a goal. Even as JavaScript continues to evolve, with new features being introduced, not all browsers are updated with support for these new features at the same pace. This is where compilation and [polyfills](guide/browser-support#polyfills) come in. The code you write in development using TypeScript is compiled and bundled into a format that is compatible with most browsers, commonly known as ES5. Polyfills are used bridge the gap, providing functionality that simply doesn't exist in some legacy browsers.
|
When building web applications, making sure your application is compatible with the majority of browsers is a goal.
|
||||||
|
Even as JavaScript continues to evolve, with new features being introduced, not all browsers are updated with support for these new features at the same pace.
|
||||||
|
|
||||||
There is a cost to ensure this browser compatibility, and it comes in the form of larger bundle size. All modern browsers support ES2015 and beyond, but in most cases, you still have to account for users accessing your application from a browser that doesn't. To maximize compatibility, you ship a single bundle that includes all your compiled code, plus any polyfills that may be needed. Users with modern browsers shouldn't pay the price of increased bundle size when used in a modern browser that supports many of the latest features in JavaScript. This is where differential loading comes into play.
|
The code you write in development using TypeScript is compiled and bundled into ES2015, the JavaScript syntax that is compatible with most browsers.
|
||||||
|
All modern browsers support ES2015 and beyond, but in most cases, you still have to account for users accessing your application from a browser that doesn't.
|
||||||
|
When targeting older browsers, [polyfills](guide/browser-support#polyfills) can bridge the gap by providing functionality that doesn't exist in the older versions of JavaScript supported by those browsers.
|
||||||
|
|
||||||
Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application. The modern bundle contains modern syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size. The second bundle, includes the additional compiled code, all necessary polyfills, and results in a larger bundle size. This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs.
|
To maximize compatibility, you could ship a single bundle that includes all your compiled code, plus any polyfills that may be needed.
|
||||||
|
Users with modern browsers, however, shouldn't have to pay the price of increased bundle size that comes with polyfills they don't need.
|
||||||
|
Differential loading, which is supported by default in Angular CLI version 8 and higher, solves this problem.
|
||||||
|
|
||||||
|
Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application.
|
||||||
|
|
||||||
|
* The first bundle contains modern ES2015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size.
|
||||||
|
|
||||||
|
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers.
|
||||||
|
|
||||||
|
This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs.
|
||||||
|
|
||||||
### Differential builds
|
### Differential builds
|
||||||
|
|
||||||
The Angular CLI handles differential loading for you as part of the _build_ process for deployment. The Angular CLI will produce the necessary bundles used for differential loading, based on your browser support requirements and compilation target.
|
The Angular CLI handles differential loading for you as part of the _build_ process for deployment.
|
||||||
|
The `ng build` command produces the necessary bundles used for differential loading, based on your browser support requirements and compilation target.
|
||||||
|
|
||||||
The Angular CLI uses two configurations for differential loading:
|
The Angular CLI uses two configurations for differential loading:
|
||||||
|
|
||||||
- Browserslist - The `browserslist` configuration file is included in your application [project structure](guide/file-structure#application-configuration-files) and provides the minimum browsers your application supports. See the [Browserslist spec](https://github.com/browserslist/browserslist) for complete configuration options.
|
* Browsers list
|
||||||
- tsconfig.json - The `target` in the TypeScript `compilerOptions` determines the ECMAScript target version that the code is compiled to. Modern browsers support ES2015 natively, while ES5 is more commonly used to support legacy browsers.
|
The `browserslist` configuration file is included in your application [project structure](guide/file-structure#application-configuration-files) and provides the minimum browsers your application supports. See the [Browserslist spec](https://github.com/browserslist/browserslist) for complete configuration options.
|
||||||
|
|
||||||
|
* TypeScript configuration
|
||||||
|
In the TypeScript configuration file, `tsconfig.json`, the `target` in the `compilerOptions` section determines the ECMAScript target version that the code is compiled to.
|
||||||
|
Modern browsers support ES2015 natively, while ES5 is more commonly used to support legacy browsers.
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
**Note:** Differential loading is currently only supported when using `es2015` as a compilation `target`. When used with targets higher than `es2015`, a warning is emitted during build time.
|
Differential loading is currently only supported when using `es2015` as a compilation `target`. When used with targets higher than `es2015`, a warning is emitted during build time.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
The CLI queries the Browserslist configuration, and checks the `target` to determine if support for legacy browsers is required. The combination of these two configurations determines whether multiple bundles are produced when you create a _build_. When you create a development build using [`ng build`](cli/build) and differential loading is enabled, the output produced is simpler and easier to debug, allowing you to rely less on sourcemaps of compiled code. When you create a production build using [`ng build --prod`](cli/build), the CLI uses the defined configurations above to determine the bundles to build for deployment of your application.
|
The CLI queries the Browserslist configuration, and checks the `target` to determine if support for legacy browsers is required.
|
||||||
|
The combination of these two configurations determines whether multiple bundles are produced when you create a _build_.
|
||||||
|
When you create a development build using [`ng build`](cli/build) and differential loading is enabled, the output produced is simpler and easier to debug, allowing you to rely less on sourcemaps of compiled code.
|
||||||
|
When you create a production build using [`ng build --prod`](cli/build), the CLI uses the defined configurations above to determine the bundles to build for deployment of your application.
|
||||||
|
|
||||||
The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`.
|
The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`.
|
||||||
|
|
||||||
```html
|
<code-example language="html">
|
||||||
<!-- ... -->
|
<body>
|
||||||
<body>
|
<app-root></app-root>
|
||||||
<app-root></app-root>
|
<script src="runtime-es2015.js" type="module"></script>
|
||||||
<script src="runtime-es2015.js" type="module"></script>
|
<script src="runtime-es5.js" nomodule></script>
|
||||||
<script src="runtime-es5.js" nomodule></script>
|
<script src="polyfills-es2015.js" type="module"></script>
|
||||||
<script src="polyfills-es2015.js" type="module"></script>
|
<script src="polyfills-es5.js" nomodule></script>
|
||||||
<script src="polyfills-es5.js" nomodule></script>
|
<script src="styles-es2015.js" type="module"></script>
|
||||||
<script src="styles-es2015.js" type="module"></script>
|
<script src="styles-es5.js" nomodule></script>
|
||||||
<script src="styles-es5.js" nomodule></script>
|
<script src="vendor-es2015.js" type="module"></script>
|
||||||
<script src="vendor-es2015.js" type="module"></script>
|
<script src="vendor-es5.js" nomodule></script>
|
||||||
<script src="vendor-es5.js" nomodule></script>
|
<script src="main-es2015.js" type="module"></script>
|
||||||
<script src="main-es2015.js" type="module"></script>
|
<script src="main-es5.js" nomodule></script>
|
||||||
<script src="main-es5.js" nomodule></script>
|
</body>
|
||||||
</body>
|
</code-example>
|
||||||
<!-- ... -->
|
|
||||||
```
|
|
||||||
|
|
||||||
Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules.
|
Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules.
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
**Note:** Some legacy browsers still download both bundles, but only execute the appropriate scripts based on the attributes mentioned above. You can read more on the issue [here](https://github.com/philipwalton/webpack-esnext-boilerplate/issues/1).
|
Some legacy browsers still download both bundles, but only execute the appropriate scripts based on the attributes mentioned above. You can read more on the issue [here](https://github.com/philipwalton/webpack-esnext-boilerplate/issues/1).
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -427,11 +464,10 @@ See the [configuration table](#configuration-table) below for the configurations
|
|||||||
|
|
||||||
### Configuring differential loading
|
### Configuring differential loading
|
||||||
|
|
||||||
Differential loading for creating builds is already supported with version 8 and later of the Angular CLI. For each application project in your workspace, you can configure how builds are produced based on the mentioned `browserslist` and `tsconfig.json` files in your application project.
|
Differential loading is supported by default with version 8 and later of the Angular CLI.
|
||||||
|
For each application project in your workspace, you can configure how builds are produced based on the `browserslist` and `tsconfig.json` files in your application project.
|
||||||
|
|
||||||
Look at the default configuration for a newly created Angular application:
|
For a newly created Angular application, the default `browserslist` looks like this:
|
||||||
|
|
||||||
The `browserslist` looks like this:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
> 0.5%
|
> 0.5%
|
||||||
@ -443,8 +479,8 @@ not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|||||||
|
|
||||||
The `tsconfig.json` looks like this:
|
The `tsconfig.json` looks like this:
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
```
|
|
||||||
{
|
{
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
@ -467,13 +503,14 @@ The `tsconfig.json` looks like this:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
By default, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015. As a result, this produces two builds, and differential loading is enabled. If you ignore browsers without ES2015 support, a single build is produced. To see the build result for differential loading based on different configurations, refer to the table below.
|
By default, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015. As a result, this produces two builds, and differential loading is enabled. If you ignore browsers without ES2015 support, a single build is produced. To see the build result for differential loading based on different configurations, refer to the table below.
|
||||||
|
|
||||||
<div class="alert is-important">
|
<div class="alert is-important">
|
||||||
|
|
||||||
**Note:** To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+Chrome+41%2C+not+dead%2C+not+IE+9-11).
|
To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11).
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -496,3 +533,145 @@ To explicitly disable differential loading:
|
|||||||
|
|
||||||
- Enable the `dead` or `IE` browsers in the `browserslist` config file by removing the `not` keyword in front of them.
|
- Enable the `dead` or `IE` browsers in the `browserslist` config file by removing the `not` keyword in front of them.
|
||||||
- Set the `target` in the `compilerOptions` to `es5`.
|
- Set the `target` in the `compilerOptions` to `es5`.
|
||||||
|
|
||||||
|
{@a test-and-serve}
|
||||||
|
|
||||||
|
## Local development in older browsers
|
||||||
|
|
||||||
|
In Angular CLI version 8 and higher, differential loading is enabled by default for the `ng build` command.
|
||||||
|
The `ng serve`, `ng test`, and `ng e2e` commands, however, generate a single ES2015 build which cannot run in older browsers that don't support the modules, such as IE 11.
|
||||||
|
|
||||||
|
If you want to run ES5 code during development, you could disable differential loading completely.
|
||||||
|
To maintain the benefits of differential loading, however, a better option is to define multiple configurations for `ng serve`, `ng e2e`, and `ng test`.
|
||||||
|
|
||||||
|
{@a differential-serve}
|
||||||
|
|
||||||
|
### Configuring serve for ES5
|
||||||
|
|
||||||
|
To do this for `ng serve`, create a new file, `tsconfig-es5.app.json` next to `tsconfig.app.json` with the following content.
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.app.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
In `angular.json` add two new configuration sections under the `build` and `serve` targets to point to the new TypeScript configuration.
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"es5": {
|
||||||
|
"tsConfig": "./tsconfig-es5.app.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"es5": {
|
||||||
|
"browserTarget": "app:build:es5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
You can then run the serve with this configuration.
|
||||||
|
|
||||||
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
|
ng serve --configuration es5
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
{@a differential-test}
|
||||||
|
|
||||||
|
### Configuring the test command
|
||||||
|
|
||||||
|
Create a new file, `tsconfig-es5.spec.json` next to `tsconfig.spec.json` with the following content.
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.spec.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"es5": {
|
||||||
|
"tsConfig": "./tsconfig-es5.spec.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
You can then run the tests with this configuration
|
||||||
|
|
||||||
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
|
ng test --configuration es5
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
### Configuring the e2e command
|
||||||
|
|
||||||
|
Create an [ES5 serve configuration](guide/deployment#configuring-serve-for-es5) as explained above, and configuration an ES5 configuration for the E2E target.
|
||||||
|
|
||||||
|
<code-example language="json">
|
||||||
|
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
...
|
||||||
|
},
|
||||||
|
"es5": {
|
||||||
|
"devServerTarget": "app:serve:es5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
You can then run the e2e's with this configuration
|
||||||
|
|
||||||
|
<code-example language="none" class="code-shell">
|
||||||
|
|
||||||
|
ng e2e --configuration es5
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
@ -465,3 +465,99 @@ For more information about using `@angular/common/http`, see the [HttpClient gui
|
|||||||
| `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
|
| `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
|
||||||
| `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
|
| `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
|
||||||
|
|
||||||
|
## Renderer to Renderer2 migration
|
||||||
|
|
||||||
|
### Migration Overview
|
||||||
|
|
||||||
|
The `Renderer` class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer `Renderer2` API and what it means for your app.
|
||||||
|
|
||||||
|
### Why should I migrate to Renderer2?
|
||||||
|
|
||||||
|
The deprecated `Renderer` class has been removed in version 9 of Angular, so it's necessary to migrate to a supported API. Using `Renderer2` is the recommended strategy because it supports a similar set of functionality to `Renderer`. The API surface is quite large (with 19 methods), but the schematic should simplify this process for your applications.
|
||||||
|
|
||||||
|
### Is there action required on my end?
|
||||||
|
|
||||||
|
No. The schematic should handle most cases with the exception of `Renderer.animate()` and `Renderer.setDebugInfo()`, which already aren’t supported.
|
||||||
|
|
||||||
|
### What are the `__ngRendererX` methods? Why are they necessary?
|
||||||
|
|
||||||
|
Some methods either don't have exact equivalents in `Renderer2`, or they correspond to more than one expression. For example, both renderers have a `createElement()` method, but they're not equal because a call such as `renderer.createElement(parentNode, namespaceAndName)` in the `Renderer` corresponds to the following block of code in `Renderer2`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const [namespace, name] = splitNamespace(namespaceAndName);
|
||||||
|
const el = renderer.createElement(name, namespace);
|
||||||
|
if (parentNode) {
|
||||||
|
renderer.appendChild(parentNode, el);
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
```
|
||||||
|
|
||||||
|
Migration has to guarantee that the return values of functions and types of variables stay the same. To handle the majority of cases safely, the schematic declares helper functions at the bottom of the user's file. These helpers encapsulate your own logic and keep the replacements inside your code down to a single function call. Here's an example of how the `createElement()` migration looks:
|
||||||
|
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
public createAndAppendElement() {
|
||||||
|
const el = this.renderer.createElement('span');
|
||||||
|
el.textContent = 'hello world';
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
|
||||||
|
<code-example>
|
||||||
|
|
||||||
|
public createAndAppendElement() {
|
||||||
|
const el = __ngRendererCreateElement(this.renderer, this.element, 'span');
|
||||||
|
el.textContent = 'hello world';
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
// Generated code at the bottom of the file
|
||||||
|
__ngRendererCreateElement(renderer: any, parentNode: any, nameAndNamespace: any) {
|
||||||
|
const [namespace, name] = __ngRendererSplitNamespace(namespaceAndName);
|
||||||
|
const el = renderer.createElement(name, namespace);
|
||||||
|
if (parentNode) {
|
||||||
|
renderer.appendChild(parentNode, el);
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
__ngRendererSplitNamespace(nameAndNamespace: any) {
|
||||||
|
// returns the split name and namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
When implementing these helper functions, the schematic ensures that they're only declared once per file and that their names are unique enough that there's a small chance of colliding with pre-existing functions in your code. The schematic also keeps their parameter types as `any` so that it doesn't have to insert extra logic that ensures that their values have the correct type.
|
||||||
|
|
||||||
|
### I’m a library author. Should I run this migration?
|
||||||
|
|
||||||
|
**Library authors should definitely use this migration to move away from the `Renderer`. Otherwise, the libraries won't work with applications built with version 9.**
|
||||||
|
|
||||||
|
|
||||||
|
### Full list of method migrations
|
||||||
|
|
||||||
|
The following table shows all methods that the migration maps from `Renderer` to `Renderer2`.
|
||||||
|
|
||||||
|
|Renderer|Renderer2|
|
||||||
|
|---|---|
|
||||||
|
|`listen(renderElement, name, callback)`|`listen(renderElement, name, callback)`|
|
||||||
|
|`setElementProperty(renderElement, propertyName, propertyValue)`|`setProperty(renderElement, propertyName, propertyValue)`|
|
||||||
|
|`setText(renderNode, text)`|`setValue(renderNode, text)`|
|
||||||
|
|`listenGlobal(target, name, callback)`|`listen(target, name, callback)`|
|
||||||
|
|`selectRootElement(selectorOrNode, debugInfo?)`|`selectRootElement(selectorOrNode)`|
|
||||||
|
|`createElement(parentElement, name, debugInfo?)`|`appendChild(parentElement, createElement(name))`|
|
||||||
|
|`setElementStyle(el, style, value?)`|`value == null ? removeStyle(el, style) : setStyle(el, style, value)`
|
||||||
|
|`setElementAttribute(el, name, value?)`|`attributeValue == null ? removeAttribute(el, name) : setAttribute(el, name, value)`
|
||||||
|
|`createText(parentElement, value, debugInfo?)`|`appendChild(parentElement, createText(value))`|
|
||||||
|
|`createTemplateAnchor(parentElement)`|`appendChild(parentElement, createComment(''))`|
|
||||||
|
|`setElementClass(renderElement, className, isAdd)`|`isAdd ? addClass(renderElement, className) : removeClass(renderElement, className)`|
|
||||||
|
|`projectNodes(parentElement, nodes)`|`for (let i = 0; i < nodes.length; i<ins></ins>) { appendChild(parentElement, nodes<i>); }`|
|
||||||
|
|`attachViewAfter(node, viewRootNodes)`|`const parentElement = parentNode(node); const nextSibling = nextSibling(node); for (let i = 0; i < viewRootNodes.length; i<ins></ins>) { insertBefore(parentElement, viewRootNodes<i>, nextSibling);}`|
|
||||||
|
|`detachView(viewRootNodes)`|`for (let i = 0; i < viewRootNodes.length; i<ins></ins>) {const node = viewRootNodes<i>; const parentElement = parentNode(node); removeChild(parentElement, node);}`|
|
||||||
|
|`destroyView(hostElement, viewAllNodes)`|`for (let i = 0; i < viewAllNodes.length; i<ins></ins>) { destroyNode(viewAllNodes<i>); }`|
|
||||||
|
|`setBindingDebugInfo()`|This function is a noop in `Renderer2`.|
|
||||||
|
|`createViewRoot(hostElement)`|Should be replaced with a reference to `hostElement`|
|
||||||
|
|`invokeElementMethod(renderElement, methodName, args?)`|`(renderElement as any)<methodName>.apply(renderElement, args);`|
|
||||||
|
|`animate(element, startingStyles, keyframes, duration, delay, easing, previousPlayers?)`|Throws an error (same behavior as `Renderer.animate()`)|
|
||||||
|
@ -41,9 +41,7 @@ changing the template and the body of the component.
|
|||||||
When you're done, it should look like this:
|
When you're done, it should look like this:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts">
|
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -53,9 +51,7 @@ The template displays the two component properties using double curly brace
|
|||||||
interpolation:
|
interpolation:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
|
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -97,9 +93,7 @@ The CSS `selector` in the `@Component` decorator specifies an element named `<ap
|
|||||||
That element is a placeholder in the body of your `index.html` file:
|
That element is a placeholder in the body of your `index.html` file:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/index.html" linenums="false" header="src/index.html (body)" region="body">
|
<code-example path="displaying-data/src/index.html" header="src/index.html (body)" region="body"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -148,9 +142,7 @@ In either style, the template data bindings have the same access to the componen
|
|||||||
Although this example uses variable assignment to initialize the components, you could instead declare and initialize the properties using a constructor:
|
Although this example uses variable assignment to initialize the components, you could instead declare and initialize the properties using a constructor:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" linenums="false" region="class">
|
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" region="class"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -163,9 +155,7 @@ This app uses more terse "variable assignment" style simply for brevity.
|
|||||||
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
|
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (class)" region="class">
|
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -173,9 +163,7 @@ Now use the Angular `ngFor` directive in the template to display
|
|||||||
each item in the `heroes` list.
|
each item in the `heroes` list.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
|
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -184,9 +172,7 @@ in the `<li>` element is the Angular "repeater" directive.
|
|||||||
It marks that `<li>` element (and its children) as the "repeater template":
|
It marks that `<li>` element (and its children) as the "repeater template":
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (li)" region="li">
|
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (li)" region="li"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -251,9 +237,7 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
|
|||||||
With the following code:
|
With the following code:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts">
|
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -265,9 +249,7 @@ The declaration of the constructor parameters takes advantage of a TypeScript sh
|
|||||||
Consider the first parameter:
|
Consider the first parameter:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts (id)" region="id">
|
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts (id)" region="id"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -285,9 +267,7 @@ After importing the `Hero` class, the `AppComponent.heroes` property can return
|
|||||||
of `Hero` objects:
|
of `Hero` objects:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (heroes)" region="heroes">
|
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (heroes)" region="heroes"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -296,9 +276,7 @@ At the moment it displays the hero's `id` and `name`.
|
|||||||
Fix that to display only the hero's `name` property.
|
Fix that to display only the hero's `name` property.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
|
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -316,9 +294,7 @@ The Angular `ngIf` directive inserts or removes an element based on a _truthy/fa
|
|||||||
To see it in action, add the following paragraph at the bottom of the template:
|
To see it in action, add the following paragraph at the bottom of the template:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="displaying-data/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (message)" region="message">
|
<code-example path="displaying-data/src/app/app.component.ts" header="src/app/app.component.ts (message)" region="message"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -428,7 +428,7 @@ You control the _code-example_ output by setting one or more of its attributes:
|
|||||||
|
|
||||||
* `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment").
|
* `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment").
|
||||||
|
|
||||||
* `linenums`- value may be `true`, `false`, or a `number`. When not specified, line numbers are automatically displayed when there are greater than 10 lines of code. The rarely used `number` option starts line numbering at the given value. `linenums=4` sets the starting line number to 4.
|
* `linenums`- value may be `true`, `false`, or a `number`. When not specified, line numbers default to `false` (i.e. no line numbers are displayed). The rarely used `number` option starts line numbering at the given value. `linenums=4` sets the starting line number to 4.
|
||||||
|
|
||||||
* `class`- code snippets can be styled with the CSS classes `no-box`, `code-shell`, and `avoid`.
|
* `class`- code snippets can be styled with the CSS classes `no-box`, `code-shell`, and `avoid`.
|
||||||
|
|
||||||
@ -465,8 +465,6 @@ A couple of observations:
|
|||||||
1. Omitting the `header` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header.
|
1. Omitting the `header` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header.
|
||||||
There's no need to repeat the header.
|
There's no need to repeat the header.
|
||||||
|
|
||||||
1. The line numbers disappeared. By default, the doc viewer omits line numbers when there are fewer than 10 lines of code; it adds line numbers after that. You can turn line numbers on or off explicitly by setting the `linenums` attribute.
|
|
||||||
|
|
||||||
#### Example of bad code
|
#### Example of bad code
|
||||||
|
|
||||||
Sometimes you want to display an example of bad code or bad design.
|
Sometimes you want to display an example of bad code or bad design.
|
||||||
@ -496,18 +494,18 @@ Code tabs display code much like _code examples_ do. The added advantage is tha
|
|||||||
|
|
||||||
#### Code-tabs attributes
|
#### Code-tabs attributes
|
||||||
|
|
||||||
* `linenums`: The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when code for a tab pane has greater than 10 lines of code.
|
* `linenums`: The value can be `true`, `false` or a number indicating the starting line number. If not specified, it defaults to `false`.
|
||||||
|
|
||||||
#### Code-pane attributes
|
#### Code-pane attributes
|
||||||
|
|
||||||
* `path` - a file in the content/examples folder
|
* `path` - a file in the content/examples folder
|
||||||
* `header` - seen in the header of a tab
|
* `header` - seen in the header of a tab
|
||||||
* `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10.
|
* `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, it defaults to `false`.
|
||||||
|
|
||||||
The next example displays multiple code tabs, each with its own header.
|
The next example displays multiple code tabs, each with its own header.
|
||||||
It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels.
|
It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels.
|
||||||
|
|
||||||
<code-tabs linenums="false">
|
<code-tabs linenums="true">
|
||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.html"
|
header="app.component.html"
|
||||||
path="docs-style-guide/src/app/app.component.html">
|
path="docs-style-guide/src/app/app.component.html">
|
||||||
@ -515,7 +513,7 @@ It demonstrates control over display of line numbers at both the `<code-tabs>` a
|
|||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.ts"
|
header="app.component.ts"
|
||||||
path="docs-style-guide/src/app/app.component.ts"
|
path="docs-style-guide/src/app/app.component.ts"
|
||||||
linenums="true">
|
linenums="false">
|
||||||
</code-pane>
|
</code-pane>
|
||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.css (heroes)"
|
header="app.component.css (heroes)"
|
||||||
@ -530,11 +528,11 @@ It demonstrates control over display of line numbers at both the `<code-tabs>` a
|
|||||||
|
|
||||||
Here's the markup for that example.
|
Here's the markup for that example.
|
||||||
|
|
||||||
Note how the `linenums` attribute in the `<code-tabs>` explicitly disables numbering for all panes.
|
Note how the `linenums` attribute in the `<code-tabs>` explicitly enables numbering for all panes.
|
||||||
The `linenums` attribute in the second pane restores line numbering for _itself only_.
|
The `linenums` attribute in the second pane disables line numbering for _itself only_.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<code-tabs linenums="false">
|
<code-tabs linenums="true">
|
||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.html"
|
header="app.component.html"
|
||||||
path="docs-style-guide/src/app/app.component.html">
|
path="docs-style-guide/src/app/app.component.html">
|
||||||
@ -542,7 +540,7 @@ The `linenums` attribute in the second pane restores line numbering for _itself
|
|||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.ts"
|
header="app.component.ts"
|
||||||
path="docs-style-guide/src/app/app.component.ts"
|
path="docs-style-guide/src/app/app.component.ts"
|
||||||
linenums="true">
|
linenums="false">
|
||||||
</code-pane>
|
</code-pane>
|
||||||
<code-pane
|
<code-pane
|
||||||
header="app.component.css (heroes)"
|
header="app.component.css (heroes)"
|
||||||
@ -667,7 +665,7 @@ Examine the `src/app/app.component.ts` file which defines two nested _#docregion
|
|||||||
|
|
||||||
The inner, `class-skeleton` region appears twice, once to capture the code that opens the class definition and once to capture the code that closes the class definition.
|
The inner, `class-skeleton` region appears twice, once to capture the code that opens the class definition and once to capture the code that closes the class definition.
|
||||||
|
|
||||||
<code-example linenums="false">
|
<code-example>
|
||||||
// #docplaster
|
// #docplaster
|
||||||
...
|
...
|
||||||
// #docregion class, class-skeleton
|
// #docregion class, class-skeleton
|
||||||
|
@ -35,9 +35,7 @@ The ad banner uses a helper directive called `AdDirective` to
|
|||||||
mark valid insertion points in the template.
|
mark valid insertion points in the template.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts" linenums="false">
|
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -62,9 +60,7 @@ To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
|
|||||||
where to dynamically load components.
|
where to dynamically load components.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)" linenums="false">
|
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -91,9 +87,7 @@ With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdI
|
|||||||
and loads a new component every 3 seconds by calling `loadComponent()`.
|
and loads a new component every 3 seconds by calling `loadComponent()`.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)" linenums="false">
|
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -150,9 +144,7 @@ dynamically loaded components since they load at runtime.
|
|||||||
To ensure that the compiler still generates a factory,
|
To ensure that the compiler still generates a factory,
|
||||||
add dynamically loaded components to the `NgModule`'s `entryComponents` array:
|
add dynamically loaded components to the `NgModule`'s `entryComponents` array:
|
||||||
|
|
||||||
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)" linenums="false">
|
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,18 +77,14 @@ appropriate controls dynamically.
|
|||||||
via the `type` property.
|
via the `type` property.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts" linenums="false">
|
<code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
`DropdownQuestion` presents a list of choices in a select box.
|
`DropdownQuestion` presents a list of choices in a select box.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts" linenums="false">
|
<code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -97,9 +93,7 @@ In a nutshell, the form group consumes the metadata from the question model and
|
|||||||
allows you to specify default values and validation rules.
|
allows you to specify default values and validation rules.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts" linenums="false">
|
<code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a form-component}
|
{@a form-component}
|
||||||
|
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
# Entry Components
|
# Entry Components
|
||||||
|
|
||||||
#### Prerequisites:
|
|
||||||
|
|
||||||
A basic understanding of the following concepts:
|
|
||||||
* [Bootstrapping](guide/bootstrapping).
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
An entry component is any component that Angular loads imperatively, (which means you’re not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition.
|
An entry component is any component that Angular loads imperatively, (which means you’re not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition.
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
Feature modules are NgModules for the purpose of organizing code.
|
Feature modules are NgModules for the purpose of organizing code.
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
A basic understanding of the following:
|
|
||||||
* [Bootstrapping](guide/bootstrapping).
|
|
||||||
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
|
||||||
* [Frequently Used Modules](guide/frequent-ngmodules).
|
|
||||||
|
|
||||||
For the final sample app with a feature module that this page describes,
|
For the final sample app with a feature module that this page describes,
|
||||||
see the <live-example></live-example>.
|
see the <live-example></live-example>.
|
||||||
|
|
||||||
@ -72,8 +66,7 @@ ng generate component customer-dashboard/CustomerDashboard
|
|||||||
This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info:
|
This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
|
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" header="src/app/customer-dashboard/customer-dashboard.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -83,8 +76,7 @@ The `CustomerDashboardComponent` is now in the JavaScript import list at the top
|
|||||||
|
|
||||||
To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array:
|
To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array:
|
||||||
|
|
||||||
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts" linenums="false">
|
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules don’t expose their components.
|
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules don’t expose their components.
|
||||||
@ -94,21 +86,18 @@ Now the `AppModule` knows about the feature module. If you were to add any servi
|
|||||||
|
|
||||||
When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup:
|
When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup:
|
||||||
|
|
||||||
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" header="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false">
|
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" header="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardComponent`:
|
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardComponent`:
|
||||||
|
|
||||||
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
|
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`:
|
Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`:
|
||||||
|
|
||||||
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
|
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
|
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
|
||||||
|
@ -4,7 +4,7 @@ You develop applications in the context of an Angular [workspace](guide/glossary
|
|||||||
|
|
||||||
The Angular CLI `ng new` command creates a workspace.
|
The Angular CLI `ng new` command creates a workspace.
|
||||||
|
|
||||||
<code-example language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
ng new <my-project>
|
ng new <my-project>
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ An `e2e/` folder at the top level contains source files for a set of end-to-end
|
|||||||
|
|
||||||
For a multi-project workspace, application-specific end-to-end tests are in the project root, under `projects/project-name/e2e/`.
|
For a multi-project workspace, application-specific end-to-end tests are in the project root, under `projects/project-name/e2e/`.
|
||||||
|
|
||||||
<code-example language="none" linenums="false">
|
<code-example language="none">
|
||||||
e2e/
|
e2e/
|
||||||
src/ (end-to-end tests for my-app)
|
src/ (end-to-end tests for my-app)
|
||||||
app.e2e-spec.ts
|
app.e2e-spec.ts
|
||||||
@ -131,13 +131,13 @@ A multi-project workspace is suitable for an enterprise that uses a single repos
|
|||||||
If you intend to have multiple projects in a workspace, you can skip the initial application generation when you create the workspace, and give the workspace a unique name.
|
If you intend to have multiple projects in a workspace, you can skip the initial application generation when you create the workspace, and give the workspace a unique name.
|
||||||
The following command creates a workspace with all of the workspace-wide configuration files, but no root-level application.
|
The following command creates a workspace with all of the workspace-wide configuration files, but no root-level application.
|
||||||
|
|
||||||
<code-example language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
ng new my-workspace --createApplication="false"
|
ng new my-workspace --createApplication="false"
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
You can then generate apps and libraries with names that are unique within the workspace.
|
You can then generate apps and libraries with names that are unique within the workspace.
|
||||||
|
|
||||||
<code-example language="bash" linenums="false">
|
<code-example language="bash">
|
||||||
cd my-workspace
|
cd my-workspace
|
||||||
ng generate application my-first-app
|
ng generate application my-first-app
|
||||||
</code-example>
|
</code-example>
|
||||||
@ -148,7 +148,7 @@ The first explicitly generated application goes into the `projects/` folder alon
|
|||||||
Newly generated libraries are also added under `projects/`.
|
Newly generated libraries are also added under `projects/`.
|
||||||
When you create projects this way, the file structure of the workspace is entirely consistent with the structure of the [workspace configuration file](guide/workspace-config), `angular.json`.
|
When you create projects this way, the file structure of the workspace is entirely consistent with the structure of the [workspace configuration file](guide/workspace-config), `angular.json`.
|
||||||
|
|
||||||
<code-example language="none" linenums="false">
|
<code-example language="none">
|
||||||
my-workspace/
|
my-workspace/
|
||||||
... (workspace-wide config files)
|
... (workspace-wide config files)
|
||||||
projects/ (generated applications and libraries)
|
projects/ (generated applications and libraries)
|
||||||
|
@ -29,9 +29,7 @@ either a list of validation errors, which results in an INVALID status, or null,
|
|||||||
You can then inspect the control's state by exporting `ngModel` to a local template variable.
|
You can then inspect the control's state by exporting `ngModel` to a local template variable.
|
||||||
The following example exports `NgModel` into a variable called `name`:
|
The following example exports `NgModel` into a variable called `name`:
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" header="template/hero-form-template.component.html (name)" linenums="false">
|
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" header="template/hero-form-template.component.html (name)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Note the following:
|
Note the following:
|
||||||
@ -92,8 +90,7 @@ built-in validators—this time, in function form. See below:
|
|||||||
|
|
||||||
{@a reactive-component-class}
|
{@a reactive-component-class}
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" header="reactive/hero-form-reactive.component.ts (validator functions)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Note that:
|
Note that:
|
||||||
|
|
||||||
@ -106,8 +103,7 @@ for the template.
|
|||||||
|
|
||||||
If you look at the template for the name input again, it is fairly similar to the template-driven example.
|
If you look at the template for the name input again, it is fairly similar to the template-driven example.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" header="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" header="reactive/hero-form-reactive.component.html (name with error msg)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Key takeaways:
|
Key takeaways:
|
||||||
|
|
||||||
@ -125,8 +121,7 @@ Consider the `forbiddenNameValidator` function from previous
|
|||||||
[examples](guide/form-validation#reactive-component-class) in
|
[examples](guide/form-validation#reactive-component-class) in
|
||||||
this guide. Here's what the definition of that function looks like:
|
this guide. Here's what the definition of that function looks like:
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
|
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
|
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
|
||||||
|
|
||||||
@ -148,8 +143,7 @@ at which point the form uses the last value emitted for validation.
|
|||||||
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
|
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
|
||||||
to the `FormControl`.
|
to the `FormControl`.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" header="reactive/hero-form-reactive.component.ts (validator functions)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
### Adding to template-driven forms
|
### Adding to template-driven forms
|
||||||
|
|
||||||
@ -161,8 +155,7 @@ The corresponding `ForbiddenValidatorDirective` serves as a wrapper around the `
|
|||||||
Angular recognizes the directive's role in the validation process because the directive registers itself
|
Angular recognizes the directive's role in the validation process because the directive registers itself
|
||||||
with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators.
|
with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" header="shared/forbidden-name.directive.ts (providers)" linenums="false">
|
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" header="shared/forbidden-name.directive.ts (providers)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The directive class then implements the `Validator` interface, so that it can easily integrate
|
The directive class then implements the `Validator` interface, so that it can easily integrate
|
||||||
with Angular forms. Here is the rest of the directive to help you get an idea of how it all
|
with Angular forms. Here is the rest of the directive to help you get an idea of how it all
|
||||||
@ -173,9 +166,7 @@ comes together:
|
|||||||
|
|
||||||
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
|
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" header="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
|
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" header="template/hero-form-template.component.html (forbidden-name-input)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
@ -245,8 +236,7 @@ const heroForm = new FormGroup({
|
|||||||
|
|
||||||
The validator code is as follows:
|
The validator code is as follows:
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" header="shared/identity-revealed.directive.ts" linenums="false">
|
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" header="shared/identity-revealed.directive.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise.
|
The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise.
|
||||||
|
|
||||||
@ -255,8 +245,7 @@ First we retrieve the child controls by calling the `FormGroup`'s [get](api/form
|
|||||||
If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object.
|
If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object.
|
||||||
|
|
||||||
Next, to provide better user experience, we show an appropriate error message when the form is invalid.
|
Next, to provide better user experience, we show an appropriate error message when the form is invalid.
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" header="reactive/hero-form-template.component.html" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" header="reactive/hero-form-template.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Note that we check if:
|
Note that we check if:
|
||||||
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
||||||
@ -265,16 +254,13 @@ Note that we check if:
|
|||||||
### Adding to template driven forms
|
### Adding to template driven forms
|
||||||
First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms).
|
First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms).
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" header="shared/identity-revealed.directive.ts" linenums="false">
|
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" header="shared/identity-revealed.directive.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag.
|
Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag.
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" header="template/hero-form-template.component.html" linenums="false">
|
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" header="template/hero-form-template.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
To provide better user experience, we show an appropriate error message when the form is invalid.
|
To provide better user experience, we show an appropriate error message when the form is invalid.
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" header="template/hero-form-template.component.html" linenums="false">
|
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" header="template/hero-form-template.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Note that we check if:
|
Note that we check if:
|
||||||
- the form has the cross validation error returned by the `identityRevealed` validator,
|
- the form has the cross validation error returned by the `identityRevealed` validator,
|
||||||
@ -313,7 +299,7 @@ To validate the potential alter ego, we need to consult a central database of al
|
|||||||
|
|
||||||
Let's start by creating the validator class.
|
Let's start by creating the validator class.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/alter-ego.directive.ts" region="async-validator" linenums="false"></code-example>
|
<code-example path="form-validation/src/app/shared/alter-ego.directive.ts" region="async-validator"></code-example>
|
||||||
|
|
||||||
As you can see, the `UniqueAlterEgoValidator` class implements the `AsyncValidator` interface. In the constructor, we inject the `HeroesService` that has the following interface:
|
As you can see, the `UniqueAlterEgoValidator` class implements the `AsyncValidator` interface. In the constructor, we inject the `HeroesService` that has the following interface:
|
||||||
|
|
||||||
|
@ -109,9 +109,7 @@ Using the Angular CLI command [`ng generate class`](cli/generate), generate a ne
|
|||||||
|
|
||||||
With this content:
|
With this content:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero.ts" header="src/app/hero.ts">
|
<code-example path="forms/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
It's an anemic model with few requirements and no behavior. Perfect for the demo.
|
It's an anemic model with few requirements and no behavior. Perfect for the demo.
|
||||||
|
|
||||||
@ -122,9 +120,7 @@ The `alterEgo` is optional, so the constructor lets you omit it; note the questi
|
|||||||
|
|
||||||
You can create a new hero like this:
|
You can create a new hero like this:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" region="SkyDog">
|
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="SkyDog"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
## Create a form component
|
## Create a form component
|
||||||
|
|
||||||
@ -142,9 +138,7 @@ Using the Angular CLI command [`ng generate component`](cli/generate), generate
|
|||||||
|
|
||||||
With this content:
|
With this content:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (v1)" region="v1">
|
<code-example path="forms/src/app/hero-form/hero-form.component.ts" header="src/app/hero-form/hero-form.component.ts (v1)" region="v1"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
There’s nothing special about this component, nothing form-specific,
|
There’s nothing special about this component, nothing form-specific,
|
||||||
nothing to distinguish it from any component you've written before.
|
nothing to distinguish it from any component you've written before.
|
||||||
@ -176,9 +170,7 @@ Because template-driven forms are in their own module, you need to add the `Form
|
|||||||
|
|
||||||
Update it with the following:
|
Update it with the following:
|
||||||
|
|
||||||
<code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts">
|
<code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -204,9 +196,7 @@ Update it with the following:
|
|||||||
|
|
||||||
Replace the contents of its template with the following:
|
Replace the contents of its template with the following:
|
||||||
|
|
||||||
<code-example path="forms/src/app/app.component.html" header="src/app/app.component.html">
|
<code-example path="forms/src/app/app.component.html" header="src/app/app.component.html"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -221,9 +211,7 @@ Replace the contents of its template with the following:
|
|||||||
|
|
||||||
Update the template file with the following contents:
|
Update the template file with the following contents:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" header="src/app/hero-form/hero-form.component.html">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" header="src/app/hero-form/hero-form.component.html"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The language is simply HTML5. You're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
The language is simply HTML5. You're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
||||||
opening them up for user input in input boxes.
|
opening them up for user input in input boxes.
|
||||||
@ -259,9 +247,7 @@ Bootstrap gives the form a little style.
|
|||||||
|
|
||||||
To add the stylesheet, open `styles.css` and add the following import line at the top:
|
To add the stylesheet, open `styles.css` and add the following import line at the top:
|
||||||
|
|
||||||
<code-example path="forms/src/styles.1.css" linenums="false" header="src/styles.css">
|
<code-example path="forms/src/styles.1.css" header="src/styles.css"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
## Add powers with _*ngFor_
|
## Add powers with _*ngFor_
|
||||||
|
|
||||||
@ -274,9 +260,7 @@ a technique seen previously in the [Displaying Data](guide/displaying-data) page
|
|||||||
|
|
||||||
Add the following HTML *immediately below* the *Alter Ego* group:
|
Add the following HTML *immediately below* the *Alter Ego* group:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (powers)" region="powers">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (powers)" region="powers"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
This code repeats the `<option>` tag for each power in the list of powers.
|
This code repeats the `<option>` tag for each power in the list of powers.
|
||||||
The `pow` template input variable is a different power in each iteration;
|
The `pow` template input variable is a different power in each iteration;
|
||||||
@ -307,9 +291,7 @@ makes binding the form to the model easy.
|
|||||||
|
|
||||||
Find the `<input>` tag for *Name* and update it like this:
|
Find the `<input>` tag for *Name* and update it like this:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -325,9 +307,7 @@ You need one more addition to display the data. Declare
|
|||||||
a template variable for the form. Update the `<form>` tag with
|
a template variable for the form. Update the `<form>` tag with
|
||||||
`#heroForm="ngForm"` as follows:
|
`#heroForm="ngForm"` as follows:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
|
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
|
||||||
|
|
||||||
@ -391,9 +371,7 @@ Then you can confirm that two-way data binding works *for the entire hero model*
|
|||||||
|
|
||||||
After revision, the core of the form should look like this:
|
After revision, the core of the form should look like this:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -493,9 +471,7 @@ You can leverage those class names to change the appearance of the control.
|
|||||||
Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy`
|
Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy`
|
||||||
to the _Name_ `<input>` tag and use it to display the input's CSS classes.
|
to the _Name_ `<input>` tag and use it to display the input's CSS classes.
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now run the app and look at the _Name_ input box.
|
Now run the app and look at the _Name_ input box.
|
||||||
Follow these steps *precisely*:
|
Follow these steps *precisely*:
|
||||||
@ -535,15 +511,11 @@ on the left of the input box:
|
|||||||
You achieve this effect by adding these class definitions to a new `forms.css` file
|
You achieve this effect by adding these class definitions to a new `forms.css` file
|
||||||
that you add to the project as a sibling to `index.html`:
|
that you add to the project as a sibling to `index.html`:
|
||||||
|
|
||||||
<code-example path="forms/src/assets/forms.css" header="src/assets/forms.css">
|
<code-example path="forms/src/assets/forms.css" header="src/assets/forms.css"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Update the `<head>` of `index.html` to include this style sheet:
|
Update the `<head>` of `index.html` to include this style sheet:
|
||||||
|
|
||||||
<code-example path="forms/src/index.html" linenums="false" header="src/index.html (styles)" region="styles">
|
<code-example path="forms/src/index.html" header="src/index.html (styles)" region="styles"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
## Show and hide validation error messages
|
## Show and hide validation error messages
|
||||||
|
|
||||||
@ -564,9 +536,7 @@ To achieve this effect, extend the `<input>` tag with the following:
|
|||||||
|
|
||||||
Here's an example of an error message added to the _name_ input box:
|
Here's an example of an error message added to the _name_ input box:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You need a template reference variable to access the input box's Angular control from within the template.
|
You need a template reference variable to access the input box's Angular control from within the template.
|
||||||
Here you created a variable called `name` and gave it the value "ngModel".
|
Here you created a variable called `name` and gave it the value "ngModel".
|
||||||
@ -583,9 +553,7 @@ Here you created a variable called `name` and gave it the value "ngModel".
|
|||||||
You control visibility of the name error message by binding properties of the `name`
|
You control visibility of the name error message by binding properties of the `name`
|
||||||
control to the message `<div>` element's `hidden` property.
|
control to the message `<div>` element's `hidden` property.
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
In this example, you hide the message when the control is valid or pristine;
|
In this example, you hide the message when the control is valid or pristine;
|
||||||
"pristine" means the user hasn't changed the value since it was displayed in this form.
|
"pristine" means the user hasn't changed the value since it was displayed in this form.
|
||||||
@ -609,13 +577,9 @@ power to valid values.
|
|||||||
Now you'll add a new hero in this form.
|
Now you'll add a new hero in this form.
|
||||||
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
|
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" header="src/app/hero-form/hero-form.component.html (New Hero button)">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" header="src/app/hero-form/hero-form.component.html (New Hero button)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" header="src/app/hero-form/hero-form.component.ts (New Hero method)"></code-example>
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" header="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false">
|
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Run the application again, click the *New Hero* button, and the form clears.
|
Run the application again, click the *New Hero* button, and the form clears.
|
||||||
The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties.
|
The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties.
|
||||||
@ -634,9 +598,7 @@ Replacing the hero object *did not restore the pristine state* of the form contr
|
|||||||
You have to clear all of the flags imperatively, which you can do
|
You have to clear all of the flags imperatively, which you can do
|
||||||
by calling the form's `reset()` method after calling the `newHero()` method.
|
by calling the form's `reset()` method after calling the `newHero()` method.
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" header="src/app/hero-form/hero-form.component.html (Reset the form)">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" header="src/app/hero-form/hero-form.component.html (Reset the form)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now clicking "New Hero" resets both the form and its control flags.
|
Now clicking "New Hero" resets both the form and its control flags.
|
||||||
|
|
||||||
@ -651,9 +613,7 @@ A "form submit" is useless at the moment.
|
|||||||
To make it useful, bind the form's `ngSubmit` event property
|
To make it useful, bind the form's `ngSubmit` event property
|
||||||
to the hero form component's `onSubmit()` method:
|
to the hero form component's `onSubmit()` method:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You'd already defined a template reference variable,
|
You'd already defined a template reference variable,
|
||||||
`#heroForm`, and initialized it with the value "ngForm".
|
`#heroForm`, and initialized it with the value "ngForm".
|
||||||
@ -664,9 +624,7 @@ You'll bind the form's overall validity via
|
|||||||
the `heroForm` variable to the button's `disabled` property
|
the `heroForm` variable to the button's `disabled` property
|
||||||
using an event binding. Here's the code:
|
using an event binding. Here's the code:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
If you run the application now, you find that the button is enabled—although
|
If you run the application now, you find that the button is enabled—although
|
||||||
it doesn't do anything useful yet.
|
it doesn't do anything useful yet.
|
||||||
@ -703,17 +661,13 @@ hide the data entry area and display something else.
|
|||||||
Wrap the form in a `<div>` and bind
|
Wrap the form in a `<div>` and bind
|
||||||
its `hidden` property to the `HeroFormComponent.submitted` property.
|
its `hidden` property to the `HeroFormComponent.submitted` property.
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The main form is visible from the start because the
|
The main form is visible from the start because the
|
||||||
`submitted` property is false until you submit the form,
|
`submitted` property is false until you submit the form,
|
||||||
as this fragment from the `HeroFormComponent` shows:
|
as this fragment from the `HeroFormComponent` shows:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted">
|
<code-example path="forms/src/app/hero-form/hero-form.component.ts" header="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
When you click the *Submit* button, the `submitted` flag becomes true and the form disappears
|
When you click the *Submit* button, the `submitted` flag becomes true and the form disappears
|
||||||
as planned.
|
as planned.
|
||||||
@ -721,9 +675,7 @@ as planned.
|
|||||||
Now the app needs to show something else while the form is in the submitted state.
|
Now the app needs to show something else while the form is in the submitted state.
|
||||||
Add the following HTML below the `<div>` wrapper you just wrote:
|
Add the following HTML below the `<div>` wrapper you just wrote:
|
||||||
|
|
||||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted">
|
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
There's the hero again, displayed read-only with interpolation bindings.
|
There's the hero again, displayed read-only with interpolation bindings.
|
||||||
This `<div>` appears only while the component is in the submitted state.
|
This `<div>` appears only while the component is in the submitted state.
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
# Frequently Used Modules
|
# Frequently Used Modules
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
|
|
||||||
A basic understanding of [Bootstrapping](guide/bootstrapping).
|
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
An Angular app needs at least one module that serves as the root module.
|
An Angular app needs at least one module that serves as the root module.
|
||||||
As you add features to your app, you can add them in modules.
|
As you add features to your app, you can add them in modules.
|
||||||
The following are frequently used Angular modules with examples
|
The following are frequently used Angular modules with examples
|
||||||
|
@ -362,7 +362,7 @@ Compare to [custom element](#custom-element).
|
|||||||
|
|
||||||
## entry point
|
## entry point
|
||||||
|
|
||||||
A JavaScript module(#module) that is intended to be imported by a user of [an
|
A [JavaScript module](#module) that is intended to be imported by a user of [an
|
||||||
npm package](guide/npm-packages). An entry-point module typically re-exports
|
npm package](guide/npm-packages). An entry-point module typically re-exports
|
||||||
symbols from other internal modules. A package can contain multiple
|
symbols from other internal modules. A package can contain multiple
|
||||||
entry points. For example, the `@angular/core` package has two entry-point
|
entry points. For example, the `@angular/core` package has two entry-point
|
||||||
@ -454,10 +454,9 @@ A form of property [data binding](#data-binding) in which a [template expression
|
|||||||
That text can be concatenated with neighboring text before it is assigned to an element property
|
That text can be concatenated with neighboring text before it is assigned to an element property
|
||||||
or displayed between element tags, as in this example.
|
or displayed between element tags, as in this example.
|
||||||
|
|
||||||
<code-example language="html" escape="html">
|
```html
|
||||||
<label>My current hero is {{hero.name}}</label>
|
<label>My current hero is {{hero.name}}</label>
|
||||||
|
```
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax).
|
Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax).
|
||||||
@ -749,7 +748,7 @@ For more information, see [Schematics](guide/schematics) and [Integrating Librar
|
|||||||
Schematics come with their own command-line tool.
|
Schematics come with their own command-line tool.
|
||||||
Using Node 6.9 or above, install the Schematics CLI globally:
|
Using Node 6.9 or above, install the Schematics CLI globally:
|
||||||
|
|
||||||
<code-example format="." language="bash">
|
<code-example language="bash">
|
||||||
npm install -g @angular-devkit/schematics-cli
|
npm install -g @angular-devkit/schematics-cli
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
@ -764,7 +763,7 @@ NgModules are delivered within scoped packages whose names begin with the Angula
|
|||||||
|
|
||||||
Import a scoped package in the same way that you import a normal package.
|
Import a scoped package in the same way that you import a normal package.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/app.component.ts" linenums="false" header="architecture/src/app/app.component.ts (import)" region="import">
|
<code-example path="architecture/src/app/app.component.ts" header="architecture/src/app/app.component.ts (import)" region="import">
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ When an injectable class provides its own service to the `root` injector, the se
|
|||||||
|
|
||||||
The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class.
|
The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/heroes.service.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/heroes.service.ts"></code-example>
|
||||||
|
|
||||||
This configuration tells Angular that the app's root injector is responsible for creating an
|
This configuration tells Angular that the app's root injector is responsible for creating an
|
||||||
instance of `HeroService` by invoking its constructor,
|
instance of `HeroService` by invoking its constructor,
|
||||||
@ -92,7 +92,7 @@ Instead of specifying the `root` injector, you can set `providedIn` to a specifi
|
|||||||
For example, in the following excerpt, the `@Injectable()` decorator configures a provider
|
For example, in the following excerpt, the `@Injectable()` decorator configures a provider
|
||||||
that is available in any injector that includes the `HeroModule`.
|
that is available in any injector that includes the `HeroModule`.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="src/app/heroes/hero.service.ts" linenums="false"> </code-example>
|
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="src/app/heroes/hero.service.ts"></code-example>
|
||||||
|
|
||||||
This is generally no different from configuring the injector of the NgModule itself,
|
This is generally no different from configuring the injector of the NgModule itself,
|
||||||
except that the service is tree-shakable if the NgModule doesn't use it.
|
except that the service is tree-shakable if the NgModule doesn't use it.
|
||||||
@ -117,9 +117,7 @@ Here is an example of the case where the component router configuration includes
|
|||||||
a non-default [location strategy](guide/router#location-strategy) by listing its provider
|
a non-default [location strategy](guide/router#location-strategy) by listing its provider
|
||||||
in the `providers` list of the `AppModule`.
|
in the `providers` list of the `AppModule`.
|
||||||
|
|
||||||
<code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)" linenums="false">
|
<code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
{@a register-providers-component}
|
{@a register-providers-component}
|
||||||
@ -132,8 +130,7 @@ by configuring the provider at the component level using the `@Component` metada
|
|||||||
|
|
||||||
The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances.
|
The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances.
|
||||||
|
|
||||||
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" linenums="false">
|
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
### Element injectors
|
### Element injectors
|
||||||
|
|
||||||
@ -207,9 +204,7 @@ that would make the `VillainsService` available everywhere in the application, i
|
|||||||
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" header="src/app/villains-list.component.ts (metadata)" region="metadata">
|
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" header="src/app/villains-list.component.ts (metadata)" region="metadata"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
|
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
|
||||||
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
||||||
@ -273,9 +268,7 @@ Every component would share the same service instance, and each component would
|
|||||||
To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
|
To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" header="src/app/hero-tax-return.component.ts (providers)" region="providers">
|
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header="src/app/hero-tax-return.component.ts (providers)" region="providers"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
|
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
|
||||||
Recall that every component _instance_ has its own injector.
|
Recall that every component _instance_ has its own injector.
|
||||||
|
@ -28,7 +28,7 @@ Most apps do so in the root `AppModule`.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/app.module.ts"
|
path="http/src/app/app.module.ts"
|
||||||
region="sketch"
|
region="sketch"
|
||||||
header="app/app.module.ts (excerpt)" linenums="false">
|
header="app/app.module.ts (excerpt)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient`
|
Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient`
|
||||||
@ -37,7 +37,7 @@ into an application class as shown in the following `ConfigService` example.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="proto"
|
region="proto"
|
||||||
header="app/config/config.service.ts (excerpt)" linenums="false">
|
header="app/config/config.service.ts (excerpt)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
## Getting JSON data
|
## Getting JSON data
|
||||||
@ -48,7 +48,7 @@ that specifies resource URLs.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/assets/config.json"
|
path="http/src/assets/config.json"
|
||||||
header="assets/config.json" linenums="false">
|
header="assets/config.json">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
|
The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
|
||||||
@ -56,7 +56,7 @@ The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="getConfig_1"
|
region="getConfig_1"
|
||||||
header="app/config/config.service.ts (getConfig v.1)" linenums="false">
|
header="app/config/config.service.ts (getConfig v.1)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
A component, such as `ConfigComponent`, injects the `ConfigService` and calls
|
A component, such as `ConfigComponent`, injects the `ConfigService` and calls
|
||||||
@ -65,7 +65,7 @@ the `getConfig` service method.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.component.ts"
|
path="http/src/app/config/config.component.ts"
|
||||||
region="v1"
|
region="v1"
|
||||||
header="app/config/config.component.ts (showConfig v.1)" linenums="false">
|
header="app/config/config.component.ts (showConfig v.1)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Because the service method returns an `Observable` of configuration data,
|
Because the service method returns an `Observable` of configuration data,
|
||||||
@ -95,7 +95,7 @@ The subscribe callback above requires bracket notation to extract the data value
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.component.ts"
|
path="http/src/app/config/config.component.ts"
|
||||||
region="v1_callback" linenums="false">
|
region="v1_callback">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
You can't write `data.heroesUrl` because TypeScript correctly complains that the `data` object from the service does not have a `heroesUrl` property.
|
You can't write `data.heroesUrl` because TypeScript correctly complains that the `data` object from the service does not have a `heroesUrl` property.
|
||||||
@ -108,7 +108,7 @@ First, define an interface with the correct shape:
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="config-interface" linenums="false">
|
region="config-interface">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Then, specify that interface as the `HttpClient.get()` call's type parameter in the service:
|
Then, specify that interface as the `HttpClient.get()` call's type parameter in the service:
|
||||||
@ -116,7 +116,7 @@ Then, specify that interface as the `HttpClient.get()` call's type parameter in
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="getConfig_2"
|
region="getConfig_2"
|
||||||
header="app/config/config.service.ts (getConfig v.2)" linenums="false">
|
header="app/config/config.service.ts (getConfig v.2)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The callback in the updated component method receives a typed data object, which is
|
The callback in the updated component method receives a typed data object, which is
|
||||||
@ -125,7 +125,7 @@ easier and safer to consume:
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.component.ts"
|
path="http/src/app/config/config.component.ts"
|
||||||
region="v2"
|
region="v2"
|
||||||
header="app/config/config.component.ts (showConfig v.2)" linenums="false">
|
header="app/config/config.component.ts (showConfig v.2)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### Reading the full response
|
### Reading the full response
|
||||||
@ -136,7 +136,7 @@ Tell `HttpClient` that you want the full response with the `observe` option:
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="getConfigResponse" linenums="false">
|
region="getConfigResponse">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Now `HttpClient.get()` returns an `Observable` of typed `HttpResponse` rather than just the JSON data.
|
Now `HttpClient.get()` returns an `Observable` of typed `HttpResponse` rather than just the JSON data.
|
||||||
@ -147,7 +147,7 @@ The component's `showConfigResponse()` method displays the response headers as w
|
|||||||
path="http/src/app/config/config.component.ts"
|
path="http/src/app/config/config.component.ts"
|
||||||
region="showConfigResponse"
|
region="showConfigResponse"
|
||||||
header="app/config/config.component.ts (showConfigResponse)"
|
header="app/config/config.component.ts (showConfigResponse)"
|
||||||
linenums="false">
|
>
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
As you can see, the response object has a `body` property of the correct type.
|
As you can see, the response object has a `body` property of the correct type.
|
||||||
@ -162,7 +162,7 @@ You _could_ handle in the component by adding a second callback to the `.subscri
|
|||||||
path="http/src/app/config/config.component.ts"
|
path="http/src/app/config/config.component.ts"
|
||||||
region="v3"
|
region="v3"
|
||||||
header="app/config/config.component.ts (showConfig v.3 with error handling)"
|
header="app/config/config.component.ts (showConfig v.3 with error handling)"
|
||||||
linenums="false">
|
>
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
It's certainly a good idea to give the user some kind of feedback when data access fails.
|
It's certainly a good idea to give the user some kind of feedback when data access fails.
|
||||||
@ -188,7 +188,7 @@ You might first devise an error handler like this one:
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="handleError"
|
region="handleError"
|
||||||
header="app/config/config.service.ts (handleError)" linenums="false">
|
header="app/config/config.service.ts (handleError)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message.
|
Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message.
|
||||||
@ -201,7 +201,7 @@ and _pipe them through_ to the error handler.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="getConfig_3"
|
region="getConfig_3"
|
||||||
header="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false">
|
header="app/config/config.service.ts (getConfig v.3 with error handler)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### `retry()`
|
### `retry()`
|
||||||
@ -218,7 +218,7 @@ _Pipe_ it onto the `HttpClient` method result just before the error handler.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="getConfig"
|
region="getConfig"
|
||||||
header="app/config/config.service.ts (getConfig with retry)" linenums="false">
|
header="app/config/config.service.ts (getConfig with retry)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
{@a rxjs}
|
{@a rxjs}
|
||||||
@ -239,7 +239,7 @@ If you're following along with these code snippets, note that you must import th
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/config/config.service.ts"
|
path="http/src/app/config/config.service.ts"
|
||||||
region="rxjs-imports"
|
region="rxjs-imports"
|
||||||
header="app/config/config.service.ts (RxJS imports)" linenums="false">
|
header="app/config/config.service.ts (RxJS imports)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
## Requesting non-JSON data
|
## Requesting non-JSON data
|
||||||
@ -252,7 +252,7 @@ as an `Observable<string>`.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/downloader/downloader.service.ts"
|
path="http/src/app/downloader/downloader.service.ts"
|
||||||
region="getTextFile"
|
region="getTextFile"
|
||||||
header="app/downloader/downloader.service.ts (getTextFile)" linenums="false">
|
header="app/downloader/downloader.service.ts (getTextFile)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
`HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option.
|
`HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option.
|
||||||
@ -264,7 +264,7 @@ A `download()` method in the `DownloaderComponent` initiates the request by subs
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/downloader/downloader.component.ts"
|
path="http/src/app/downloader/downloader.component.ts"
|
||||||
region="download"
|
region="download"
|
||||||
header="app/downloader/downloader.component.ts (download)" linenums="false">
|
header="app/downloader/downloader.component.ts (download)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
## Sending data to the server
|
## Sending data to the server
|
||||||
@ -289,7 +289,7 @@ to every `HttpClient` save method.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="http-options"
|
region="http-options"
|
||||||
header="app/heroes/heroes.service.ts (httpOptions)" linenums="false">
|
header="app/heroes/heroes.service.ts (httpOptions)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### Making a POST request
|
### Making a POST request
|
||||||
@ -300,7 +300,7 @@ In the following example, the `HeroesService` posts when adding a hero to the da
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="addHero"
|
region="addHero"
|
||||||
header="app/heroes/heroes.service.ts (addHero)" linenums="false">
|
header="app/heroes/heroes.service.ts (addHero)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `HttpClient.post()` method is similar to `get()` in that it has a type parameter
|
The `HttpClient.post()` method is similar to `get()` in that it has a type parameter
|
||||||
@ -320,7 +320,7 @@ the `Observable` returned by this service method.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.component.ts"
|
path="http/src/app/heroes/heroes.component.ts"
|
||||||
region="add-hero-subscribe"
|
region="add-hero-subscribe"
|
||||||
header="app/heroes/heroes.component.ts (addHero)" linenums="false">
|
header="app/heroes/heroes.component.ts (addHero)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
When the server responds successfully with the newly added hero, the component adds
|
When the server responds successfully with the newly added hero, the component adds
|
||||||
@ -334,7 +334,7 @@ in the request URL.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="deleteHero"
|
region="deleteHero"
|
||||||
header="app/heroes/heroes.service.ts (deleteHero)" linenums="false">
|
header="app/heroes/heroes.service.ts (deleteHero)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `HeroesComponent` initiates the actual DELETE operation by subscribing to
|
The `HeroesComponent` initiates the actual DELETE operation by subscribing to
|
||||||
@ -343,7 +343,7 @@ the `Observable` returned by this service method.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.component.ts"
|
path="http/src/app/heroes/heroes.component.ts"
|
||||||
region="delete-hero-subscribe"
|
region="delete-hero-subscribe"
|
||||||
header="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
|
header="app/heroes/heroes.component.ts (deleteHero)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
|
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
|
||||||
@ -357,7 +357,7 @@ You must call _subscribe()_ or nothing happens. Just calling `HeroesService.dele
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.component.ts"
|
path="http/src/app/heroes/heroes.component.ts"
|
||||||
region="delete-hero-no-subscribe" linenums="false">
|
region="delete-hero-no-subscribe">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
{@a always-subscribe}
|
{@a always-subscribe}
|
||||||
@ -403,7 +403,7 @@ The following `HeroesService` example is just like the POST example.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="updateHero"
|
region="updateHero"
|
||||||
header="app/heroes/heroes.service.ts (updateHero)" linenums="false">
|
header="app/heroes/heroes.service.ts (updateHero)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
|
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
|
||||||
@ -435,7 +435,7 @@ before making the next request.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="update-headers" linenums="false">
|
region="update-headers">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
#### URL Parameters
|
#### URL Parameters
|
||||||
@ -445,7 +445,7 @@ Here is a `searchHeroes` method that queries for heroes whose names contain the
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/heroes/heroes.service.ts"
|
path="http/src/app/heroes/heroes.service.ts"
|
||||||
region="searchHeroes" linenums="false">
|
region="searchHeroes">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
||||||
@ -543,8 +543,7 @@ To implement an interceptor, declare a class that implements the `intercept()` m
|
|||||||
Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it:
|
Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it:
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/noop-interceptor.ts"
|
path="http/src/app/http-interceptors/noop-interceptor.ts"
|
||||||
header="app/http-interceptors/noop-interceptor.ts"
|
header="app/http-interceptors/noop-interceptor.ts">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `intercept` method transforms a request into an `Observable` that eventually returns the HTTP response.
|
The `intercept` method transforms a request into an `Observable` that eventually returns the HTTP response.
|
||||||
@ -590,7 +589,7 @@ write the `NoopInterceptor` provider like this:
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/index.ts"
|
path="http/src/app/http-interceptors/index.ts"
|
||||||
region="noop-provider" linenums="false">
|
region="noop-provider">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Note the `multi: true` option.
|
Note the `multi: true` option.
|
||||||
@ -608,7 +607,7 @@ Consider creating a "barrel" file that gathers all the interceptor providers int
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/index.ts"
|
path="http/src/app/http-interceptors/index.ts"
|
||||||
region="interceptor-providers"
|
region="interceptor-providers"
|
||||||
header="app/http-interceptors/index.ts" linenums="false">
|
header="app/http-interceptors/index.ts">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Then import and add it to the `AppModule` _providers array_ like this:
|
Then import and add it to the `AppModule` _providers array_ like this:
|
||||||
@ -616,7 +615,7 @@ Then import and add it to the `AppModule` _providers array_ like this:
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/app.module.ts"
|
path="http/src/app/app.module.ts"
|
||||||
region="interceptor-providers"
|
region="interceptor-providers"
|
||||||
header="app/app.module.ts (interceptor providers)" linenums="false">
|
header="app/app.module.ts (interceptor providers)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
As you create new interceptors, add them to the `httpInterceptorProviders` array and
|
As you create new interceptors, add them to the `httpInterceptorProviders` array and
|
||||||
@ -672,7 +671,7 @@ You can clone and modify the request in a single step as in this example.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/ensure-https-interceptor.ts"
|
path="http/src/app/http-interceptors/ensure-https-interceptor.ts"
|
||||||
region="excerpt"
|
region="excerpt"
|
||||||
header="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false">
|
header="app/http-interceptors/ensure-https-interceptor.ts (excerpt)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others.
|
The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others.
|
||||||
@ -692,7 +691,7 @@ If you must mutate the request body, copy it first, change the copy,
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/trim-name-interceptor.ts"
|
path="http/src/app/http-interceptors/trim-name-interceptor.ts"
|
||||||
region="excerpt"
|
region="excerpt"
|
||||||
header="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false">
|
header="app/http-interceptors/trim-name-interceptor.ts (excerpt)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
##### Clearing the request body
|
##### Clearing the request body
|
||||||
@ -768,7 +767,7 @@ The `CachingInterceptor` demonstrates this approach.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/http-interceptors/caching-interceptor.ts"
|
path="http/src/app/http-interceptors/caching-interceptor.ts"
|
||||||
region="v1"
|
region="v1"
|
||||||
header="app/http-interceptors/caching-interceptor.ts)" linenums="false">
|
header="app/http-interceptors/caching-interceptor.ts)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `isCachable()` function determines if the request is cachable.
|
The `isCachable()` function determines if the request is cachable.
|
||||||
@ -876,7 +875,7 @@ returns an `Observable` of `HttpEvents`, the same events processed by intercepto
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/uploader/uploader.service.ts"
|
path="http/src/app/uploader/uploader.service.ts"
|
||||||
region="upload-body"
|
region="upload-body"
|
||||||
header="app/uploader/uploader.service.ts (upload body)" linenums="false">
|
header="app/uploader/uploader.service.ts (upload body)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The `getEventMessage` method interprets each type of `HttpEvent` in the event stream.
|
The `getEventMessage` method interprets each type of `HttpEvent` in the event stream.
|
||||||
@ -884,7 +883,7 @@ The `getEventMessage` method interprets each type of `HttpEvent` in the event st
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/uploader/uploader.service.ts"
|
path="http/src/app/uploader/uploader.service.ts"
|
||||||
region="getEventMessage"
|
region="getEventMessage"
|
||||||
header="app/uploader/uploader.service.ts (getEventMessage)" linenums="false">
|
header="app/uploader/uploader.service.ts (getEventMessage)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
@ -925,8 +924,7 @@ use `HttpClientXsrfModule.withOptions()` to override the defaults.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/app/app.module.ts"
|
path="http/src/app/app.module.ts"
|
||||||
region="xsrf"
|
region="xsrf">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
## Testing HTTP requests
|
## Testing HTTP requests
|
||||||
@ -967,7 +965,7 @@ along with the other symbols your tests require.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="imports"
|
region="imports"
|
||||||
header="app/testing/http-client.spec.ts (imports)" linenums="false">
|
header="app/testing/http-client.spec.ts (imports)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Then add the `HttpClientTestingModule` to the `TestBed` and continue with
|
Then add the `HttpClientTestingModule` to the `TestBed` and continue with
|
||||||
@ -976,7 +974,7 @@ the setup of the _service-under-test_.
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="setup"
|
region="setup"
|
||||||
header="app/testing/http-client.spec.ts(setup)" linenums="false">
|
header="app/testing/http-client.spec.ts(setup)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Now requests made in the course of your tests will hit the testing backend instead of the normal backend.
|
Now requests made in the course of your tests will hit the testing backend instead of the normal backend.
|
||||||
@ -991,15 +989,14 @@ Now you can write a test that expects a GET Request to occur and provides a mock
|
|||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="get-test"
|
region="get-test"
|
||||||
header="app/testing/http-client.spec.ts(httpClient.get)" linenums="false">
|
header="app/testing/http-client.spec.ts(httpClient.get)">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
|
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
|
||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="afterEach"
|
region="afterEach">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
#### Custom request expectations
|
#### Custom request expectations
|
||||||
@ -1009,8 +1006,7 @@ For example, you could look for an outgoing request that has an authorization he
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="predicate"
|
region="predicate">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
As with the previous `expectOne()`,
|
As with the previous `expectOne()`,
|
||||||
@ -1025,8 +1021,7 @@ you are responsible for flushing and verifying them.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="multi-request"
|
region="multi-request">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### Testing for errors
|
### Testing for errors
|
||||||
@ -1037,14 +1032,12 @@ Call `request.flush()` with an error message, as seen in the following example.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="404"
|
region="404">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Alternatively, you can call `request.error()` with an `ErrorEvent`.
|
Alternatively, you can call `request.error()` with an `ErrorEvent`.
|
||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="network-error"
|
region="network-error">
|
||||||
linenums="false">
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
@ -85,8 +85,7 @@ The CLI imports the locale data for you when you use the parameter `--configurat
|
|||||||
|
|
||||||
If you want to import locale data for other languages, you can do it manually:
|
If you want to import locale data for other languages, you can do it manually:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" header="src/app/app.module.ts" linenums="false">
|
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The first parameter is an object containing the locale data imported from `@angular/common/locales`.
|
The first parameter is an object containing the locale data imported from `@angular/common/locales`.
|
||||||
By default, the imported locale data is registered with the locale id that is defined in the Angular
|
By default, the imported locale data is registered with the locale id that is defined in the Angular
|
||||||
@ -100,8 +99,7 @@ The files in `@angular/common/locales` contain most of the locale data that you
|
|||||||
need, but some advanced formatting options might only be available in the extra dataset that you can
|
need, but some advanced formatting options might only be available in the extra dataset that you can
|
||||||
import from `@angular/common/locales/extra`. An error message informs you when this is the case.
|
import from `@angular/common/locales/extra`. An error message informs you when this is the case.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" header="src/app/app.module.ts" linenums="false">
|
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
@ -146,13 +144,11 @@ text is to be translated.
|
|||||||
|
|
||||||
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
|
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.component.html" region="greeting" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/doc-files/app.component.html" region="greeting" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
|
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
@ -171,8 +167,7 @@ To translate a text message accurately, the translator may need additional infor
|
|||||||
You can add a description of the text message as the value of the `i18n` attribute, as shown in the
|
You can add a description of the text message as the value of the `i18n` attribute, as shown in the
|
||||||
example below:
|
example below:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The translator may also need to know the meaning or intent of the text message within this particular
|
The translator may also need to know the meaning or intent of the text message within this particular
|
||||||
app context.
|
app context.
|
||||||
@ -180,8 +175,7 @@ app context.
|
|||||||
You add context by beginning the `i18n` attribute value with the _meaning_ and
|
You add context by beginning the `i18n` attribute value with the _meaning_ and
|
||||||
separating it from the _description_ with the `|` character: `<meaning>|<description>`
|
separating it from the _description_ with the `|` character: `<meaning>|<description>`
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
All occurrences of a text message that have the same meaning will have the same translation.
|
All occurrences of a text message that have the same meaning will have the same translation.
|
||||||
A text message that is associated with different meanings can have different translations.
|
A text message that is associated with different meanings can have different translations.
|
||||||
@ -199,8 +193,7 @@ text messages with different descriptions (not different meanings), then they ar
|
|||||||
The angular i18n extractor tool generates a file with a translation unit entry for each `i18n`
|
The angular i18n extractor tool generates a file with a translation unit entry for each `i18n`
|
||||||
attribute in a template. By default, it assigns each translation unit a unique id such as this one:
|
attribute in a template. By default, it assigns each translation unit a unique id such as this one:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
When you change the translatable text, the extractor tool generates a new id for that translation unit.
|
When you change the translatable text, the extractor tool generates a new id for that translation unit.
|
||||||
You must then update the translation file with the new id.
|
You must then update the translation file with the new id.
|
||||||
@ -208,14 +201,12 @@ You must then update the translation file with the new id.
|
|||||||
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
|
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
|
||||||
The example below defines the custom id `introductionHeader`:
|
The example below defines the custom id `introductionHeader`:
|
||||||
|
|
||||||
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' header='app/app.component.html' linenums="false">
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' header='app/app.component.html'></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
When you specify a custom id, the extractor tool and compiler generate a translation unit with that
|
When you specify a custom id, the extractor tool and compiler generate a translation unit with that
|
||||||
custom id.
|
custom id.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The custom id is persistent. The extractor tool does not change it when the translatable text changes.
|
The custom id is persistent. The extractor tool does not change it when the translatable text changes.
|
||||||
Therefore, you do not need to update the translation. This approach makes maintenance easier.
|
Therefore, you do not need to update the translation. This approach makes maintenance easier.
|
||||||
@ -226,13 +217,11 @@ You can use a custom id in combination with a description by including both in t
|
|||||||
`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed
|
`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed
|
||||||
by the custom `id`:
|
by the custom `id`:
|
||||||
|
|
||||||
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' header='app/app.component.html' linenums="false">
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' header='app/app.component.html'></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You also can add a meaning, as shown in this example:
|
You also can add a meaning, as shown in this example:
|
||||||
|
|
||||||
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' header='app/app.component.html' linenums="false">
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' header='app/app.component.html'></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
#### Define unique custom ids
|
#### Define unique custom ids
|
||||||
|
|
||||||
@ -275,8 +264,7 @@ However, if you don't want to create a new DOM element merely to facilitate tran
|
|||||||
you can wrap the text in an `<ng-container>` element.
|
you can wrap the text in an `<ng-container>` element.
|
||||||
The `<ng-container>` is transformed into an html comment:
|
The `<ng-container>` is transformed into an html comment:
|
||||||
|
|
||||||
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a translate-attributes}
|
{@a translate-attributes}
|
||||||
### Translate attributes
|
### Translate attributes
|
||||||
@ -284,15 +272,13 @@ The `<ng-container>` is transformed into an html comment:
|
|||||||
Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag.
|
Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag.
|
||||||
For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated.
|
For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
To mark an attribute for translation, add an attribute in the form of `i18n-x`,
|
To mark an attribute for translation, add an attribute in the form of `i18n-x`,
|
||||||
where `x` is the name of the attribute to translate. The following example shows how to mark the
|
where `x` is the name of the attribute to translate. The following example shows how to mark the
|
||||||
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
|
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
|
||||||
|
|
||||||
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
This technique works for any attribute of any element.
|
This technique works for any attribute of any element.
|
||||||
|
|
||||||
@ -316,8 +302,7 @@ Other languages might express the cardinality differently.
|
|||||||
The example below shows how to use a `plural` ICU expression to display one of those three options
|
The example below shows how to use a `plural` ICU expression to display one of those three options
|
||||||
based on when the update occurred:
|
based on when the update occurred:
|
||||||
|
|
||||||
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
* The first parameter is the key. It is bound to the component property (`minutes`), which determines
|
* The first parameter is the key. It is bound to the component property (`minutes`), which determines
|
||||||
the number of minutes.
|
the number of minutes.
|
||||||
@ -372,8 +357,7 @@ The following format message in the component template binds to the component's
|
|||||||
which outputs one of the following string values: "male", "female" or "other".
|
which outputs one of the following string values: "male", "female" or "other".
|
||||||
The message maps those values to the appropriate translations:
|
The message maps those values to the appropriate translations:
|
||||||
|
|
||||||
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a nesting-ICUS}
|
{@a nesting-ICUS}
|
||||||
### Nesting plural and select ICU expressions
|
### Nesting plural and select ICU expressions
|
||||||
@ -518,8 +502,7 @@ This sample file is easy to translate without a special editor or knowledge of F
|
|||||||
|
|
||||||
1. Open `messages.fr.xlf` and find the first `<trans-unit>` section:
|
1. Open `messages.fr.xlf` and find the first `<trans-unit>` section:
|
||||||
|
|
||||||
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the
|
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the
|
||||||
`i18n` attribute earlier in this guide.
|
`i18n` attribute earlier in this guide.
|
||||||
@ -534,13 +517,11 @@ This sample file is easy to translate without a special editor or knowledge of F
|
|||||||
and context provided by the source, description, and meaning elements to guide your selection of
|
and context provided by the source, description, and meaning elements to guide your selection of
|
||||||
the appropriate French translation.
|
the appropriate French translation.
|
||||||
|
|
||||||
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" header="src/locale/messages.fr.xlf (<trans-unit>, after translation)" linenums="false">
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" header="src/locale/messages.fr.xlf (<trans-unit>, after translation)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
3. Translate the other text nodes the same way:
|
3. Translate the other text nodes the same way:
|
||||||
|
|
||||||
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
<div class="alert is-important">
|
<div class="alert is-important">
|
||||||
|
|
||||||
@ -566,8 +547,7 @@ must be just below the translation unit for the logo.
|
|||||||
|
|
||||||
To translate a `plural`, translate its ICU format match values:
|
To translate a `plural`, translate its ICU format match values:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
You can add or remove plural cases, with each language having its own cardinality. (See
|
You can add or remove plural cases, with each language having its own cardinality. (See
|
||||||
[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).)
|
[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).)
|
||||||
@ -577,8 +557,7 @@ You can add or remove plural cases, with each language having its own cardinalit
|
|||||||
|
|
||||||
Below is the content of our example `select` ICU expression in the component template:
|
Below is the content of our example `select` ICU expression in the component template:
|
||||||
|
|
||||||
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
|
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The extraction tool broke that into two translation units because ICU expressions are extracted
|
The extraction tool broke that into two translation units because ICU expressions are extracted
|
||||||
separately.
|
separately.
|
||||||
@ -588,19 +567,16 @@ In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `
|
|||||||
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
|
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
|
||||||
the placeholder, the ICU expression will not be present in your translated app.
|
the placeholder, the ICU expression will not be present in your translated app.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The second translation unit, immediately below the first one, contains the `select` message.
|
The second translation unit, immediately below the first one, contains the `select` message.
|
||||||
Translate that as well.
|
Translate that as well.
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Here they are together, after translation:
|
Here they are together, after translation:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
{@a translate-nested}
|
{@a translate-nested}
|
||||||
### Translate a nested expression
|
### Translate a nested expression
|
||||||
@ -608,18 +584,15 @@ Here they are together, after translation:
|
|||||||
A nested expression is similar to the previous examples. As in the previous example, there are
|
A nested expression is similar to the previous examples. As in the previous example, there are
|
||||||
two translation units. The first one contains the text outside of the nested expression:
|
two translation units. The first one contains the text outside of the nested expression:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The second unit contains the complete nested expression:
|
The second unit contains the complete nested expression:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
And both together:
|
And both together:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" header="src/locale/messages.fr.xlf (<trans-unit>)"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The entire template translation is complete. The next section describes how to load that translation
|
The entire template translation is complete. The next section describes how to load that translation
|
||||||
into the app.
|
into the app.
|
||||||
@ -783,8 +756,7 @@ behavior of the compiler. You can use it to specify the translation providers:
|
|||||||
|
|
||||||
Then provide the `LOCALE_ID` in the main module:
|
Then provide the `LOCALE_ID` in the main module:
|
||||||
|
|
||||||
<code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
|
<code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts"></code-example>
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
{@a missing-translation}
|
{@a missing-translation}
|
||||||
@ -837,4 +809,4 @@ For example, if the French version of your application is served from https://my
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 to serve them from different subdirectories, read [this tutorial by Philippe Martin](https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358#.1xq4iy6fp).
|
For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 and NGINX to serve them from different subdirectories, read [this tutorial by Philippe Martin](https://dev.to/angular/deploying-an-i18n-angular-app-with-angular-cli-2fb9).
|
||||||
|
@ -1,23 +1,13 @@
|
|||||||
# Lazy Loading Feature Modules
|
# Lazy Loading Feature Modules
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
A basic understanding of the following:
|
|
||||||
* [Feature Modules](guide/feature-modules).
|
|
||||||
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
|
||||||
* [Frequently Used Modules](guide/frequent-ngmodules).
|
|
||||||
* [Types of Feature Modules](guide/module-types).
|
|
||||||
* [Routing and Navigation](guide/router).
|
|
||||||
|
|
||||||
For the final sample app with two lazy loaded modules that this page describes, see the
|
|
||||||
<live-example></live-example>.
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
## High level view
|
## High level view
|
||||||
|
|
||||||
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading—a design pattern that loads NgModules as needed. Lazy loading helps keep initial
|
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading—a design pattern that loads NgModules as needed. Lazy loading helps keep initial
|
||||||
bundle sizes smaller, which in turn helps decrease load times.
|
bundle sizes smaller, which in turn helps decrease load times.
|
||||||
|
|
||||||
|
For the final sample app with two lazy loaded modules that this page describes, see the
|
||||||
|
<live-example></live-example>.
|
||||||
|
|
||||||
There are three main steps to setting up a lazy loaded feature module:
|
There are three main steps to setting up a lazy loaded feature module:
|
||||||
|
|
||||||
1. Create the feature module.
|
1. Create the feature module.
|
||||||
@ -98,9 +88,7 @@ placeholder markup in `app.component.html` with a custom nav
|
|||||||
so you can easily navigate to your modules in the browser:
|
so you can easily navigate to your modules in the browser:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
|
<code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -138,9 +126,7 @@ Each feature module acts as a doorway via the router. In the `AppRoutingModule`,
|
|||||||
In `AppRoutingModule`, update the `routes` array with the following:
|
In `AppRoutingModule`, update the `routes` array with the following:
|
||||||
|
|
||||||
|
|
||||||
<code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" header="src/app/app-routing.module.ts" linenums="false">
|
<code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" header="src/app/app-routing.module.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a function that uses the browser's built-in `import('...')` syntax for dynamic imports. The import path is the relative path to the module.
|
The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a function that uses the browser's built-in `import('...')` syntax for dynamic imports. The import path is the relative path to the module.
|
||||||
@ -150,9 +136,7 @@ The import statements stay the same. The first two paths are the routes to the `
|
|||||||
Next, take a look at `customers.module.ts`. If you’re using the CLI and following the steps outlined in this page, you don’t have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`.
|
Next, take a look at `customers.module.ts`. If you’re using the CLI and following the steps outlined in this page, you don’t have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`.
|
||||||
|
|
||||||
|
|
||||||
<code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" header="src/app/customers/customers.module.ts" linenums="false">
|
<code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" header="src/app/customers/customers.module.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -163,18 +147,14 @@ The `customers.module.ts` file imports the `CustomersRoutingModule` and `Custome
|
|||||||
|
|
||||||
The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`.
|
The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`.
|
||||||
|
|
||||||
<code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" header="src/app/customers/customers-routing.module.ts" linenums="false">
|
<code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" header="src/app/customers/customers-routing.module.ts"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
Notice that the `path` is set to an empty string. This is because the path in `AppRoutingModule` is already set to `customers`, so this route in the `CustomersRoutingModule`, is already within the `customers` context. Every route in this routing module is a child route.
|
Notice that the `path` is set to an empty string. This is because the path in `AppRoutingModule` is already set to `customers`, so this route in the `CustomersRoutingModule`, is already within the `customers` context. Every route in this routing module is a child route.
|
||||||
|
|
||||||
Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`:
|
Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`:
|
||||||
|
|
||||||
<code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" header="src/app/orders/orders-routing.module.ts (excerpt)" linenums="false">
|
<code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" header="src/app/orders/orders-routing.module.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Now, if you view the app in the browser, the three buttons take you to each module.
|
Now, if you view the app in the browser, the three buttons take you to each module.
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ Each interface has a single hook method whose name is the interface name prefixe
|
|||||||
For example, the `OnInit` interface has a hook method named `ngOnInit()`
|
For example, the `OnInit` interface has a hook method named `ngOnInit()`
|
||||||
that Angular calls shortly after creating the component:
|
that Angular calls shortly after creating the component:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" header="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" header="peek-a-boo.component.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
No directive or component will implement all of the lifecycle hooks.
|
No directive or component will implement all of the lifecycle hooks.
|
||||||
Angular only calls a directive/component hook method *if it is defined*.
|
Angular only calls a directive/component hook method *if it is defined*.
|
||||||
@ -339,13 +339,13 @@ The heroes will never know they're being watched.
|
|||||||
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
|
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
|
||||||
that log messages to the parent via an injected `LoggerService`.
|
that log messages to the parent via an injected `LoggerService`.
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" header="src/app/spy.directive.ts" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" header="src/app/spy.directive.ts"></code-example>
|
||||||
|
|
||||||
You can apply the spy to any native or component element and it'll be initialized and destroyed
|
You can apply the spy to any native or component element and it'll be initialized and destroyed
|
||||||
at the same time as that element.
|
at the same time as that element.
|
||||||
Here it is attached to the repeated hero `<div>`:
|
Here it is attached to the repeated hero `<div>`:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" header="src/app/spy.component.html" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" header="src/app/spy.component.html"></code-example>
|
||||||
|
|
||||||
Each spy's birth and death marks the birth and death of the attached hero `<div>`
|
Each spy's birth and death marks the birth and death of the attached hero `<div>`
|
||||||
with an entry in the *Hook Log* as seen here:
|
with an entry in the *Hook Log* as seen here:
|
||||||
@ -425,7 +425,7 @@ You risk memory leaks if you neglect to do so.
|
|||||||
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
|
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
|
||||||
This example monitors the `OnChanges` hook.
|
This example monitors the `OnChanges` hook.
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" header="on-changes.component.ts (excerpt)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" header="on-changes.component.ts (excerpt)"></code-example>
|
||||||
|
|
||||||
The `ngOnChanges()` method takes an object that maps each changed property name to a
|
The `ngOnChanges()` method takes an object that maps each changed property name to a
|
||||||
[SimpleChange](api/core/SimpleChange) object holding the current and previous property values.
|
[SimpleChange](api/core/SimpleChange) object holding the current and previous property values.
|
||||||
@ -433,7 +433,7 @@ This hook iterates over the changed properties and logs them.
|
|||||||
|
|
||||||
The example component, `OnChangesComponent`, has two input properties: `hero` and `power`.
|
The example component, `OnChangesComponent`, has two input properties: `hero` and `power`.
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" header="src/app/on-changes.component.ts" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" header="src/app/on-changes.component.ts"></code-example>
|
||||||
|
|
||||||
The host `OnChangesParentComponent` binds to them like this:
|
The host `OnChangesParentComponent` binds to them like this:
|
||||||
|
|
||||||
@ -468,7 +468,7 @@ Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch
|
|||||||
|
|
||||||
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
|
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" header="DoCheckComponent (ngDoCheck)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" header="DoCheckComponent (ngDoCheck)"></code-example>
|
||||||
|
|
||||||
This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
|
This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
|
||||||
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
|
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
|
||||||
@ -497,25 +497,25 @@ The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` h
|
|||||||
|
|
||||||
Here's a child view that displays a hero's name in an `<input>`:
|
Here's a child view that displays a hero's name in an `<input>`:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" header="ChildComponent" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" header="ChildComponent"></code-example>
|
||||||
|
|
||||||
The `AfterViewComponent` displays this child view *within its template*:
|
The `AfterViewComponent` displays this child view *within its template*:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" header="AfterViewComponent (template)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" header="AfterViewComponent (template)"></code-example>
|
||||||
|
|
||||||
The following hooks take action based on changing values *within the child view*,
|
The following hooks take action based on changing values *within the child view*,
|
||||||
which can only be reached by querying for the child view via the property decorated with
|
which can only be reached by querying for the child view via the property decorated with
|
||||||
[@ViewChild](api/core/ViewChild).
|
[@ViewChild](api/core/ViewChild).
|
||||||
|
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" header="AfterViewComponent (class excerpts)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" header="AfterViewComponent (class excerpts)"></code-example>
|
||||||
|
|
||||||
{@a wait-a-tick}
|
{@a wait-a-tick}
|
||||||
|
|
||||||
### Abide by the unidirectional data flow rule
|
### Abide by the unidirectional data flow rule
|
||||||
The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
|
The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" header="AfterViewComponent (doSomething)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" header="AfterViewComponent (doSomething)"></code-example>
|
||||||
|
|
||||||
Why does the `doSomething()` method wait a tick before updating `comment`?
|
Why does the `doSomething()` method wait a tick before updating `comment`?
|
||||||
|
|
||||||
@ -559,7 +559,7 @@ Consider this variation on the [previous _AfterView_](guide/lifecycle-hooks#afte
|
|||||||
This time, instead of including the child view within the template, it imports the content from
|
This time, instead of including the child view within the template, it imports the content from
|
||||||
the `AfterContentComponent`'s parent. Here's the parent's template:
|
the `AfterContentComponent`'s parent. Here's the parent's template:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)"></code-example>
|
||||||
|
|
||||||
Notice that the `<app-child>` tag is tucked between the `<after-content>` tags.
|
Notice that the `<app-child>` tag is tucked between the `<after-content>` tags.
|
||||||
Never put content between a component's element tags *unless you intend to project that content
|
Never put content between a component's element tags *unless you intend to project that content
|
||||||
@ -567,7 +567,7 @@ into the component*.
|
|||||||
|
|
||||||
Now look at the component's template:
|
Now look at the component's template:
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" header="AfterContentComponent (template)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" header="AfterContentComponent (template)"></code-example>
|
||||||
|
|
||||||
The `<ng-content>` tag is a *placeholder* for the external content.
|
The `<ng-content>` tag is a *placeholder* for the external content.
|
||||||
It tells Angular where to insert that content.
|
It tells Angular where to insert that content.
|
||||||
@ -603,7 +603,7 @@ The following *AfterContent* hooks take action based on changing values in a *co
|
|||||||
which can only be reached by querying for them via the property decorated with
|
which can only be reached by querying for them via the property decorated with
|
||||||
[@ContentChild](api/core/ContentChild).
|
[@ContentChild](api/core/ContentChild).
|
||||||
|
|
||||||
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" header="AfterContentComponent (class excerpts)" linenums="false"></code-example>
|
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" header="AfterContentComponent (class excerpts)"></code-example>
|
||||||
|
|
||||||
{@a no-unidirectional-flow-worries}
|
{@a no-unidirectional-flow-worries}
|
||||||
|
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
# Types of Feature Modules
|
# Types of Feature Modules
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
|
|
||||||
A basic understanding of the following concepts:
|
|
||||||
* [Feature Modules](guide/feature-modules).
|
|
||||||
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
|
||||||
* [Frequently Used Modules](guide/frequent-ngmodules).
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
There are five general categories of feature modules which
|
There are five general categories of feature modules which
|
||||||
tend to fall into the following groups:
|
tend to fall into the following groups:
|
||||||
|
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
# NgModule API
|
# NgModule API
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
|
|
||||||
A basic understanding of the following concepts:
|
|
||||||
* [Bootstrapping](guide/bootstrapping).
|
|
||||||
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
## Purpose of `@NgModule`
|
|
||||||
|
|
||||||
At a high level, NgModules are a way to organize Angular apps
|
At a high level, NgModules are a way to organize Angular apps
|
||||||
and they accomplish this through the metadata in the `@NgModule`
|
and they accomplish this through the metadata in the `@NgModule`
|
||||||
decorator.
|
decorator.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user