Extending factories in AngularJS TypeScript - javascript

I want to extend a angular factory with typescript, so I can have a specific factory, but it gives me an error when I try to run it.
module App.Services {
export interface IShared {
documents: Array<any>;
}
export class Shared implements IShared {
public static serviceId = "shared";
datacontext: App.Services.IDatacontext;
documents: Array<any>;
constructor(datacontext: App.Services.IDatacontext) {
this.datacontext = datacontext;
this.datacontext.getDocuments().success((documents) => {
this.documents = documents;
});
}
}
editorApp.factory(Shared.serviceId, ['datacontext',
(datacontext) => new Shared(datacontext)
]);
}
I want to extend the Shared class to the following class
module App.Services {
export interface ITemplateShared extends IShared {
}
export class TemplateShared extends Shared implements ITemplateShared {
public static serviceId = "templateShared";
datacontext: App.Services.IDatacontext;
constructor(datacontext) {
super(datacontext);
//this.datacontext = datacontext;
}
}
editorApp.factory(TemplateShared.serviceId, ['datacontext', 'shared',
(datacontext) => new TemplateShared(datacontext)
]);
}
When I start it gives me an Unhandled exception at line 6, column 5 in templateShared.js
Thanks in advance!

class TemplateShared extends Shared
Most likey issue: make sure Shared is loaded by the browser before TemplateShared. The order of loading in JavaScript / TypeScript is important.
I recommend using external modules to avoid this mistake : https://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1

Related

Is there any way I can Inject my Service class in a non Service annotated classes in NodeJs?

