TypeScript: inherit from Array - arrays

I'm trying to create a rich data model for an AngularJS application and I would like for my model to inherit from Array<BaseModel>. I haven't found a way to do this (with confidence) yet.
In pseudocode this would be something like:
// NOT REAL CODE. DOES NOT WORK
class BaseModel {}
class Person extends BaseModel {}
class People extends Array<Person> {
constructor(private promise:Promise) { }
$unwrap(promise) {
promise.then((response) => {
response.data.map((person) => {
this.push(new Person(person));
});
});
}
static $load() {
/* do some ajaxy thing and unwrap the promise right onto the
the new instance of this rich model */
return new People(promise);
}
}
The reason I would like something like this is that now I can bind this model directly to my view and get updates on the fly.
Any thoughts on extending from Array?

At this point it time it is not possible to inherit from Array in TypeScript. It is best to unwrap into a public array field and use this field to bind to the UI. It resolves into the same functionality and remove the necessity of inheriting from Array.

Related

React class change in a extend the generic State/Prop

Basically I have a ViewMaster with many many Functions that gets somewhere in a wrapper => components executed
Now I want to have a different but mostly the same View that needs some extra Functions. Now 2 states are changing its type from
interface ViewState {
something:something
...
}
to
interface NewViewState extends ViewState {
change:change
}
But how am I able to do this.
My ViewMaster looks like this
class ViewMaster extends React.Component<ViewProps,ViewState>{}
and my new View
class ViewNew extends ViewMaster
But how am I able to set a new ViewState generic?
EDIT: Thinking about it, I can simply change the interface ViewState
to
interface ViewState {
change:change|something
}
But still It would be intresting to know
There are a number of ways you can do this. Given that your base component is a React Component and it already has parameterization I would do something like this:
class ViewMaster<P = ViewProps, S = ViewState> extends React.Component<P, S>{}
and then
class ViewNew extends ViewMaster<ViewProps, NewViewState>{}

TypeScript 2: Calling method of class, not object

