Skip to content

Commit

Permalink
Merge pull request #423 from TAMULib/sprint20-ngbindings
Browse files Browse the repository at this point in the history
Sprint20 ngbindings
  • Loading branch information
wwelling committed Sep 17, 2021
2 parents e0866e5 + b291a26 commit b24357c
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 4 deletions.
34 changes: 34 additions & 0 deletions projects/wvr-elements/src/lib/core/ng-bindings.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ChangeDetectorRef, Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

export interface CdRefBindingSubject {
subject: BehaviorSubject<any>;
cdRef: ChangeDetectorRef;
}

/**
* A registry for AngularJS binding subjects.
*/
@Injectable({
providedIn: 'root'
})
export class NgBindingsService {

private readonly subjects: { [key: string]: Array<CdRefBindingSubject> };

constructor() {
this.subjects = {};
}

putSubject(key: string, subject: CdRefBindingSubject): Array<CdRefBindingSubject> {
let subjects = this.subjects[key];
if (!subjects) {
subjects = [];
this.subjects[key] = subjects;
}
this.subjects[key].push(subject);

return this.subjects[key];
}

}
2 changes: 2 additions & 0 deletions projects/wvr-elements/src/lib/core/wvr-core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { AnimationService } from './animation.service';
import { ComponentRegistryService } from './component-registry.service';
import { LayoutEffects } from './layout/layout.effects';
import { ManifestEffects } from './manifest/manifest.effects';
import { NgBindingsService } from './ng-bindings.service';
import { RestEffects } from './rest/rest.effects';
import { metaReducers, ROOT_REDUCER } from './store';
import { ThemeEffects } from './theme/theme.effects';
Expand Down Expand Up @@ -101,6 +102,7 @@ const PROVIDERS = [
AnimationService,
ActionRegistryService,
ComponentRegistryService,
NgBindingsService,
ThemeService
];

Expand Down
77 changes: 74 additions & 3 deletions projects/wvr-elements/src/lib/shared/wvr-base.component.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { AfterContentInit, Directive, ElementRef, EventEmitter, HostBinding, Injector, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { AfterContentInit, ChangeDetectorRef, Directive, ElementRef, EventEmitter, HostBinding, Injector, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { select, Store } from '@ngrx/store';
import * as JSON5 from 'json5';
import { Observable, Subscription } from 'rxjs';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { AnimationService } from '../core/animation.service';
import { ComponentRegistryService } from '../core/component-registry.service';
import { WvrDataSelect } from '../core/data-select';
import * as ManifestActions from '../core/manifest/manifest.actions';
import { NgBindingsService } from '../core/ng-bindings.service';
import { RootState, selectIsMobileLayout, selectManifestEntryResponse } from '../core/store';
import { ThemeService } from '../core/theme/theme.service';
import { AppConfig, APP_CONFIG } from './config';
import { ThemeVariantName } from './theme';
import { wvrParseProjectedContent } from './utility';
import { WvrAnimationComponent } from './wvr-animation.component';
import { WvrDataComponent } from './wvr-data.component';
import { WvrThemeableComponent } from './wvr-themeable.component';
import { wvrParseProjectedContent } from './utility';

@Directive()
// tslint:disable-next-line:directive-class-suffix
Expand All @@ -29,6 +30,9 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe
/** A reference to the ElementRef */
readonly eRef: ElementRef;

/** A reference to the ChangeDetectorRef */
readonly cdRef: ChangeDetectorRef;

/** A reference to the AppConfig */
readonly appConfig: AppConfig;

Expand Down Expand Up @@ -91,6 +95,9 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe
/** A reference to the ThemeService */
private readonly themeService: ThemeService;

/** A reference to the NgBindingsService */
private readonly ngBindingsService: NgBindingsService;

/** A host bound accessor which applies the wvr-hidden class if both isMobileLayout and hiddenInMobile evaluate to true. */
@HostBinding('class.wvr-hidden') private get _hiddenInMobile(): boolean {
return this.isMobileLayout && this.hiddenInMobile;
Expand All @@ -104,6 +111,12 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe

isMobileLayout: boolean;

private _ngBindings: { [key: string]: string };

@Input() set ngBindings(value: string) {
this._ngBindings = JSON5.parse(value);
}

isMobile: Observable<boolean>;

protected subscriptions: Array<Subscription>;
Expand All @@ -114,12 +127,15 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe
this.id = this.componentRegistry.register(this);

this.eRef = injector.get(ElementRef);
this.cdRef = injector.get(ChangeDetectorRef);
this.appConfig = injector.get(APP_CONFIG);
this.store = injector.get<Store<RootState>>(Store);

this._animationService = injector.get(AnimationService);
this.themeService = injector.get(ThemeService);

this.ngBindingsService = injector.get(NgBindingsService);

const element = (this.eRef.nativeElement as HTMLElement);
const htmlIDAttrName = element.hasAttribute('id') ? 'wvr-id' : 'id';
element.setAttribute(htmlIDAttrName, `${ComponentRegistryService.HTML_ID_BASE}-${this.id}`);
Expand All @@ -143,6 +159,7 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe
/** Used for post content initialization animation setup. */
ngAfterContentInit(): void {
this.initializeAnimationElement();
this.bootstrapNgBindings();
}

/** Handles the the unregistering of this component with the component registry. */
Expand All @@ -155,6 +172,60 @@ export abstract class WvrBaseComponent implements AfterContentInit, OnInit, OnDe
});
}

bootstrapNgBindings(): void {
if (!!this._ngBindings) {
const win = window as any;
let elem = this.eRef.nativeElement;

for (const [k, v] of Object.entries(this._ngBindings)) {
let ngScope;

while (!ngScope && elem.tagName !== 'BODY') {
const ngElem = win.angular.element(elem);
if (ngElem.scope() && ngElem.scope().hasOwnProperty(k)) {
ngScope = ngElem.scope();
break;
}
elem = elem.parentElement;
if (elem.tagName === 'BODY') {
console.warn(`${k} not found on ng scope`);
}
}

if (!!ngScope) {
const subject = new BehaviorSubject<any>(ngScope[k]);

const references = this.ngBindingsService.putSubject(k, {
subject,
cdRef: this.cdRef
});

if (references.length === 1) {
Object.defineProperty(ngScope, k, {
get: () => subject.getValue(),
set: (value: any) => {
references.forEach((sub) => {
sub.subject.next(value);
sub.cdRef.detectChanges();
});
}
});
}

Object.defineProperty(this, v, {
get: () => subject.getValue(),
set: (value: any): void => {
if (value !== subject.getValue()) {
subject.next(value);
ngScope.$apply();
}
}
});
}
}
}
}

applyThemeOverride(customProperty: string, value: string): void {
this.themeOverrides[customProperty] = value;
this.eRef.nativeElement.style.setProperty(customProperty, value);
Expand Down
3 changes: 2 additions & 1 deletion projects/wvr-elements/src/lib/wvr-text/wvr-text.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

/* TODO: Issue #292. */
import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular/core';
import { WvrBaseComponent } from '../shared/wvr-base.component';
import { ThemeVariantName } from '../shared/theme';

/**
Expand All @@ -13,7 +14,7 @@ import { ThemeVariantName } from '../shared/theme';
styleUrls: ['./wvr-text.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class WvrTextComponent {
export class WvrTextComponent extends WvrBaseComponent {

/** The text value to be displayed in the text node. */
@Input() value: string;
Expand Down

0 comments on commit b24357c

Please sign in to comment.