This ABCService class perform some initialization on service startup
class ABCService {
public init() : void {
some stuff...
}
export const service = new ABCService();
I am using this class as loader
import { MicroframeworkLoader, MicroframeworkSettings } from 'microframework-w3tec';
import { service } from '../ABCService';
export const serviceLoader: MicroframeworkLoader = (settings: MicroframeworkSettings | undefined) => {
service.init();
};
I am using this serviceLoader in bootstrapMicroframework loaders of APP.ts file.
bootstrapMicroframework({
loaders: [
serviceLoader
],
}).then(() => ... )
.catch(error => log.error('Application is crashed: ' + error));
Now I have another Service class annotated with #Service
#Service()
export public class XYZService {
constructor(private userRepository: UserRepository, private dependency2: Dependency2){
}
public doSomeThing(): Promise<any> {
....
....
}
}
I want to inject this XYZService class in ABCService with all dependencies in XYZService being injected by the container. How can I achieve that?
I got to know that It's possible to get an instance of a service class in a non service classes using typedi's
Container.get<ServiceClassType>(ServiceClassType);

Angular Unable to Init Service (HttpClient) in a Class

I want to isolate http interactions by creating data access objects from a class so that in a component I might simply get data like this:
// dashboard.component
import { AppUser } from './appuser.service'
export class DashboardComponent implements OnInit {
user: AppUser = new AppUser();
constructor() { }
ngOnInit() {
let id = JSON.parse(window.localStorage.getItem('session')).userId;
this.user.find(id) // 'find' is from base class
.subscribe(
// handle user data
);
}
}
I have defined a base class and a sub class like this:
// base-resource.service
import { HttpClient } from '#angular/common/http';
...
export class BaseResource {
private fullpath: string;
protected http: HttpClient;
constructor (path: string) {
this.fullpath = path;
}
find (id): Observable<Object> {
return this.http.get(this.fullpath + '/' + id); // this line throws Error!
}
}
// app-user.service
...
export class AppUser extends BaseResource {
constructor(data?) {
super('api/appusers');
}
}
However this generates an error: ERROR TypeError: Cannot read property 'get' of undefined from within the base class function.
My 'AppUser' instance is clearly inheriting find from 'BaseResource', but find is picking up the 'AppUser' instance as the value of this and http is not available. I have tried declaring http as public and private as well as protected, but that had no effect. I imagine I'm missing some bigger picture of how to extend classes.
As specifically as possible, i think my question is in how to abstract functions to a base class when they need access to the base class's context.
(using Angular 6.0.4)
EDIT
I updated the title as it became clear that this is a problem of instantiating the HttpClient service in a class.
The error is because nothing is instantiating HttpClient, so it is undefined when you come to use it.
You should inject HttpClient into AppUser, and pass it into BaseResource via the constructor
export class AppUser extends BaseResource {
constructor(HttpClient http) {
super(http, 'api/appusers');
}
}
And in base-resource.service
import { HttpClient } from '#angular/common/http';
...
export class BaseResource {
private fullpath: string;
protected http: HttpClient;
constructor (httpClient: HttpClient, path: string) {
this.fullpath = path;
this.http = httpClient;
}
find (id): Observable<Object> {
return this.http.get(this.fullpath + '/' + id); // this line throws Error!
}
}

TypeScript: class composition

Based on this awesome Composition over Inheritance video by MPJ, I've been trying to formulate composition in TypeScript. I want to compose classes, not objects or factory functions. Here is my effort so far (with a little help from lodash):
class Barker {
constructor(private state) {}
bark() {
console.log(`Woof, I am ${this.state.name}`);
}
}
class Driver {
constructor(private state) {}
drive() {
this.state.position = this.state.position + this.state.speed;
}
}
class Killer {
constructor(private state) {}
kill() {
console.log(`Burn the ${this.state.prey}`);
}
}
class MurderRobotDog {
constructor(private state) {
return _.assignIn(
{},
new Killer(state),
new Driver(state),
new Barker(state)
);
}
}
const metalhead = new MurderRobotDog({
name: 'Metalhead',
position: 0,
speed: 100,
prey: 'witch'
});
metalhead.bark(); // expected: "Woof, I am Metalhead"
metalhead.kill(); // expected: "Burn the witch"
This resulting in:
TS2339: Property 'bark' does not exist on type 'MurderRobotDog'
TS2339: Property 'kill' does not exist on type 'MurderRobotDog'
What's the right way of doing class composition in TypeScript?
Composition vs Inheritance
I think we should make a distinction between composition and inheritance and reconsider what we are trying to achieve. As a commenter pointed out, what MPJ does is actually an example of using mixins. This is basically a form of inheritance, adding implementation on the target object (mixing).
Multiple inheritance
I tried to come up with a neat way to do this and this is my best suggestion:
type Constructor<I extends Base> = new (...args: any[]) => I;
class Base {}
function Flies<T extends Constructor<Base>>(constructor: T = Base as any) {
return class extends constructor implements IFlies {
public fly() {
console.log("Hi, I fly!");
}
};
}
function Quacks<T extends Constructor<Base>>(constructor: T = Base as any) {
return class extends constructor implements ICanQuack {
public quack(this: IHasSound, loud: boolean) {
console.log(loud ? this.sound.toUpperCase() : this.sound);
}
};
}
interface IHasSound {
sound: string;
}
interface ICanQuack {
quack(loud: boolean): void;
}
interface IQuacks extends IHasSound, ICanQuack {}
interface IFlies {
fly(): void;
}
class MonsterDuck extends Quacks(Flies()) implements IQuacks, IFlies {
public sound = "quackly!!!";
}
class RubberDuck extends Quacks() implements IQuacks {
public sound = "quack";
}
const monsterDuck = new MonsterDuck();
monsterDuck.quack(true); // "QUACKLY!!!"
monsterDuck.fly(); // "Hi, I fly!"
const rubberDuck = new RubberDuck();
rubberDuck.quack(false); // "quack"
The benefit of using this approach is that you can allow access to certain properties of the owner object in the implementation of the inherited methods. Although a bit better naming could be use, I see this as a very potential solution.
Composition
Composition is instead of mixing the functions into the object, we set what behaviours should be contained in it instead, and then implement these as self-contained libraries inside the object.
interface IQuackBehaviour {
quack(): void;
}
interface IFlyBehaviour {
fly(): void;
}
class NormalQuack implements IQuackBehaviour {
public quack() {
console.log("quack");
}
}
class MonsterQuack implements IQuackBehaviour {
public quack() {
console.log("QUACK!!!");
}
}
class FlyWithWings implements IFlyBehaviour {
public fly() {
console.log("I am flying with wings");
}
}
class CannotFly implements IFlyBehaviour {
public fly() {
console.log("Sorry! Cannot fly");
}
}
interface IDuck {
flyBehaviour: IFlyBehaviour;
quackBehaviour: IQuackBehaviour;
}
class MonsterDuck implements IDuck {
constructor(
public flyBehaviour = new FlyWithWings(),
public quackBehaviour = new MonsterQuack()
) {}
}
class RubberDuck implements IDuck {
constructor(
public flyBehaviour = new CannotFly(),
public quackBehaviour = new NormalQuack()
) {}
}
const monsterDuck = new MonsterDuck();
monsterDuck.quackBehaviour.quack(); // "QUACK!!!"
monsterDuck.flyBehaviour.fly(); // "I am flying with wings"
const rubberDuck = new RubberDuck();
rubberDuck.quackBehaviour.quack(); // "quack"
As you can see, the practical difference is that the composites doesn't know of any properties existing on the object using it. This is probably a good thing, as it conforms to the principle of Composition over Inheritance.
Unfortunately, there is no easy way to do this. There is currently a proposal to allow for the extends keyword to allow you to do this, but it is still being talked about in this GitHub issue.
Your only other option is to use the Mixins functionality available in TypeScript, but the problem with that approach is that you have to re-define each function or method that you want to re-use from the "inherited" classes.

Typescript module export not work when import something

I trying to create PowerBI custom visual and i must use typescript for that. I'm not too familiar with typescript. So I got 2 ts files under same namespace(I using VS Code editor):
visual.ts
module powerbi.extensibility.visual {
export class Visual implements IVisual {
private target: HTMLElement;
private updateCount: number;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.target = options.element;
this.updateCount = 0;
}
public update(options: VisualUpdateOptions) {
console.log('Visual update', options);
console.log(testFunc());
$('#datepicker').datepicker();
this.target.innerHTML = `<p>Update count: <em>${(this.updateCount++)}</em></p>`;
}
public destroy(): void {
//TODO: Perform any cleanup tasks here
}
}
}
test.ts
import React=require('react');
import ReactDOM=require('react-dom');
module powerbi.extensibility.visual {
export function testFunc():String{
return "Test string";
}
export class TestClass{}
}
Problem is when there is no imports in test.ts i can see and use exported function "testFunc()"(VS Code see that function) but when i add imports i cant user that function(also VS Code don't recognize that function)? Is there any way to have imports and to use that function?

Node.js v6.2.0 class extends is not a function error?

So I'm trying to extend a class in node js and the compiler keeps returning the following error:
TypeError: Class extends value #<Object> is not a function or null
I checked that I was exporting the class correctly and I am, any ideas? I'll post my code below:
/handler/venue.js:
var VenueViews = require('../views/venue'); // If I remove this the error will dissapear (as expected)
class Venue {
constructor(data) {
this.setDataHere = data;
}
main () {
var View = new VenueViews(); // This doesn't run
}
}
module.exports = Venue;
/views/venue.js:
var Venue = require('../handlers/venue');
console.log (Venue) // This returns {} ???
class VenueViews extends Venue {
constructor() {
super();
}
}
module.exports = VenueViews;
I know that node supports these es6 features, so I'm unsure why they aren't working?
Edit:
I'm not sure if this is suppose to happen but, when I log my Venue require it returns an empty object {}.
console.log (Venue) // This returns {} ???
So it turns out I had a circular reference in my code, where I was importing the class that was extending, into the class that itself was extending (tongue twister :P).
The obvious fix was to simply remove the extends reference and find another way of doing what I was trying to achieve. In my case it was passing the Venue class properties down into the VenueViews constructor.
E.g var x = VenueViews(this)
In my instance, it was the same issue as #James111 was experiencing (circular import) due to a factory pattern I was trying to set up in Typescript. My fix was to do move the code into files, similar to the following:
// ./src/interface.ts
import { ConcreteClass } from './concrete';
export interface BaseInterface {
someFunction(): any;
}
export class Factory {
static build(): BaseInterface {
return new ConcreteClass();
}
}
// ./src/base.ts
import { BaseInterface } from './interface';
class BaseClass implements BaseInterface {
someFunction(): any {
return true;
}
}
// ./src/concrete.ts
import { BaseClass } from './base';
export class ConcreteClass extends BaseClass {
someFunction(): any {
return false;
}
}
I had faced similar issue, after checking all the workaround finally issue got resolved by deleting the node_modules folder and run npm i.

Categories