With #31953 we moved the factories for components, directives and pipes into a new field called `ngFactoryDef`, however I decided not to do it for injectables, because they needed some extra logic. These changes set up the `ngFactoryDef` for injectables as well.
For reference, the extra logic mentioned above is that for injectables we have two code paths:
1. For injectables that don't configure how they should be instantiated, we create a `factory` that proxies to `ngFactoryDef`:
```
// Source
@Injectable()
class Service {}
// Output
class Service {
static ngInjectableDef = defineInjectable({
factory: () => Service.ngFactoryFn(),
});
static ngFactoryFn: (t) => new (t || Service)();
}
```
2. For injectables that do configure how they're created, we keep the `ngFactoryDef` and generate the factory based on the metadata:
```
// Source
@Injectable({
useValue: DEFAULT_IMPL,
})
class Service {}
// Output
export class Service {
static ngInjectableDef = defineInjectable({
factory: () => DEFAULT_IMPL,
});
static ngFactoryFn: (t) => new (t || Service)();
}
```
PR Close#32433
Child component refresh must happen before executing the ViewQueryFn because
child components could insert a template from the host that contains the result
of the ViewQuery function (see related test added in this PR).
PR Close#32922
This patch changes the Ivy `DebugElement` code to always read style and
class values directly from the native element instead of reading them
through the styling contexts. The reason for this change is because Ivy
does not make use of a debug renderer and will therefore not have access
to any classes/styles applied directly through the renderer (unless it
reads the values directly from the element).
PR Close#32842
Prior to this commit, the `ngProjectAs` attribute was only included with a special flag and in a parsed format. As a result, projected node was missing `ngProjectAs` attribute as well as other attributes added after `ngProjectAs` one. This is problematic since app code might rely on the presence of `ngProjectAs` attribute (for example in CSS). This commit fixes the problem by including `ngProjectAs` into attributes array as a regular attribute and also makes sure that the parsed version of the `ngProjectAs` attribute with a special marker is added after regular attributes (thus we set them correctly at runtime). This change also aligns View Engine and Ivy behavior.
PR Close#32784
This patch fixes a bug where the map-based cursor moves too far and
skips intermediate values when the correct combination of single-prop
bindings and map-based bindings are used together.
PR Close#32774
This patch enables a styling debug instance (which is apart of the
`debugNode.styles` or `debugNode.classes` data structures) to expose
its context value so that it can be easily debugged.
PR Close#32753
Prior to this patch the `window.ng.getDebugNode` method would fail to
return the debug information for an element that is a host element to
a component.
PR Close#32780
Now that the `$localize` translations are `MessageId` based the
compiler must render `MessageId`s in its generated `$localize` code.
This is because the `MessageId` used by the compiler is computed
from information that does not get passed through to the `$localize`
tagged string.
For example, the generated code for the following template
```html
<div id="static" i18n-title="m|d" title="introduction"></div>
```
will contain these localization statements
```ts
if (ngI18nClosureMode) {
/**
* @desc d
* @meaning m
*/
const MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1 = goog.getMsg("introduction");
I18N_1 = MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1;
}
else {
I18N_1 = $localize \`:m|d@@8809028065680254561:introduction\`;
}
```
Since `$localize` is not able to accurately regenerate the source-message
(and so the `MessageId`) from the generated code, it must rely upon the
`MessageId` being provided explicitly in the generated code.
The compiler now prepends all localized messages with a "metadata block"
containing the id (and the meaning and description if defined).
Note that this metadata block will also allow translation file extraction
from the compiled code - rather than relying on the legacy ViewEngine
extraction code. (This will be implemented post-v9).
Although these metadata blocks add to the initial code size, compile-time
inlining will completely remove these strings and so will not impact on
production bundle size.
PR Close#32594
Prior to this patch, each time `advance()` would run (or when a
templateFn or hostBindings code exits) then the core change detection
code would check to see whether the styling data needs to be reset. This
patch removes that functionality and places everything inside of the
scheduled styling exit function. This means that each time one or more
styling bindings run (even if the value hasn't changed) then an exit
function will be scheduled and that will do all the cleanup.
PR Close#32591
This patch is a final major refactor in styling Angular.
This PR includes three main fixes:
All temporary state taht is persisted between template style/class application
and style/class application in host bindings is now removed.
Removes the styling() and stylingApply() instructions.
Introduces a "direct apply" mode that is used apply prop-based
style/class in the event that there are no map-based bindings as
well as property collisions.
PR Close#32259
PR Close#32591
If an <ng-template> contains a structural directive (for example *ngIf), Ngtsc generates extra template function with 1 template instruction call. When <ng-template> tag also contains i18n attribute on it, we generate i18nStart and i18nEnd instructions around it, which is unnecessary and breaking runtime. This commit adds a logic to make sure we do not generate i18n instructions in case only `template` is present.
PR Close#32623
This is a refactoring that moves the source code around to provide a better
platform for adding the compile-time inlining.
1. Move the global side-effect import from the primary entry-point to a
secondary entry-point @angular/localize/init.
This has two benefits: first it allows the top level entry-point to
contain tree-shakable shareable code; second it gives the side-effect
import more of an "action" oriented name, which indicates that importing
it does something tangible
2. Move all the source code into the top src folder, and import the localize
related functions into the localize/init/index.ts entry-point.
This allows the different parts of the package to share code without
a proliferation of secondary entry-points (i.e. localize/utils).
3. Avoid publicly exporting any utilities at this time - the only public
API at this point are the global `$localize` function and the two runtime
helpers `loadTranslations()` and `clearTranslations()`.
This does not mean that we will not expose additional helpers for 3rd
party tooling in the future, but it avoid us preemptively exposing
something that we might want to change in the near future.
Notes:
It is not possible to have the `$localize` code in the same Bazel package
as the rest of the code. If we did this, then the bundled `@angular/localize/init`
entry-point code contains all of the helper code, even though most of it is not used.
Equally it is not possible to have the `$localize` types (i.e. `LocalizeFn`
and `TranslateFn`) defined in the `@angular/localize/init` entry-point because
these types are needed for the runtime code, which is inside the primary
entry-point. Importing them from `@angular/localize/init` would run the
side-effect.
The solution is to have a Bazel sub-package at `//packages/localize/src/localize`
which contains these types and the `$localize` function implementation.
The primary `//packages/localize` entry-point imports the types without
any side-effect.
The secondary `//packages/localize/init` entry-point imports the `$localize`
function and attaches it to the global scope as a side-effect, without
bringing with it all the other utility functions.
BREAKING CHANGES:
The entry-points have changed:
* To attach the `$localize` function to the global scope import from
`@angular/localize/init`. Previously it was `@angular/localize`.
* To access the `loadTranslations()` and `clearTranslations()` functions,
import from `@angular/localize`. Previously it was `@angular/localize/run_time`.
PR Close#32488
This patch is a final major refactor in styling Angular.
This PR includes three main fixes:
All temporary state taht is persisted between template style/class application
and style/class application in host bindings is now removed.
Removes the styling() and stylingApply() instructions.
Introduces a "direct apply" mode that is used apply prop-based
style/class in the event that there are no map-based bindings as
well as property collisions.
PR Close#32259
PR Close#32596
This patch is a final major refactor in styling Angular.
This PR includes three main fixes:
All temporary state taht is persisted between template style/class application
and style/class application in host bindings is now removed.
Removes the styling() and stylingApply() instructions.
Introduces a "direct apply" mode that is used apply prop-based
style/class in the event that there are no map-based bindings as
well as property collisions.
PR Close#32259
Adds two acceptance tests to show a current difference in behavior between Ivy and VE.
A directive with a selector `.Titledir` matches an element with `class="titleDir"` in VE but not in Ivy.
Same thing for an attribute value.
PR Close#32548
Prior to this commit, the `previousOrParentTNode` was set to null after performing all operations within `refreshView` function. It's causing problems in more complex scenarios, for example when change detection is triggered during DI (see test added as a part of this commit). As a result, global state might be corrupted. This commit captures current value of `previousOrParentTNode` and restores it after `refreshView` call.
PR Close#32521
The `goog.getMsg()` function requires placeholder names to be camelCased.
This is not the case for `$localize`. Here placeholder names need
match what is serialized to translation files.
Specifically such placeholder names keep their casing but have all characters
that are not in `a-z`, `A-Z`, `0-9` and `_` converted to `_`.
PR Close#32509
Logs a warning instead of throwing when running into a binding to an unknown property in JIT mode. Since we aren't using a schema for the runtime validation anymore, this allows us to support browsers where properties are unsupported.
PR Close#32463
Prior to this commit, listeners order was not preserved in case we coalesce them to avoid triggering unnecessary change detection cycles. For performance reasons we were attaching listeners to existing events at head (always using first listener as an anchor), to avoid going through the list, thus breaking the order in which listeners are registered. In some scenarios this order might be important (for example with `ngModelChange` and `input` listeners), so this commit updates the logic to put new listeners at the end of the list. In order to avoid performance implications, we keep a pointer to the last listener in the list, so adding a new listener takes constant amount of time.
PR Close#32484
Fixes an issue where Ivy incorrectly inserts items in the beginning of an `ngFor`, if the `ngFor` is set on an `ng-container`. The issue comes from the fact that we choose the `ng-container` comment node as the anchor point before which to insert the content, however the node might be after any of the nodes inside the container. These changes switch to picking out the first node inside of the container instead.
PR Close#32324
Prior to this commit, complex expressions (that require additional statements to be generated) were handled incorrectly in case they were used in attributes annotated with i18n flags. The problem was caused by the fact that extra statements were not appended to the temporary vars block, so they were missing in generated code. This commit updated the logic to use the `convertPropertyBinding`, which contains the necessary code to append extra statements. The `convertExpressionBinding` function was removed as it duplicates the `convertPropertyBinding` one (for the most part) and is no longer used.
PR Close#32309
Prior to this fix if a `NO_CHANGE` value was assigned to a binding, or
an interpolation value rendererd a `NO_CHANGE` value, then the presence
of that value would cause the internal counter index values to not
increment properly. This patch ensures that this doesn't happen and
that the counter/bitmask values update accordingly.
PR Close#32143
This commit changes the Angular compiler (ivy-only) to generate `$localize`
tagged strings for component templates that use `i18n` attributes.
BREAKING CHANGE
Since `$localize` is a global function, it must be included in any applications
that use i18n. This is achieved by importing the `@angular/localize` package
into an appropriate bundle, where it will be executed before the renderer
needs to call `$localize`. For CLI based projects, this is best done in
the `polyfills.ts` file.
```ts
import '@angular/localize';
```
For non-CLI applications this could be added as a script to the index.html
file or another suitable script file.
PR Close#31609
Extend the vocabulary of the `providedIn` to also include `'platform'` and `'any'`` scope.
```
@Injectable({
providedId: 'platform', // tree shakable injector for platform injector
})
class MyService {...}
```
PR Close#32154
Prior to this change, the `BINDING_INDEX` of a given lView was reset after processing a template. However change detection can be triggered as a result of View queries processing, thus leading to subsequent `refreshView` call (and executing a template), which in turn operates with the binding index that is not reset after the previous `refreshView` call. This commit updates the logic to reset binding index before we execute a template, so binding index is correct for instructions inside template function.
PR Close#32201
In VE the `Sanitizer` is always available in `BrowserModule` because the VE retrieves it using injection.
In Ivy the injection is optional and we have instructions instead of component definition arrays. The implication of this is that in Ivy the instructions can pull in the sanitizer only when they are working with a property which is known to be unsafe. Because the Injection is optional this works even if no Sanitizer is present. So in Ivy we first use the sanitizer which is pulled in by the instruction, unless one is available through the `Injector` then we use that one instead.
This PR does few things:
1) It makes `Sanitizer` optional in Ivy.
2) It makes `DomSanitizer` tree shakable.
3) It aligns the semantics of Ivy `Sanitizer` with that of the Ivy sanitization rules.
4) It refactors `DomSanitizer` to use same functions as Ivy sanitization for consistency.
PR Close#31934
Similar to interpolation, we do not want to completely remove whitespace
nodes that are siblings of an expansion.
For example, the following template
```html
<div>
<strong>items left<strong> {count, plural, =1 {item} other {items}}
</div>
```
was being collapsed to
```html
<div><strong>items left<strong>{count, plural, =1 {item} other {items}}</div>
```
which results in the text looking like
```
items left4
```
instead it should be collapsed to
```html
<div><strong>items left<strong> {count, plural, =1 {item} other {items}}</div>
```
which results in the text looking like
```
items left 4
```
---
**Analysis of the code and manual testing has shown that this does not cause
the generated ids to change, so there is no breaking change here.**
PR Close#31962
Fixes Ivy's directive matching not capturing attribute selectors when there is one class binding, one style binding and a regular binding that precede the attribute that would match the directive. The issue appears to come from the fact that we weren't skipping over style bindings correctly which was throwing the loop off not to go into `bindingsMode` and to skip some of the bindings when matching.
PR Close#31942
Prior to this commit, the `schemas` configuration was applied to top-level view only. That leads to problems when using unknown props with elements inside nested views (for example generated as a result of *ngIf). This commit passes `schemas` information down to nested views to make sure that all the checks are consistent.
PR Close#31913
In `BrowserModule` the value of `LOCALE_ID` is defined in the `APPLICATION_MODULE_PROVIDERS` after `APP_INITIALIZER` has run.
This PR ensures that `LOCALE_ID` is also set for ivy at the same moment which allows the application to fetch the locale from a backend (for example).
Fixes#31465
FW-1436 #resolve
PR Close#31566
Fixes Ivy throwing an error when something is passed in as a `forwardRef` into `@Injectable`'s `useClass` option. The error was being thrown, because we were trying to get the provider factory off of the wrapper function, rather than the value itself.
This PR resolves FW-1335.
PR Close#30532
This commit fixes a bug where we assumed all dynamically created
components would have tag-name selectors, so we passed through the
"tag name" to the renderer as the first index of the selector. For
components with attribute selectors, the tag name would be "", so
the renderer would try to create an element with tag name "" and
throw. Now we default to a "div" element the same way that View
Engine did.
Closes#31785
PR Close#31812
The way the `ComponentFactory.create` is set up at the moment is that if a `rootSelectorOrNode` is passed in, the root context will be injected instead of creating dedicated one for the component. As far as I can tell, there doesn't seem to be a reason to do this and nothing seems to break because of it. These changes switch to always create the root context.
PR Close#31661
When injecting a `ChangeDetectorRef` into a pipe, the expected result is that the ref will be tied to the component in which the pipe is being used. This works for most cases, however when a pipe is used inside a property binding of a component (see test case as an example), the current `TNode` is pointing to component's host so we end up injecting the inner component's view. These changes fix the issue by only looking up the component view of the `TNode` if the `TNode` is a parent.
This PR resolves FW-1419.
PR Close#31438
In the previous patch () all the existing styling code was turned
off in favor of using the new refactored ivy styling code. This
patch is a follow up patch to that and removes all old, unused
styling code from the render3 directory.
PR Close#31193
This commit fixes a bug where ICU expressions inserted into ngTemplateOutlets
that are inside ngFor blocks would throw an error. We were assuming in view
insertion code that text nodes would always exist by the time a view\`s
creation block had executed. This is not true for text nodes created dynamically
by ICUs because this happens in the update block (in `i18nApply`).
This change ensures such dynamically created nodes are skipped when encountered
too early (as they will be attached later by i18n code anyway).
PR Close#31789
We currently have a handwritten version of the Ivy directive def for NgClass so
we can switch between Ivy and View Engine behavior. This generated code needs to
be kept up-to-date with what the Ivy compiler generates.
PR 30742 recently changed `classMap` such that it now requires allocation of
host binding slots. This means that the `allocHostVars()` function must be
called in the NgClass directive def to match compiler output, but the
handwritten directive def was not updated. This caused a bug where NgClass
was inappropriately overwriting data for other directives because space was
not allocated for its values.
PR Close#31788
This commit is the final patch of the ivy styling algorithm refactor.
This patch swaps functionality from the old styling mechanism to the
new refactored code by changing the instruction code the compiler
generates and by pointing the runtime instruction code to the new
styling algorithm.
PR Close#30742
Fixes all TypeScript failures caused by enabling the `--strict`
flag for test source files. We also want to enable the strict
options for tests as the strictness enforcement improves the
overall codehealth, unveiled common issues and additionally it
allows us to enable `strict` in the `tsconfig.json` that is picked
up by IDE's.
PR Close#30993
In View Engine, developers can pass bootstrap and entry components
as nested arrays. e.g.
```ts
export const MyOtherEntryComponents = [A, B, C]
@NgModule({
entryComponents: [MyComp, MyOtherEntryComponents]
})
```
Currently using nested arrays for these properties causes
unexpected errors to be reported in Ivy since the semantic
NgModule checks aren't properly recursing into the nested
entry/bootstrap components. This issue has been unveiled by
enabling the strict function parameter checks.
PR Close#30993
Fixes Ivy matching directives against attribute bindings (e.g. `[attr.some-directive]="foo"`). Works by excluding attribute bindings from the attributes array during compilation. This has the added benefit of generating less code.
**Note:** My initial approach to implementing this was to have a different marker for attribute bindings so that they can be ignored when matching directives, however as I was implementing it I realized that the attributes in that array were only used for directive matching (as far as I could tell). I decided to drop the attribute bindings completely, because it results in less generated code.
PR Close#31541
Prior to this fix, the logic to set the right placeholder format for ICUs was a bit incorrect: if there was a nested ICU in one of the root ICU cases, that led to a problem where placeholders in subsequent branches used the wrong ({$placeholder}) format instead of {PLACEHOLDER} one. This commit updates the logic to make sure we properly transform all placeholders even if nested ICUs are present.
PR Close#31516
Since `goog.getMsg` does not process ICUs (post-processing is required via goog.i18n.MessageFormat, https://google.github.io/closure-library/api/goog.i18n.MessageFormat.html) and placeholder format used for ICUs and regular messages inside `goog.getMsg` are different, the current implementation (that assumed the same placeholder format) needs to be updated. This commit updates placeholder format used inside ICUs from `{$placeholder}` to `{PLACEHOLDER}` to better align with Closure. ICU placeholders (that were left as is prior to this commit) are now replaced with actual values in post-processing step (inside `i18nPostprocess`).
PR Close#31459
Prior to this commit, the `` unicode symbol that represents `&ngsp` in translations was not handled correctly, i.e. was not replaced with a whitespace, thus appearing on a screen. This commit adds post-processing and replaces the mentioned symbol with a whitespace.
PR Close#31479
`i18nStart` was calling `allocExpando` even if there was 0 new variable created.
This created a new expando instruction with the value 0 which was later interpreted as the start of a new expando block instead of just skipping 0 instructions.
FW-1417 #resolve
PR Close#31451
Adds a new `elementContainer` instruction that can be used to avoid two instruction (`elementContainerStart` and `elementContainerEnd`) for `ng-container` that has text-only content. This is particularly useful when we have `ng-container` inside i18n sections.
This PR resolves FW-1105.
PR Close#31444
Adds the new `classMapInterpolate1` through `classMapInterpolate8` instructions which handle interpolations inside the `class` attribute and moves the interpolation logic internally. This allows us to remove the `interpolationX` instructions in a follow-up PR.
These changes also add an error if an interpolation is encountered inside a `style` tag (e.g. `style="width: {{value}}"`). Up until now this would actually generate valid instructions, because `styleMap` goes through the same code path as `classMap` which does support interpolation. At runtime, however, `styleMap` would set invalid styles that look like `<div style="0:w;1:i;2:d;3:t;4:h;5::;7:1;">`. In `ViewEngine` interpolations inside `style` weren't supported either, however there we'd output invalid styles like `<div style="unsafe">`, even if the content was trusted.
PR Close#31211
Prior to this commit, host element of a view created via TestBed.createComponent was not attached to the component's host, making it problematic to use TestBed.createComponent API in component factories, which might be used for testing purposes only. This behavior is observed in google3 app tests and was supported by VE, so this commit aligns Ivy and VE.
PR Close#31318
When `walkTNodeTree` was refactored, the case of ICU expressions was forgotten (because it was handled in the `else` previously).
This PR fixes that to handle it like `ElementContainer`.
FW-1411 #resolve
PR Close#31313
Currently in Ivy whenever we encounter a new namespace, we set it in the global state so that all subsequent nodes are created under the same namespace. Next time a template is run the namespace will be reset back to HTML.
This breaks down if the last node that was rendered was under the SVG or MathML namespace and we create a component through `ViewContainerRef.create`, because the next template function hasn't run yet and it hasn't had the chance to update the namespace. The result is that the root node of the new component will retain the wrong namespace and may not end up rendering at all (e.g. if we're trying to show a `div` inside the SVG namespace). This issue has the potential to affect a lot of apps, because all components inserted through the router also go through `ViewContainerRef.create`.
PR Close#31232
The Angular runtime frequently calls into user code (for example, when
writing to a property binding). Since user code can throw errors, calls to
it are frequently wrapped in a try-finally block. In Ivy, the following
pattern is common:
```typescript
enterView();
try {
callUserCode();
} finally {
leaveView();
}
```
This has a significant problem, however: `leaveView` has a side effect: it
calls any pending lifecycle hooks that might've been scheduled during the
current round of change detection. Generally it's a bad idea to run
lifecycle hooks after the application has crashed. The application is in an
inconsistent state - directives may not be instantiated fully, queries may
not be resolved, bindings may not have been applied, etc. Invariants that
the app code relies upon may not hold. Further crashes or broken behavior
are likely.
Frequently, lifecycle hooks are used to make assertions about these
invariants. When these assertions fail, they will throw and "swallow" the
original error, making debugging of the problem much more difficult.
This commit modifies `leaveView` to understand whether the application is
currently crashing, via a parameter `safeToRunHooks`. This parameter is set
by modifying the above pattern:
```typescript
enterView();
let safeToRunHooks = false;
try {
callUserCode();
safeToRunHooks = true;
} finally {
leaveView(..., safeToRunHooks);
}
```
If `callUserCode` crashes, then `safeToRunHooks` will never be set to `true`
and `leaveView` won't call any further user code. The original error will
then propagate back up the stack and be reported correctly. A test is added
to verify this behavior.
PR Close#31244
In ViewEngine injecting a Renderer2 returns a renderer that is specific to the particular component, however in Ivy we inject the renderer for the parent view instead. This causes it to set incorrect `ngcontent` attributes when creating elements through the renderer.
The issue comes from the fact that the `Renderer2` is created according to the current `LView`, but because DI happens before we've entered the `LView` of the component that's injecting the renderer, we end up with one that's one level up. We work around the issue by finding the `LView` that corresponds to the `previousOrParentTNode` inside of the parent view and associating the `Renderer2` with it.
This PR resolves FW-1382.
PR Close#31063
Previously, multiple ViewContainerRef instances (obtained by injecting
ViewContainerRef multiple times) each had private state that could be out of
sync with actual LContainer, if views were inserted/removed/queried across
the different instances. In particular each instance had its own array which
tracked ViewRefs inserted via that instance.
This commit moves the ViewRefs array onto the LContainer itself, so that it
can be shared across multiple ViewContainerRef instances. A test is added
that verifies ViewContainerRefs now provide a consistent view of the
container.
FW-1377 #resolve
PR Close#30985
When using `createEmbeddedView` after the creation of an ICU expression, the nodes for the current selected case were not reprojected (only the anchor comment node was moved to the new location).
Now we reproject correctly all the child nodes of an ICU expression when an anchor comment node is projected.
FW-1372 #resolve
PR Close#30979
Currently in Ivy we throw when attempting to destroy a `ComponentRef` that has been destroyed, however in ViewEngine we didn't which can cause some tests to break. These changes remove the error to match ViewEngine.
These changes resolve FW-1379.
PR Close#31022
To provide some context: The implicit receiver is part of the
parsed Angular template AST. Any property reads in bindings,
interpolations etc. read from a given object (usually the component
instance). In that case there is an _implicit_ receiver which can also
be specified explicitly by just using `this`.
e.g.
```html
<ng-template>{{this.myProperty}}</ng-template>
```
This works as expected in Ivy and View Engine, but breaks in case the
implicit receiver is not used for property reads. For example:
```html
<my-dir [myFn]="greetFn.bind(this)"></my-dir>
```
In that case the `this` will not be properly translated into the generated
template function code because the Ivy compiler currently always treats
the `ctx` variable as the implicit receiver. This is **not correct** and breaks
compatibility with View Engine. Rather we need to ensure that we retrieve
the root context for the standalone implicit receiver similar to how it works
for property reads (as seen in the example above with `this.myProperty`)
Note that this requires some small changes to the `expression_converter`
because we only want to generate the `eenextContent()` instruction if the
implicit receiver is _actually_ used/needed. View Engine determines if that is the case by recursively walking through the converted output AST and
checking for usages of the `o.variable('_co')` variable ([see here][ve_check]). This would work too for Ivy, but involves most likely more code duplication
since templates are isolated in different functions and it another pass
through the output AST for every template expression.
[ve_check]: 0d6c9d36a1/packages/compiler/src/view_compiler/view_compiler.ts (L206-L208)
Resolves FW-1366.
PR Close#30897
17d87d4e10 has been created before the changes
to the `@ViewChild` and `@ContentChild` decorators. Meaning that it still uses the queries
without the `static` flag. This results in failures in `master` because #30625 has been merged.
PR Close#30967
`TView.firstChild` was defined as the first node with index 0, but when we use runtime i18n then the instruction `i18nStart` can be the one with index 0 and the first node will be index 1 or more.
With this fix we set `TView.firstChild` when we see the first node with index 0 or later if `TView.firstChild` is still null.
FW-1367 #resolve
PR Close#30920
This work is being done ahead of changes to how view insertion is done in Ivy in accordance with [this design document](https://hackmd.io/Ae3W_2pOQlKouu9YNy1t6A?view).
The idea is to make sure we have acceptance tests ahead of that change.
PR Close#30625
The `renderStringify` function shows up pretty high in the CPU profiling.
Turns out that this function contained unnecessary `typeof` check for
function types - the check only makes sense / is used in error messages.
The PR also alligns how ivy and view engine stringify functions used in
interpolations.
PR Close#30838
A directive input that doesn't use a binding is triggered during the creation phase. But this was only executed at the first template pass, and not on subsequent ones.
Now only the creation of the update instruction is executed on the first template pass, anything else is executed every time a template is created.
FW-1361 #resolve
PR Close#30870
When translated content was projected, all of the content was reappended, even the placeholders that had been removed in the translation.
To avoid that we added a new flag on `TNode` that specifies that a node is detached, in which case it should be ignored by the projection.
FW-1319 #resolve
PR Close#30783
Added a new syntax for projections (`¤` will represent `ng-content` nodes) so that we can treat them specifically.
When we enter an i18n block with the instruction `i18nStart`, a new `delayProjection` variable is set to true to prevent the instruction `projection` from projecting the nodes. Once we reach the `i18nEnd` instruction and encounter a projection in the translation we will project its nodes.
If a projection was removed from a translation, then its nodes won't be projected at all.
The variable `delayProjection` is restored to `false` at the end of `i18nEnd` so that it doesn't stop projections outside of i18n blocks.
FW-1261 #resolve
PR Close#30782
We used to ignore empty strings for optimization purposes, but it turns out that empty strings are also valid values for ICU cases and we shouldn't ignore those.
FW-1290 #resolve
PR Close#30846
Projecting bare ICU expressions failed because we would assume that component's content nodes would be projected later and doing so at that point would be wasteful. But ICU nodes are handled independently and should be inserted immediately because they will be ignored by projections.
FW-1348 #resolve
PR Close#30696
With View engine it was possible to declare multiple projection
definitions and to programmatically project nodes into the slots.
e.g.
```html
<ng-content></ng-content>
<ng-content></ng-content>
```
Using `ViewContainerRef#createComponent` allowed projecting
nodes into one of the projection defs (through index)
This no longer works with Ivy as the `projectionDef` instruction only
retrieves a list of selectors instead of also retrieving entries for
reserved projection slots which appear when using the default
selector multiple times (as seen above).
In order to fix this issue, the Ivy compiler now passes all
projection slots to the `projectionDef` instruction. Meaning that
there can be multiple projection slots with the same wildcard
selector. This allows multi-slot projection as seen in the
example above, and it also allows us to match the multi-slot node
projection order from View Engine (to avoid breaking changes).
It basically ensures that Ivy fully matches the View Engine behavior
except of a very small edge case that has already been discussed
in FW-886 (with the conclusion of working as intended).
Read more here: https://hackmd.io/s/Sy2kQlgTE
PR Close#30561
Currently with Ivy, `ModuleWithProvider` providers are processed in order
of declaration in the `NgModule` imports. This technically makes makes
sense but is a potential breaking change as `ModuleWithProvider` providers
are processed after all imported modules in View Engine.
In order to keep the behavior of View Engine, the `r3_injector` is updated
to no longer process `ModuleWithProvider` providers egarly.
Resolves FW-1349
PR Close#30688
Due to sanitization being stored as a temp/global value between
instructions, unit tests randomly failed because one test failed
to clean up its temporary value. This patch fixes this issue.
Changed runtime i18n to define attributes with bindings, or matching directive inputs/outputs as element properties as we are supposed to do in Angular.
This PR fixes the issue where directive inputs wouldn't be trigged.
FW-1315 #resolve
PR Close#30402
Plural ICU expressions depend on the locale (different languages have different plural forms). Until now the locale was hard coded as `en-US`.
For compatibility reasons, if you use ivy with AOT and bootstrap your app with `bootstrapModule` then the `LOCALE_ID` token will be set automatically for ivy, which is then used to get the correct plural form.
If you use JIT, you need to define the `LOCALE_ID` provider on the module that you bootstrap.
For `TestBed` you can use either `configureTestingModule` or `overrideProvider` to define that provider.
If you don't use the compat mode and start your app with `renderComponent` you need to call `ɵsetLocaleId` manually to define the `LOCALE_ID` before bootstrap. We expect this to change once we start adding the new i18n APIs, so don't rely on this function (there's a reason why it's a private export).
PR Close#29249
This patch is one of the final patches to refactor the styling algorithm
to be more efficient, performant and less complex.
This patch enables sanitization support for map-based and prop-based
style bindings.
PR Close#30667
This fixes a collision between #30639 and #30543 where the latter added
usages of @ViewChild without the static flag present, but the former
made the flag required.
PR Close#30666
This patch in the second runtime change which refactors how styling
bindings work in Angular. This patch refactors how map-based
`[style]` and `[class]` bindings work using a new algorithm which
is faster and less complex than the former one.
This patch is a follow-up to an earlier refactor which enabled
support for prop-based `[style.name]` and `[class.name]`
bindings (see f03475cac8).
PR Close#30543
Depending on which placeholders the translation uses, there are some legitimate cases where we might not use all placeholder replacements in `i18nPostprocess`. For example if some of the placeholders of the original messages have been removed in the translation.
FW-1312 #resolve
PR Close#30632
With Ivy, injecting a `ViewContainerRef` for a `<ng-container>` element
results in two comments generated in the DOM. One comment as host
element for the `ElementContainer` and one for the generated `LContainer`
which is needed for the created `ViewContainerRef`.
This is problematic as developers expect the same anchor element for
the `LContainer` and the `ElementContainer` in order to be able to move
the host element of `<ng-container>` without leaving the actual
`LContainer` anchor element at the original location.
This worked differently in View Engine and various applications might
depend on the behavior where the `ViewContainerRef` shares the anchor
comment node with the host comment node of the `<ng-container>`. For
example `CdkTable` from `@angular/cdk` moves around the host element of
a `<ng-container>` and also expects embedded views to be inserted next
to the moved `<ng-container>` host element.
See: f8be5329f8/src/cdk/table/table.ts (L999-L1016)
Resolves FW-1341
PR Close#30611