Skip to content

Commit

Permalink
Merge pull request #143 from angular/main
Browse files Browse the repository at this point in the history
Create a new pull request by comparing changes across two branches.
  • Loading branch information
GulajavaMinistudio authored Nov 1, 2023
2 parents d3f1249 + de802f0 commit 3c48ca1
Show file tree
Hide file tree
Showing 208 changed files with 5,855 additions and 2,269 deletions.
1 change: 1 addition & 0 deletions .pullapprove.yml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ groups:
'aio/content/special-elements/**/{*,.*}',
'aio/content/blocks/**/{*,.*}',
'aio/content/guide/hydration.md',
'aio/content/guide/defer.md',
'aio/content/guide/signals.md',
'aio/content/guide/control_flow.md',
'aio/content/examples/injection-token/**/{*,.*}',
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con

Join the conversation and help the community.

- [Twitter][twitter]
- [X (formerly Twitter)][X (formerly Twitter)]
- [Discord][discord]
- [Gitter][gitter]
- [YouTube][youtube]
Expand Down Expand Up @@ -158,7 +158,7 @@ Join the conversation and help the community.
[node.js]: https://nodejs.org/
[npm]: https://www.npmjs.com/get-npm
[codeofconduct]: CODE_OF_CONDUCT.md
[twitter]: https://www.twitter.com/angular
[X (formerly Twitter)]: https://www.twitter.com/angular
[discord]: https://discord.gg/angular
[gitter]: https://gitter.im/angular/angular
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
Expand Down
1 change: 1 addition & 0 deletions aio/content/blocks/core/defer.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ Configures prefetching of the defer block used in the `@defer` parameters, but d
}
```

Learn more in the [defer loading guide](guide/defer).
47 changes: 46 additions & 1 deletion aio/content/blocks/core/for.md
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
Placeholder content
The `@for` block repeatedly renders content of a block for each item in a collection.

@syntax

```html
@for (item of items; track item.name) {
<li> {{ item.name }} </li>
} @empty {
<li> There are no items. </li>
}
```

@description

The `@for` block renders its content in response to changes in a collection. Collections can be any JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols), but there are performance advantages of using a regular `Array`.

You can optionally include an `@empty` section immediately after the `@for` block content. The content of the `@empty` block displays when there are no items.

<h3> track and objects identity </h3>

The value of the `track` expression determines a key used to associate array items with the views in the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM operations as items are added, removed or moved in a collection.

Loops over immutable data without `trackBy` as one of the most common causes for performance issues across Angular applications. Because of the potential for poor performance, the `track` expression is required for the `@for` loops. When in doubt, using `track $index` is a good default.

<h3> `$index` and other contextual variables </h3>

Inside `@for` contents, several implicit variables are always available:

| Variable | Meaning |
| -------- | ------- |
| `$count` | Number of items in a collection iterated over |
| `$index` | Index of the current row |
| `$first` | Whether the current row is the first row |
| `$last` | Whether the current row is the last row |
| `$even` | Whether the current row index is even |
| `$odd` | Whether the current row index is odd |

These variables are always available with these names, but can be aliased via a `let` segment:

```html
@for (item of items; track item.id; let idx = $index, e = $even) {
Item #{{ idx }}: {{ item.name }}
}
```

The aliasing is especially useful in case of using nested `@for` blocks where contextual variable names could collide.
21 changes: 17 additions & 4 deletions aio/content/blocks/core/if.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
Control flow block used to conditionally render content in the DOM.
The `@if` block conditionally displays its content when its condition expression is truthy.

@syntax

```html
@if ( <condition> ) {
<!-- conditional template fragment -->
@if (a > b) {
{{a}} is greater than {{b}}
} @else if (b > a) {
{{a}} is less than {{b}}
} @else {
{{a}} is equal to {{b}}
}
```

@description
This is the full description.

Content is added and removed from the DOM based on the evaluation of conditional expressions in the `@if` and `@else` blocks.

The built-in `@if` supports referencing of expression results to keep a solution for common coding patterns:

```html
@if (users$ | async; as users) {
{{ users.length }}
}
```
26 changes: 25 additions & 1 deletion aio/content/blocks/core/switch.md
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
Placeholder content
The `@switch` block is inspired by the JavaScript `switch` statement:

@syntax

```html
@switch (condition) {
@case (caseA) {
Case A.
}
@case (caseB) {
Case B.
}
@default {
Default case.
}
}
```

@description

The `@switch` blocks displays content selected by one of the cases matching against the conditional expression. The value of the conditional expression is compared to the case expression using the `===` operator.

The `@default` block is optional and can be omitted. If no `@case` matches the expression and there is no `@default` block, nothing is shown.

**`@switch` does not have fallthrough**, so you do not need an equivalent to a `break` or `return` statement.
39 changes: 16 additions & 23 deletions aio/content/examples/ssr/server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// #docplaster

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import {APP_BASE_HREF} from '@angular/common';
import {CommonEngine} from '@angular/ssr';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import {dirname, join, resolve} from 'node:path';
import {fileURLToPath} from 'node:url';

import bootstrap from './src/main.server';

// The Express app is exported so that it can be used by serverless Functions.
Expand All @@ -13,42 +14,34 @@ export function app(): express.Express {
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');
// #docregion CommonEngine
const commonEngine = new CommonEngine();
// #enddocregion CommonEngine

server.set('view engine', 'html');
server.set('views', browserDistFolder);

// #docregion data-request
// TODO: implement data requests securely
// Serve data from URLS that begin "/api/"
server.get('/api/**', (req, res) => {
res.status(404).send('data requests are not yet supported');
});
// #enddocregion data-request
// #docregion static
// Serve static files from /browser
server.get('*.*', express.static(browserDistFolder, {
maxAge: '1y'
}));
// #enddocregion static
server.get('*.*', express.static(browserDistFolder, {maxAge: '1y'}));

// #docregion navigation-request
// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
const {protocol, originalUrl, baseUrl, headers} = req;

commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{provide: APP_BASE_HREF, useValue: req.baseUrl}],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});
// #enddocregion navigation-request

Expand Down
37 changes: 14 additions & 23 deletions aio/content/examples/ssr/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
// #docplaster
import { importProvidersFrom } from '@angular/core';
import { provideProtractorTestingSupport } from '@angular/platform-browser';
import { provideClientHydration} from '@angular/platform-browser';
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withFetch } from '@angular/common/http';
import {provideHttpClient, withFetch} from '@angular/common/http';
import {ApplicationConfig, importProvidersFrom} from '@angular/core';
import {provideClientHydration, provideProtractorTestingSupport} from '@angular/platform-browser';
import {provideRouter} from '@angular/router';
import {HttpClientInMemoryWebApiModule} from 'angular-in-memory-web-api';

import { routes } from './app.routes';

import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
import {routes} from './app.routes';
import {InMemoryDataService} from './in-memory-data.service';

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
// TODO: Enable using Fetch API when disabling `HttpClientInMemoryWebApiModule`.
provideHttpClient(/* withFetch()*/ ),
provideClientHydration(),
provideProtractorTestingSupport(), // essential for e2e testing
// TODO: Enable using Fetch API when disabling `HttpClientInMemoryWebApiModule`.
provideHttpClient(/* withFetch()*/), provideClientHydration(),
provideProtractorTestingSupport(), // essential for e2e testing

// #docregion in-mem
// TODO: Remove from production apps
importProvidersFrom(
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
// and returns simulated server responses.
// Remove it when a real server is ready to receive requests.
HttpClientInMemoryWebApiModule.forRoot(
InMemoryDataService, { dataEncapsulation: false }
)
),
// #enddocregion in-mem
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
// and returns simulated server responses.
// Remove it when a real server is ready to receive requests.
HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, {dataEncapsulation: false})),
// ...
],
};
13 changes: 13 additions & 0 deletions aio/content/guide/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,19 @@ If you edit the proxy configuration file, you must relaunch the `ng serve` proce

</div>

<div class="alert is-important">

As of Node version 17, Node will not always resolve `http://localhost:<port>` to `http://127.0.0.1:<port>`
depending on each machine's configuration.

If you get an `ECONNREFUSED` error using a proxy targeting a `localhost` URL,
you can fix this issue by updating the target from `http://localhost:<port>` to `http://127.0.0.1:<port>`.

See [the http proxy middleware documentation](https://github.com/chimurai/http-proxy-middleware#nodejs-17-econnrefused-issue-with-ipv6-and-localhost-705)
for more information.

</div>

### Rewrite the URL path

The `pathRewrite` proxy configuration option lets you rewrite the URL path at run time.
Expand Down
Loading

0 comments on commit 3c48ca1

Please sign in to comment.