I have found a great service for recording audio in Ionic.
But there is at least one thing that I do not understand:
For example, in line 25:
this.MediaPlugin.startRecord();
Question: Why does it call on this.MediaPlugin.startRecord() and not this.mediaPlugin.startRecord() where this.mediaPlugin is an object and MediaPlugin a class?
If the class uses this.MediaPlugin to do the actions why does it return in the get method an object?
complete code:
import { Injectable } from '#angular/core';
import { MediaPlugin } from 'ionic-native';
export enum AudioRecorderState {
Ready,
Recording,
Recorded,
Playing
}
#Injectable()
export class AudioRecorder {
mediaPlugin: MediaPlugin = null;
state: AudioRecorderState = AudioRecorderState.Ready;
get MediaPlugin(): MediaPlugin {
if (this.mediaPlugin == null) {
this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
}
return this.mediaPlugin;
}
startRecording() {
this.MediaPlugin.startRecord();
this.state = AudioRecorderState.Recording;
}
stopRecording() {
this.MediaPlugin.stopRecord();
this.state = AudioRecorderState.Recorded;
}
startPlayback() {
this.MediaPlugin.play();
this.state = AudioRecorderState.Playing;
}
stopPlayback() {
this.MediaPlugin.stop();
this.state = AudioRecorderState.Ready;
}
}
this.MediaPlugin is the reference to the get. Using this syntax, it'll construct the MediaPlugin on the first call, but use the constructed on following calls.
(This solutions seems a little weird to me too, since it'd make more sense to just use the constructor in the AudioRecorder class to init this.mediaPlugin, and then use this.mediaPlugin elsewhere)
First of all following method is a getter and I guess it's an attempt to implement readonly property with lazy initialization.
get MediaPlugin(): MediaPlugin {
if (this.mediaPlugin == null) {
this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
}
return this.mediaPlugin;
}
So when you try to access this.MediaPlugin for the first time, new instance of MediaPlugin is being created. And when you instantiate AudioRecorder and do not use it (for some reasons) it helps you to save memory not creating instance of MediaPlugin immediately. (see Lazy loading pattern)
Answering you question:
Why does it call on this.MediaPlugin.startRecord() and not
this.mediaPlugin.startRecord() where this.mediaPlugin is an object and
MediaPlugin a class?
Typescript does not provide any common mechanism of lazy loading and the way to implement it is to create private property with a getter method (as in your AudioRecorder class).
Calling this.MediaPlugin.startRecord() you kind of encapsulating creation and manipulation logic of MediaPlugin instance.
Naming conventions
Someone messed up with regards to naming conventions. The name of the property should be mediaPlugin, not MediaPlugin.
The reason that the property accessor is called MediaPlugin is that there is already a backing field called mediaPlugin.
Some would argue that the backing field should be called _mediaPlugin. Others would argue that this would go against naming conventions. If the latter is the case, you could call it mediaPluginField.
class AudioRecorder {
mediaPluginField: MediaPlugin = null;
get mediaPlugin(): MediaPlugin {
if (this.mediaPluginField === null) {
this.mediaPluginField = new MediaPlugin('../Library/NoCloud/recording.wav');
}
return this.mediaPluginField;
}
}
Dependency inversion
However, as #Vladyslav Yefremov points out, an arguably better option would be to inject the MediaPlugin dependency through the constructor or pull it from some kind of service locator.
class AudioRecorder {
constructor(private mediaPlugin: MediaPlugin) { }
}
or
class AudioRecorder {
private mediaPlugin: MediaPlugin;
constructor(mediaPlugin: MediaPlugin) {
this.mediaPlugin = mediaPlugin;
}
}
Lazy instantiation
I do not immediately see the need to instantiate the media plugin lazily, as the audio recorder needs a media plugin for all actions.
However, it could be because the media plugin has the side effect of loading the media file when instantiated. If this is the case, the media plugin property is instantiated lazily to delay the opening of the resource until it is actually needed, i.e. when the AudioRecorder is needed.

Opening error popover from service in Angular 2

I would like to create a service which will be responsible for opening bootstrap popovers with errors and success communicates. I have two components ErrorComponent, SuccessComponent and one service called CommunicatesComponent. I would like to use this service to open popover like
service.error('some error')
service.success('success!')
And this should display popover with provided text as argument. What I am doing is setting component property in service like followed and use this property in this service:
ErrorComponent
export class ErrorComponent implements OnInit {
public text:string;
#ViewChild('errorPopover') private errorPopover: NgbPopover;
constructor(private communicatesService:CommunicatesService) {
}
public ngOnInit() {
this.communicatesService.setErrorComponent(this)
}
}
Service:
#Injectable()
export class CommunicatesService {
private errorComponent:ErrorComponent
public setErrorComponent(component:ErrorComponent) {
this.errorComponent = component;
}
public error(text:string) {
console.log(this.errorComponent)
// this.errorComponent.text = text;
}
}
Unfortunitelly, it seems that my component object is not provided well, because console log prints undefined. How it should be done?
Regards
There are two things I would change in your design
ErrorComponent and CommunicatesService depends on each other. It's good to avoid it - CommunicatesService could easily work with different components. So you could create an rx Observable public property of the service, so any component can subscribe to it. When service.success('success!'), the service will send the message text to the subscribers.
In ErrorComponent, you get the popover component as a #ViewChild. You could consider binding ErrorComponent.text to the popover directly (reversing the dependency).
These changes could solve the problems you have and make the design looser - easier to understand and maintain.

Make Dart-Polymer model class reflectable without JsProxy

I have a dart server running on AppEngine and a Dart-Polymer client. The idea was to share common logic, such as the models. However, there is a little problem. Usually you would make your model-Classes extend JsProxy and than annotate all relative fields with #reflectable in order to use them in data binding. Unfortunately the model which works with AppEngine's datastore already inherits from Model. Besides that, I am not sure whether dart:js is available on the server. Hence, I have to find another way to make my model reflectable for the UI.
Annotating Project#name with #reflectable didn't work. Same empty div as output.
When including JsProxy in the model:
The built-in library 'dart:html' is not available on the stand-alone
VM.
Any ideas?
#Kind(name: 'Project', idType: IdType.Integer)
class Project extends Model {
#StringProperty(required: true)
String name;
}
#PolymerRegister('project-list')
class ProjectList extends PolymerElement {
#property List<Project> projects;
ProjectList.created() : super.created();
ready() {
fetchProjects();
}
}
<dom-module id="projects-page">
<template>
<template is="dom-repeat" items="{{projects}}">
<div>{{item.name}}</div>
</template>
</template>
</dom-module>
Output:
<div></div>
This is a known issue https://github.com/dart-lang/polymer-dart/issues/664
The best workaround so far is to use proxy objects where the annotations are applied and that wrap the shared model classes.
class FooProxy extends JsProxy implements Foo {
final Foo model;
FooProxy(this.model);
#reflectable
int get bar => model.bar;
set(int value) { model.bar = value}
}

Angular 2: Using Component Input to Pass Nested Arrays

Is there a better solution to passing complex objects to child components when the objects consist of nested arrays?
Here's my issue: in the partial html that appears in the child component, you'll have to represent nested arrays like this: {{animal.quadripeds[2].dogs[4].furColor}}
The index values are hard-coded. It'd be nicer to see it like this, for instance:
animal.quadripeds.find(q => q.isDirty == true).dogs.find(d => d.isDirty == true).furColor. Unfortunately, you can't use the .find() in {{}}
Here's a plnkr for your enjoyment: Nested Arrays via Component Input
Thanks!
You can't use find method in your template, but it does not mean that you can't use it in your component, for example :
import {Input, Component, OnInit} from 'angular2/core';
#Component(...)
export class ChildComponent implements OnInit {
#Input() transport: Transport;
private _valueToDisplay;
ngOnInit() {
this._valueToDisplay = animal.quadripeds
.find(q => q.isDirty == true)
.dogs.find(d => d.isDirty == true)
.furColor;
}
get valueToDisplay() {
return this._valueToDisplay;
    }
}
Two things:
Note that I use the OnInit interface : this is because your input property will not be initialized yet in your constructor (so be careful to implement your initialization logic in the ngOnInit function).
You probably have to handle the same logic when your input property is updated, you can implement the ngOnChanges function (or use a setter for your input property).
Here is your updated plunkr: http://plnkr.co/edit/BTzAfO6AGSLnOn8S1l24
Note that, as suggested by #dfsq, this logic should probably go in a service.

Resources