UNPKG

nestedreact

Version:

Advanced models, state management, and data binding solution for React

147 lines (118 loc) 3.64 kB
/** * Import ValueLink library * Define value links binding mixins to the Record and Collection */ import { Mixable, MixinsState, Record } from 'type-r' import { Link } from './valuelink/link' export default Link; Mixable.mixins.populate( Link as any ); interface LinksCache { [ key : string ] : RecordLink } /** * Record */ MixinsState.get( Record ).merge([{ // Link to the record's attribute by its key. linkAt( key : string ) : RecordLink { return cacheLink( getLinksCache( this ), this, key ); }, // Link to the attribute of the record's tree by symbolic path. linkPath( path : string, options? : {} ) : RecordDeepLink { return new RecordDeepLink( this, path, options ) }, // Link all (or listed) attributes and return links cache. linkAll() : LinksCache { const links = getLinksCache( this ); if( arguments.length ){ for( let i = 0; i < arguments.length; i++ ){ cacheLink( links, this, arguments[ i ] ); } } else{ const { attributes } = this; for( let key in attributes ){ attributes[ key ] === void 0 || cacheLink( links, this, key ); } } return links; } }]); /** * Link to Type-R's record attribute. * Strict evaluation of value, lazy evaluation of validation error. * Links are cached in the records */ class RecordLink extends Link< any > { constructor( public record, public attr, value ){ super( value ); } set( x ){ this.record[ this.attr ] = x; } _error? : any get error(){ return this._error === void 0 ? this.record.getValidationError( this.attr ) : this._error; } set error( x ){ this._error = x; } } class RecordDeepLink extends Link< any > { constructor( public record, public path, public options ){ super( record.deepGet( path ) ); } _error? : any get error(){ if( this._error === void 0 ){ this._error = this.record.deepValidationError( this.path ) || null; } return this._error; } set error( x ){ this._error = x; } get _changeToken(){ return this.record._changeToken; } set( x ){ this.record.deepSet( this.path, x, this.options ); } } function getLinksCache( record : Record ) : LinksCache { return ( <any>record )._links || ( ( <any>record )._links = new record.AttributesCopy( {} ) ); } function cacheLink( links : LinksCache, record : Record, key : string ) : RecordLink { var cached = links[ key ], value = record[ key ]; return cached && cached.value === value ? cached : links[ key ] = new RecordLink( record, key, value ); } /*********************************** * Collection */ MixinsState.get( Record.Collection ).merge([{ // Boolean link to the record's presence in the collection linkContains( record : Record ){ return new CollectionLink( this, record ); }, // Link to collection's property linkAt( prop : string ){ return Link.value( this[ prop ], x => this[ prop ] = x ); } }]); /** * Boolean link to presence of NestedType's record in collection. * Strict evaluation of value, no error. * Safe implementation of _changeToken. */ class CollectionLink extends Link< boolean >{ constructor( public collection, public record ){ super( Boolean( collection._byId[ record.cid ] ) ); } set( x ){ this.collection.toggle( this.record, x ); } }