This commit exposes the new `output()` API with numerous benefits:
- Symmetrical API to `input()`, `model()` etc.
- Fixed types for `EventEmitter.emit`— current `emit` method of
`EventEmitter` is broken and accepts `undefined` via `emit(value?: T)`
- Removal of RxJS specific concepts from outputs. error channels,
completion channels etc. We now have a simple consistent
interface.
- Automatic clean-up of subscribers upon directive/component destory-
when subscribed programmatically.
```ts
@Directive({..})
export class MyDir {
nameChange = output<string>(); // OutputEmitterRef<string>
onClick = output(); // OutputEmitterRef<void>
}
```
Note: RxJS custom observable cases will be handled in future commits via
explicit helpers from the interop.
PR Close#54650
In a previous commit the TCB was changed to cast the assignment to an input in order to widen its type to allow `WritableSignal`. This ended up breaking existing inputs whose setter has a wider type than its getter. These changes switch to unwrapping the value on the binding side.
PR Close#54252
Adds support for model inputs in the framework. `model()` returns a writable signal that implicitly defines a input/output pair that can be used either in two-way bindings to keep two values in sync or by binding individually to the input and output. When the value of the `model` changes, it will emit an event with the current value.
Furthermore, these changes expand two-way bindings to accept `WritableSignal`. This will make it easier to transition existing code to signals in a backwards-compatible way.
Example:
```ts
@Directive({
selector: 'counter',
standalone: true,
host: {
'(click)': 'increment()',
}
})
export class Counter {
value = model(0);
increment(): void {
this.value.update(current => current + 1);
}
}
@Component({
template: `<counter [(value)]="count"/> The current count is: {{count()}}`,
})
class App {
count = signal(0);
}
```
PR Close#54252
Whenever a required input is accessed too early in a
directive/component, the signal input will throw an error.
This is necessary so that we can support required inputs
with intuitive typings that do not include `undefined` for
the short period of time where Angular is creating the component and
then assigning inputs later (Angular currently has no way of setting
inputs as part of the class creation when `new Dir()` happens)
PR Close#53808
The `afterRender` hooks currently run after `ApplicationRef.tick` but
also run after any call to `ChangeDetectorRef.detectChanges`. This is
problematic because code which uses `afterRender` cannot expect the
component it's registered from to be rendered when the callback
executes. If there is a call to `ChangeDetectorRef.detectChanges` before
the global change detection, that will cause the hooks to run earlier
than expected.
This behavior is somewhat of a blocker for the zoneless project. There
is plenty of application code that do things like `setTimeout(() =>
doSomethingThatExpectsComponentToBeRendered())`, `NgZone.onStable(() =>
...)` or `ApplicationRef.onStable...`. `ApplicationRef.onStable` is a
should likely work similarly, but all of these are really wanting an API
that is `afterRender` with the requirement that the hook runs after the
global render, not an individual CDRef instance.
This change updates the `afterRender` hooks to only run when
`ApplicationRef.tick` happens.
fixes#52429fixes#53232
PR Close#52455
This commit runs change detection in a loop while there are still dirty
views to be refreshed in the tree. At the moment, this only applies to
transplanted views but will also apply to views with changed signals.
fixes angular#49801
PR Close#51854
This commit updates the code to report errors via `ErrorHandler` instance.
For dependency loading problems, errors are reported only when `@error` block is not provided.
PR Close#52320
Certain code patterns and tools in Google (and possibly 3P world) lead to the situation that a component is bootstrapped/rendered without its ng-module being loaded in the browser. Technically speaking this should be an anti-pattern since the ng-module could contain some runtime logic (e.g., providing something, calling some services, etc) and its not being loaded leads to unexpected behaviour. However, in many cases ng-module is an empty class and its only usage is for providing scope, and since in AoT full compilation mode we already hard-code dependencies into components so we can get away with not loading the ng-module. But in AoT local compilation mode it is not possible to get away since the component's dependencies are computed in runtime and the presence of the corresponding ng-module in the browser is needed. For this reason in this change it is forbidden to attempt to render a component without first loading its ng-module in local compilation mode and an explicit error message is created to make this situation clear. This error message can help with catching such cases when running TGP in Google.
It would be an interesting question as to whether to ban this situation in full compilation mode as well, as it is error prone and these errors are sometimes very hard to debug.
PR Close#51726
non-destructive hydration expects the DOM tree to have the same structure in both places.
With this commit, the app will throw an error if comments are stripped out by the http server (eg by some CDNs).
fixes#51160
PR Close#51170
The previous commits add a new runtime error code (RUNTIME_DEPS_INVALID_IMPORTED_TYPE) which needs to be added to the golden for the tests to pass.
PR Close#50980
Hydration requires a stable App to run some logic.
With this warning developers will be informed about potential issues encountered when running an unstable app.
Fixes#50285
PR Close#50295
It might happen that the lifecycle scope represented by DestroyRef becomes
invalid before an onDestroy hook is registered (ex. injector or component
instance got destroyed). In such cases registration of the onDestroy hooks
should no longer be possible.
Fixes#49658
PR Close#49804
The initial value used for signals by default is now `undefined`. In
addition, there is a new option to express that the signal should emit a
value synchronously (`requireSync: true`). When this value is specified,
the function will throw _on creation_ if the subscribing to the
`Observable` does not result in a synchronous emit.
PR Close#49769
This commit updates the logic to detect a situation when hydration support was enabled only on the client. If that happens, Angular produces a warning in a console with a link to the error guide.
PR Close#49743
Currently, non-destructive hydration for i18n blocks is not supported (but support is coming!).
This commit updates the serialization logic from throwing an error when it comes across an i18n
block to annotating a component with a skip hydration flag.
PR Close#49722
* Prevent reads of signals during the notification process. This shouldn't
ever be triggered by user code but is more of a preventative for
internal misuse. Reading a signal during notification would/could create
glitches where the values being read are not updated to reflect the
values being updated by the notification.
* Prevent signal writes inside of computed's. These are meant to be
derived values and should not have any side-effects like writing new
values to other signals
* Prevent signal writes inside of effects by default. Writing to signal
values during the execution of an effect can lead to the
`ExpressionChangedAfterItHasBeenCheckedError` if writing to signals
that represent global state which is read in a parent component. This is
mostly just a problem for `OnPush`/`CheckAlways` components, but with
signals being new and pure signal components not even available yet,
it will be the majority for a long time.
PR Close#49631
This adds user friendly error messages outlining exactly where hydration
mismatches occur and what was expected with easy to read stringified
DOM. It also includes a pointer to exactly where the mismatch happened
and lets the user know what was expected.
PR Close#49502
This commit moves the providers for `NgZone`-based change detection to a
single provider function. This function is currently called by default
in all places where `NgZone` was provided
(`bootstrapApplication`, `bootstrapModule`, and `TestBed`).
When we want to make Angular applications zoneless by default, we
can make a public provider method that has to be used in order to enable
the zone change detection features. When this method is not called,
Angular would use `NoopNgZone` by default and not initialize any
subscriptions to the `NgZone` stability events.
Side note: There are actually two places that `NgZone` is provided for `TestBed`
(providers in `compileTestModule` and `BrowserTestingModule`). This
likely doesn't need to be in both locations.
PR Close#49373
- update `errors.ts` to annotate the error NG0403, so that the runtime can add a link to that guide when an error is thrown
- update `application_ref_spec.ts` to include the new link of the error
- update `errors.md` as a result of running `yarn bazel test packages/core/test`
Fixes#47985
PR Close#48483
This commit updates the logic related to the attribute and property binding rules for <iframe> elements. There is a set of <iframe> attributes that may affect the behavior of an iframe and this change enforces that these attributes are only applied as static attributes, making sure that they are taken into account while creating an <iframe>.
If Angular detects that some of the security-sensitive attributes are applied as an attribute or property binding, it throws an error message, which contains the name of an attribute that is causing the problem and the name of a Component where an iframe is located.
BREAKING CHANGE:
Existing iframe usages may have security-sensitive attributes applied as an attribute or property binding in a template or via host bindings in a directive. Such usages would require an update to ensure compliance with the new stricter rules around iframe bindings.
PR Close#47964
This reverts commit 2d08965b1a.
The reason for revert is that we've identified some issues with implementation. The issues will get addressed soon and the fix would be re-submitted.
PR Close#47959
This commit updates the logic related to the attribute order on iframes and makes the rules more strict. There is a set of iframe attributes that may affect the behavior of an iframe, this change enforces that these attributes are applied before an `src` or `srcdoc` attributes are applied to an iframe, so that they are taken into account.
If Angular detects that some of the attributes are set after the `src` or `srcdoc`, it throws an error message, which contains the name of ann attribute that is causing the problem and the name of a Component where an iframe is located. In most cases, it should be enough to change the order of attributes in a template to move the `src` or `srcdoc` ones to the very end.
BREAKING CHANGE:
Existing iframe usages may have `src` or `srcdoc` preceding other attributes. Such usages may need to be updated to ensure compliance with the new stricter rules around iframe bindings.
PR Close#47935
Currently if the `ENVIRONMENT_INITIALIZER` token is not configured with `multi: true` flag, the code fails while trying to iterate over the value. This commit checks whether the `ENVIRONMENT_INITIALIZER` token value type is an array and throws a helpful error message.
PR Close#46829
Previously, when instantiating a component, Angular would look in the DI
hierarchy for `RendererFactory2`. Any DI tree which rolls up through an
application injector (that is, one created with `BrowserModule`) should be
able to provide this interface. If not found, Angular would switch to the
experimental `Renderer3` mechanism. This switch was designed this way,
because it allowed for the creation of experimental applications where
`RendererFactory2` was not included in the bundle at all.
In this commit, instead of automatically falling back on `Renderer3`-style
rendering, an error is raised instead if `RendererFactory2` is missing from
the DI hierarchy.
PR Close#46605
This commit narrows down acceptable argument types of the
`importProvidersFrom` function. More specifically, it rejects
standalone components as a source of imports.
PR Close#45837
`importProvidersFrom` provides a bridge from the world of NgModule-based DI
configuration to the new, "standalone" world of direct providers and
environment injectors. Early user feedback suggested some confusion around
where this function was supposed to be used, particularly around importing
NgModule-based providers into standalone component `providers` arrays, which
is not the intended use. This confusion is exacerbated by the fact that due
to the unified `Provider` type, this kind of misconfiguration was happily
accepted by the type system.
This commit changes the return type of `importProvidersFrom` to wrap the
returned providers in an opaque type that prevents them from being used in
component provider contexts. This, together with stronger documentation
around the purpose and functionality of `importProvidersFrom`, should
address some of the above confusion.
PR Close#45838
This commit implements the `bootstrapApplication` function that allows bootstrapping an application and pass a standalone component as a root component.
PR Close#45674
This commit implements the `destroy` method on the `ApplicationRef` class. This feature is a preparation for the new logic to bootstrap (and teardown) standalone components (without going through the `NgModuleRef` destroy), which would return an instance of the `ApplicationRef` (the current bootstrap APIs return an instance of the `NgModuleRef`).
PR Close#45624
This commit refactors the `RuntimeError` class to support a short version of providing error messages:
```
throw new RuntimeError(
RuntimeErrorCode.INJECTOR_ALREADY_DESTROYED,
ngDevMode && 'Injector has already been destroyed.');
```
In prod mode, the second argument becomes `false` andn this commit extends the typings to support that.
This commit also contains a couple places were the `RuntimeError` class is used to demostrate the compact form.
PR Close#44783