refactor(common): cleanup directives

This commit is contained in:
Victor Berchet 2016-09-08 19:25:25 -07:00
parent 53f0c2206d
commit c649a5c5ab
6 changed files with 57 additions and 67 deletions

View File

@ -8,7 +8,7 @@
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core'; import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
import {getTypeNameForDebugging, isBlank, isPresent} from '../facade/lang'; import {getTypeNameForDebugging} from '../facade/lang';
export class NgForRow { export class NgForRow {
constructor(public $implicit: any, public index: number, public count: number) {} constructor(public $implicit: any, public index: number, public count: number) {}
@ -91,16 +91,16 @@ export class NgFor implements DoCheck, OnChanges {
@Input() ngForOf: any; @Input() ngForOf: any;
@Input() ngForTrackBy: TrackByFn; @Input() ngForTrackBy: TrackByFn;
private _differ: IterableDiffer; private _differ: IterableDiffer = null;
constructor( constructor(
private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<NgForRow>, private _viewContainer: ViewContainerRef, private _template: TemplateRef<NgForRow>,
private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {} private _differs: IterableDiffers, private _cdr: ChangeDetectorRef) {}
@Input() @Input()
set ngForTemplate(value: TemplateRef<NgForRow>) { set ngForTemplate(value: TemplateRef<NgForRow>) {
if (isPresent(value)) { if (value) {
this._templateRef = value; this._template = value;
} }
} }
@ -108,9 +108,9 @@ export class NgFor implements DoCheck, OnChanges {
if ('ngForOf' in changes) { if ('ngForOf' in changes) {
// React on ngForOf changes only once all inputs have been initialized // React on ngForOf changes only once all inputs have been initialized
const value = changes['ngForOf'].currentValue; const value = changes['ngForOf'].currentValue;
if (isBlank(this._differ) && isPresent(value)) { if (!this._differ && value) {
try { try {
this._differ = this._iterableDiffers.find(value).create(this._cdr, this.ngForTrackBy); this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy);
} catch (e) { } catch (e) {
throw new Error( throw new Error(
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`); `Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
@ -120,9 +120,9 @@ export class NgFor implements DoCheck, OnChanges {
} }
ngDoCheck() { ngDoCheck() {
if (isPresent(this._differ)) { if (this._differ) {
const changes = this._differ.diff(this.ngForOf); const changes = this._differ.diff(this.ngForOf);
if (isPresent(changes)) this._applyChanges(changes); if (changes) this._applyChanges(changes);
} }
} }
@ -131,16 +131,16 @@ export class NgFor implements DoCheck, OnChanges {
changes.forEachOperation( changes.forEachOperation(
(item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => { (item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => {
if (item.previousIndex == null) { if (item.previousIndex == null) {
let view = this._viewContainer.createEmbeddedView( const view = this._viewContainer.createEmbeddedView(
this._templateRef, new NgForRow(null, null, null), currentIndex); this._template, new NgForRow(null, null, null), currentIndex);
let tuple = new RecordViewTuple(item, view); const tuple = new RecordViewTuple(item, view);
insertTuples.push(tuple); insertTuples.push(tuple);
} else if (currentIndex == null) { } else if (currentIndex == null) {
this._viewContainer.remove(adjustedPreviousIndex); this._viewContainer.remove(adjustedPreviousIndex);
} else { } else {
let view = this._viewContainer.get(adjustedPreviousIndex); const view = this._viewContainer.get(adjustedPreviousIndex);
this._viewContainer.move(view, currentIndex); this._viewContainer.move(view, currentIndex);
let tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForRow>>view); const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForRow>>view);
insertTuples.push(tuple); insertTuples.push(tuple);
} }
}); });
@ -150,13 +150,13 @@ export class NgFor implements DoCheck, OnChanges {
} }
for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) { for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i); let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i; viewRef.context.index = i;
viewRef.context.count = ilen; viewRef.context.count = ilen;
} }
changes.forEachIdentityChange((record: any) => { changes.forEachIdentityChange((record: any) => {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex); let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
viewRef.context.$implicit = record.item; viewRef.context.$implicit = record.item;
}); });
} }

View File

@ -8,10 +8,6 @@
import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core'; import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isBlank} from '../facade/lang';
/** /**
* Removes or recreates a portion of the DOM tree based on an {expression}. * Removes or recreates a portion of the DOM tree based on an {expression}.
* *
@ -38,18 +34,17 @@ import {isBlank} from '../facade/lang';
*/ */
@Directive({selector: '[ngIf]'}) @Directive({selector: '[ngIf]'})
export class NgIf { export class NgIf {
private _prevCondition: boolean = null; private _hasView: boolean = false;
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) { constructor(private _viewContainer: ViewContainerRef, private _template: TemplateRef<Object>) {}
}
@Input() @Input()
set ngIf(newCondition: any) { set ngIf(condition: any) {
if (newCondition && (isBlank(this._prevCondition) || !this._prevCondition)) { if (condition && !this._hasView) {
this._prevCondition = true; this._hasView = true;
this._viewContainer.createEmbeddedView(this._templateRef); this._viewContainer.createEmbeddedView(this._template);
} else if (!newCondition && (isBlank(this._prevCondition) || this._prevCondition)) { } else if (!condition && this._hasView) {
this._prevCondition = false; this._hasView = false;
this._viewContainer.clear(); this._viewContainer.clear();
} }
} }

View File

@ -6,9 +6,8 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Attribute, Directive, Host, Input, OnInit, TemplateRef, ViewContainerRef} from '@angular/core'; import {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isPresent} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization'; import {NgLocalization, getPluralCategory} from '../localization';
import {SwitchView} from './ng_switch'; import {SwitchView} from './ng_switch';
@ -79,21 +78,22 @@ export class NgPlural {
_updateView(): void { _updateView(): void {
this._clearViews(); this._clearViews();
var key = const cases = Object.keys(this._caseViews);
getPluralCategory(this._switchValue, Object.keys(this._caseViews), this._localization); const key = getPluralCategory(this._switchValue, cases, this._localization);
this._activateView(this._caseViews[key]); this._activateView(this._caseViews[key]);
} }
/** @internal */ /** @internal */
_clearViews() { _clearViews() {
if (isPresent(this._activeView)) this._activeView.destroy(); if (this._activeView) this._activeView.destroy();
} }
/** @internal */ /** @internal */
_activateView(view: SwitchView) { _activateView(view: SwitchView) {
if (!isPresent(view)) return; if (view) {
this._activeView = view; this._activeView = view;
this._activeView.create(); this._activeView.create();
}
} }
} }

View File

@ -8,10 +8,6 @@
import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core'; import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isBlank, isPresent} from '../facade/lang';
/** /**
* The `NgStyle` directive changes styles based on a result of expression evaluation. * The `NgStyle` directive changes styles based on a result of expression evaluation.
* *
@ -79,34 +75,34 @@ export class NgStyle implements DoCheck {
@Input() @Input()
set ngStyle(v: {[key: string]: string}) { set ngStyle(v: {[key: string]: string}) {
this._ngStyle = v; this._ngStyle = v;
if (isBlank(this._differ) && isPresent(v)) { if (!this._differ && v) {
this._differ = this._differs.find(this._ngStyle).create(null); this._differ = this._differs.find(v).create(null);
} }
} }
ngDoCheck() { ngDoCheck() {
if (isPresent(this._differ)) { if (this._differ) {
var changes = this._differ.diff(this._ngStyle); const changes = this._differ.diff(this._ngStyle);
if (isPresent(changes)) { if (changes) {
this._applyChanges(changes); this._applyChanges(changes);
} }
} }
} }
private _applyChanges(changes: any): void { private _applyChanges(changes: any): void {
changes.forEachRemovedItem( changes.forEachRemovedItem((record: KeyValueChangeRecord) => this._setStyle(record.key, null));
(record: KeyValueChangeRecord) => { this._setStyle(record.key, null); });
changes.forEachAddedItem( changes.forEachAddedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); }); (record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
changes.forEachChangedItem( changes.forEachChangedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); }); (record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
} }
private _setStyle(name: string, val: string): void { private _setStyle(nameAndUnit: string, value: string): void {
const nameParts = name.split('.'); const [name, unit] = nameAndUnit.split('.');
const nameToSet = nameParts[0]; value = value !== null && value !== void(0) && unit ? `${value}${unit}` : value;
const valToSet = isPresent(val) && nameParts.length === 2 ? `${val}${nameParts[1]}` : val;
this._renderer.setElementStyle(this._ngEl.nativeElement, nameToSet, valToSet); this._renderer.setElementStyle(this._ngEl.nativeElement, name, value);
} }
} }

View File

@ -9,7 +9,6 @@
import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core'; import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {ListWrapper} from '../facade/collection'; import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent, normalizeBlank} from '../facade/lang';
const _CASE_DEFAULT = new Object(); const _CASE_DEFAULT = new Object();
@ -92,10 +91,10 @@ export class NgSwitch {
// Add the ViewContainers matching the value (with a fallback to default) // Add the ViewContainers matching the value (with a fallback to default)
this._useDefault = false; this._useDefault = false;
var views = this._valueViews.get(value); let views = this._valueViews.get(value);
if (isBlank(views)) { if (!views) {
this._useDefault = true; this._useDefault = true;
views = normalizeBlank(this._valueViews.get(_CASE_DEFAULT)); views = this._valueViews.get(_CASE_DEFAULT) || null;
} }
this._activateViews(views); this._activateViews(views);
@ -128,7 +127,7 @@ export class NgSwitch {
/** @internal */ /** @internal */
_emptyAllActiveViews(): void { _emptyAllActiveViews(): void {
var activeContainers = this._activeViews; const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) { for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy(); activeContainers[i].destroy();
} }
@ -138,7 +137,7 @@ export class NgSwitch {
/** @internal */ /** @internal */
_activateViews(views: SwitchView[]): void { _activateViews(views: SwitchView[]): void {
// TODO(vicb): assert(this._activeViews.length === 0); // TODO(vicb): assert(this._activeViews.length === 0);
if (isPresent(views)) { if (views) {
for (var i = 0; i < views.length; i++) { for (var i = 0; i < views.length; i++) {
views[i].create(); views[i].create();
} }
@ -148,8 +147,8 @@ export class NgSwitch {
/** @internal */ /** @internal */
_registerView(value: any, view: SwitchView): void { _registerView(value: any, view: SwitchView): void {
var views = this._valueViews.get(value); let views = this._valueViews.get(value);
if (isBlank(views)) { if (!views) {
views = []; views = [];
this._valueViews.set(value, views); this._valueViews.set(value, views);
} }
@ -160,7 +159,7 @@ export class NgSwitch {
_deregisterView(value: any, view: SwitchView): void { _deregisterView(value: any, view: SwitchView): void {
// `_CASE_DEFAULT` is used a marker for non-registered cases // `_CASE_DEFAULT` is used a marker for non-registered cases
if (value === _CASE_DEFAULT) return; if (value === _CASE_DEFAULT) return;
var views = this._valueViews.get(value); const views = this._valueViews.get(value);
if (views.length == 1) { if (views.length == 1) {
this._valueViews.delete(value); this._valueViews.delete(value);
} else { } else {

View File

@ -122,7 +122,7 @@ export declare class NgFor implements DoCheck, OnChanges {
ngForOf: any; ngForOf: any;
ngForTemplate: TemplateRef<NgForRow>; ngForTemplate: TemplateRef<NgForRow>;
ngForTrackBy: TrackByFn; ngForTrackBy: TrackByFn;
constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef<NgForRow>, _iterableDiffers: IterableDiffers, _cdr: ChangeDetectorRef); constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForRow>, _differs: IterableDiffers, _cdr: ChangeDetectorRef);
ngDoCheck(): void; ngDoCheck(): void;
ngOnChanges(changes: SimpleChanges): void; ngOnChanges(changes: SimpleChanges): void;
} }
@ -130,7 +130,7 @@ export declare class NgFor implements DoCheck, OnChanges {
/** @stable */ /** @stable */
export declare class NgIf { export declare class NgIf {
ngIf: any; ngIf: any;
constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef<Object>); constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<Object>);
} }
/** @experimental */ /** @experimental */