diff --git a/aio/content/examples/pipes/src/app/app.module.ts b/aio/content/examples/pipes/src/app/app.module.ts
index f1d75597fcb6f5..6e864c440f6694 100644
--- a/aio/content/examples/pipes/src/app/app.module.ts
+++ b/aio/content/examples/pipes/src/app/app.module.ts
@@ -1,26 +1,23 @@
// #docregion
+import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
-import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
+import { ExponentialStrengthPipe } from './exponential-strength.pipe';
+import { FetchJsonPipe } from './fetch-json.pipe';
import {
FlyingHeroesComponent,
FlyingHeroesImpureComponent
} from './flying-heroes.component';
+import { FlyingHeroesImpurePipe, FlyingHeroesPipe } from './flying-heroes.pipe';
import { HeroAsyncMessageComponent } from './hero-async-message.component';
import { HeroBirthdayComponent } from './hero-birthday1.component';
import { HeroBirthday2Component } from './hero-birthday2.component';
import { HeroListComponent } from './hero-list.component';
-import { PowerBoosterComponent } from './power-booster.component';
import { PowerBoostCalculatorComponent } from './power-boost-calculator.component';
-import {
- FlyingHeroesPipe,
- FlyingHeroesImpurePipe
-} from './flying-heroes.pipe';
-import { FetchJsonPipe } from './fetch-json.pipe';
-import { ExponentialStrengthPipe } from './exponential-strength.pipe';
+import { PowerBoosterComponent } from './power-booster.component';
@NgModule({
imports: [
@@ -43,6 +40,6 @@ import { ExponentialStrengthPipe } from './exponential-strength.pipe';
FetchJsonPipe,
ExponentialStrengthPipe
],
- bootstrap: [ AppComponent ]
+ bootstrap: [AppComponent]
})
-export class AppModule { }
+export class AppModule {}
diff --git a/aio/content/examples/pipes/src/app/fetch-json.pipe.ts b/aio/content/examples/pipes/src/app/fetch-json.pipe.ts
index 9fcdf341e151fe..4141e19a11441e 100644
--- a/aio/content/examples/pipes/src/app/fetch-json.pipe.ts
+++ b/aio/content/examples/pipes/src/app/fetch-json.pipe.ts
@@ -1,23 +1,24 @@
// #docregion
+import { HttpClient } from '@angular/common/http';
import { Pipe, PipeTransform } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
+
// #docregion pipe-metadata
@Pipe({
name: 'fetch',
pure: false
})
// #enddocregion pipe-metadata
-export class FetchJsonPipe implements PipeTransform {
+export class FetchJsonPipe implements PipeTransform {
private cachedData: any = null;
private cachedUrl = '';
- constructor(private http: HttpClient) { }
+ constructor(private http: HttpClient) {}
transform(url: string): any {
if (url !== this.cachedUrl) {
this.cachedData = null;
this.cachedUrl = url;
- this.http.get(url).subscribe( result => this.cachedData = result );
+ this.http.get(url).subscribe(result => (this.cachedData = result));
}
return this.cachedData;
diff --git a/aio/content/guide/architecture-components.md b/aio/content/guide/architecture-components.md
index 7b8e808f352ed8..f0f2be93b685c9 100644
--- a/aio/content/guide/architecture-components.md
+++ b/aio/content/guide/architecture-components.md
@@ -40,7 +40,7 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
-* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
+* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular how provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts
index 3fc03b2f81a3c6..43d33291f3845e 100644
--- a/modules/benchmarks/src/tree/render3/tree.ts
+++ b/modules/benchmarks/src/tree/render3/tree.ts
@@ -44,8 +44,8 @@ export class TreeComponent {
s(c0);
{ T(1); }
e();
- C(2);
C(3);
+ C(4);
}
if (rf & RenderFlags.Update) {
sp(0, 0, ctx.data.depth % 2 ? '' : 'grey');
@@ -67,7 +67,7 @@ export class TreeComponent {
}
}
cr();
- cR(3);
+ cR(4);
{
if (ctx.data.right != null) {
let rf0 = V(0);
@@ -117,8 +117,8 @@ export function TreeTpl(rf: RenderFlags, ctx: TreeNode) {
s(c1);
{ T(2); }
e();
- C(3);
C(4);
+ C(5);
}
e();
}
@@ -134,7 +134,7 @@ export function TreeTpl(rf: RenderFlags, ctx: TreeNode) {
}
}
cr();
- cR(4);
+ cR(5);
{
if (ctx.right != null) {
let rf0 = V(0);
diff --git a/packages/common/src/i18n/format_date.ts b/packages/common/src/i18n/format_date.ts
index 54c41ecf0eb727..031b50e56e3bac 100644
--- a/packages/common/src/i18n/format_date.ts
+++ b/packages/common/src/i18n/format_date.ts
@@ -198,6 +198,22 @@ function formatFractionalSeconds(milliseconds: number, digits: number): string {
return strMs.substr(0, digits);
}
+/**
+ * Trim a fractional part to `digits` number of digits.
+ * Right pads with "0" to fit the requested number of digits if needed.
+ *
+ * @param num The fractional part value
+ * @param digits The width of the output
+ */
+function trimRPadFractional(num: number, digits: number): string {
+ let strNum = String(num);
+ // Add padding at the end
+ while (strNum.length < digits) {
+ strNum = strNum + 0;
+ }
+ return strNum.substr(0, digits);
+}
+
/**
* Returns a date formatter that transforms a date into its locale digit representation
*/
diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts
index a226cbb4997023..872203b3d416fe 100644
--- a/packages/core/src/render3/instructions.ts
+++ b/packages/core/src/render3/instructions.ts
@@ -15,22 +15,21 @@ import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotE
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
-import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
+import {ComponentDefInternal, ComponentQuery, ComponentTemplate, DirectiveDefInternal, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LElementNode, LNode, LProjectionNode, LTextNode, LViewNode, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node';
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
import {LQueries} from './interfaces/query';
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
-import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
+import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTEXT, CurrentMatchesList, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
-import {StylingContext, StylingIndex, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
-import {assertDataInRangeInternal, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
+import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyles as renderElementStyles, updateStyleMap as updateElementStyleMap, updateStyleProp as updateElementStyleProp} from './styling';
+import {isDifferent, stringify} from './util';
import {ViewRef} from './view_ref';
-
/**
* Directive (D) sets a property on all component instances using this constant as a key and the
* component's host node (LElement) as the value. This is used in methods like detectChanges to
@@ -1340,6 +1339,62 @@ function getStylingContext(index: number): StylingContext {
return stylingContext;
}
+/**
+ * Assign any inline style values to the element during creation mode.
+ *
+ * This instruction is meant to be called during creation mode to apply all styling
+ * (e.g. `style="..."`) values to the element. This is also where the provided index
+ * value is allocated for the styling details for its corresponding element (the element
+ * index is the previous index value from this one).
+ *
+ * (Note this function calls `elementStylingApply` immediately when called.)
+ *
+ *
+ * @param index Index value which will be allocated to store styling data for the element.
+ * (Note that this is not the element index, but rather an index value allocated
+ * specifically for element styling--the index must be the next index after the element
+ * index.)
+ * @param styles A key/value map of CSS styles that will be registered on the element.
+ * Each individual style will be used on the element as long as it is not overridden
+ * by any styles placed on the element by multiple (`[style]`) or singular (`[style.prop]`)
+ * bindings. If a style binding changes its value to null then the initial styling
+ * values that are passed in here will be applied to the element (if matched).
+ */
+export function elementStyling(index: number, styles?: (string | number)[] | null): void {
+ const tNode = load(index - 1).tNode;
+ if (!tNode.stylingTemplate) {
+ // initialize the styling template.
+ tNode.stylingTemplate = createStylingContextTemplate(styles);
+ }
+ // Allocate space but leave null for lazy creation.
+ viewData[index + HEADER_OFFSET] = null;
+ if (styles && styles.length) {
+ elementStylingApply(index);
+ }
+}
+
+/**
+ * Retrieve the `StylingContext` at a given index.
+ *
+ * This method lazily creates the `StylingContext`. This is because in most cases
+ * we have styling without any bindings. Creating `StylingContext` eagerly would mean that
+ * every style declaration such as `` would result `StyleContext`
+ * which would create unnecessary memory pressure.
+ *
+ * @param index Index of the style allocation. See: `elementStyling`.
+ */
+function getStylingContext(index: number): StylingContext {
+ let stylingContext = load
(index);
+ if (!stylingContext) {
+ const lElement: LElementNode = load(index - 1);
+ const tNode = lElement.tNode;
+ ngDevMode &&
+ assertDefined(tNode.stylingTemplate, 'getStylingContext() called before elementStyling()');
+ stylingContext = viewData[index + HEADER_OFFSET] = allocStylingContext(tNode.stylingTemplate !);
+ }
+ return stylingContext;
+}
+
/**
* Apply all styling values to the element which have been queued by any styling instructions.
*
@@ -1355,7 +1410,7 @@ function getStylingContext(index: number): StylingContext {
* index.)
*/
export function elementStylingApply(index: number): void {
- renderElementStyles(getStylingContext(index), renderer);
+ renderElementStyles(load(index - 1), getStylingContext(index), renderer);
}
/**
@@ -1412,17 +1467,12 @@ export function elementStyleProp(
* (Note that this is not the element index, but rather an index value allocated
* specifically for element styling--the index must be the next index after the element
* index.)
- * @param styles A key/value style map of the styles that will be applied to the given element.
- * Any missing styles (that have already been applied to the element beforehand) will be
- * removed (unset) from the element's styling.
- * @param classes A key/value style map of CSS classes that will be added to the given element.
- * Any missing classes (that have already been applied to the element beforehand) will be
- * removed (unset) from the element's list of CSS classes.
- */
-export function elementStylingMap(
- index: number, styles: {[styleName: string]: any} | null,
- classes?: {[key: string]: any} | string | null): void {
- updateStylingMap(getStylingContext(index), styles, classes);
+ * @param value A value indicating if a given style should be added or removed.
+ * The expected shape of `value` is an object where keys are style names and the values
+ * are their corresponding values to set. If value is null, then the style is removed.
+ */
+export function elementStyle(index: number, value: {[styleName: string]: any} | null): void {
+ updateElementStyleMap(getStylingContext(index), value);
}
//////////////////////////
diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts
index 2e3f74a8123e67..7e5a5fa0f80784 100644
--- a/packages/core/test/render3/instructions_spec.ts
+++ b/packages/core/test/render3/instructions_spec.ts
@@ -10,7 +10,7 @@ import {NgForOfContext} from '@angular/common';
import {RenderFlags, directiveInject} from '../../src/render3';
import {defineComponent} from '../../src/render3/definition';
-import {bind, container, element, elementAttribute, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, elementStylingMap, interpolation1, renderTemplate, text, textBinding} from '../../src/render3/instructions';
+import {bind, container, element, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleProp, elementStyling, elementStylingApply, interpolation1, renderTemplate, text, textBinding} from '../../src/render3/instructions';
import {InitialStylingFlags} from '../../src/render3/interfaces/definition';
import {AttributeMarker, LElementNode, LNode} from '../../src/render3/interfaces/node';
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
@@ -23,13 +23,13 @@ import {ComponentFixture, TemplateFixture} from './render_util';
describe('instructions', () => {
function createAnchor() {
elementStart(0, 'a');
- elementStyling();
+ elementStyling(1);
elementEnd();
}
function createDiv(initialStyles?: (string | number)[]) {
elementStart(0, 'div');
- elementStyling(initialStyles && Array.isArray(initialStyles) ? initialStyles : null);
+ elementStyling(1, initialStyles && Array.isArray(initialStyles) ? initialStyles : null);
elementEnd();
}
@@ -193,15 +193,15 @@ describe('instructions', () => {
it('should use sanitizer function', () => {
const t = new TemplateFixture(() => { return createDiv(['background-image']); });
t.update(() => {
- elementStyleProp(0, 0, 'url("http://server")', sanitizeStyle);
- elementStylingApply(0);
+ elementStyleProp(1, 0, 'url("http://server")', sanitizeStyle);
+ elementStylingApply(1);
});
// nothing is set because sanitizer suppresses it.
expect(t.html).toEqual('');
t.update(() => {
- elementStyleProp(0, 0, bypassSanitizationTrustStyle('url("http://server")'), sanitizeStyle);
- elementStylingApply(0);
+ elementStyleProp(1, 0, bypassSanitizationTrustStyle('url("http://server")'), sanitizeStyle);
+ elementStylingApply(1);
});
expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image'))
.toEqual('url("http://server")');
@@ -211,15 +211,15 @@ describe('instructions', () => {
describe('elementStyleMap', () => {
function createDivWithStyle() {
elementStart(0, 'div');
- elementStyling(['height', InitialStylingFlags.VALUES_MODE, 'height', '10px']);
+ elementStyling(1, ['height', InitialStylingFlags.INITIAL_STYLES, 'height', '10px']);
elementEnd();
}
it('should add style', () => {
const fixture = new TemplateFixture(createDivWithStyle);
fixture.update(() => {
- elementStylingMap(0, {'background-color': 'red'});
- elementStylingApply(0);
+ elementStyle(1, {'background-color': 'red'});
+ elementStylingApply(1);
});
expect(fixture.html).toEqual('');
});