Angular CLI class file imports must be capitalized - why? - javascript

I have created a simple class in Angular using the CLI starter. When I imported the file and tried to use the class it didn't work. It was basically just an empty object being returned. I played around trying to figure out what the issue was and decided to capitalize the file name from store to Store in the import and it works.
Class:
export class Store {
private cards: Object = {};
private previousId: number = -1;
private addCard(card: Card) {
this.cards[card['id']] = card;
return card['id'];
}
public getCard(id) {
return this.cards[id];
}
public create(text: string) {
// Do some stuff...
}
}
Class Usage:
ngOnInit() {
this.getColumsConfig();
this.store = new Store();
console.log(this.store);
}
After newing up the class I got an empty object:
I named the file store.ts, and I initially imported it as follows:
import { Store } from '../../services/store';
I then renamed the import to the following and it worked:
import { Store } from '../../services/Store';
Does anyone know why? I tried to google this but had no success.
File named in IED:

This was happening because I forgot the add the store service to the providers array.

Related

How to properly use Enums in typescript switch

I have this on one file:
export module Utils {
export enum DataSources {
SharepointList = "SharepointList",
JsonData = "JsonData"
};
}
and on another file I have this:
import CustomerDAO from "./ICustomerDAO";
import SharepointListDAOFactory from "./SharepointListDAOFactory";
import JsonDAOFactory from "./JsonDAOFactory";
import {Utils} from "./DatasourcesEnum";
export default abstract class DAOFactory{
public static SHAREPOINTLIST: number = 1;
public static REMOTEJSON : number = 2;
public abstract getCustomerDAO(): CustomerDAO;
public static getDAOFactory(whichFactory: Utils.DataSources): DAOFactory {
switch (whichFactory) {
case whichFactory.SharepointList:
return new SharepointListDAOFactory();
case whichFactory.JsonData:
return new JsonDAOFactory();
default :
return null;
}
}
}
But I get these errors:
Property 'SharepointList' does not exist on type 'DataSources'.
I'm not quite sure what the error you're getting means. It seems like you've made a mistake with your enum though. You're using the assigned value and not the enum itself in your switch statement.
public static getDAOFactory(whichFactory: Utils.DataSources): DAOFactory {
switch (whichFactory) {
case Utils.DataSources.SharepointList:
return new SharepointListDAOFactory();
case Utils.DataSources.JsonData:
return new JsonDAOFactory();
default :
return null;
}
}
The whichFactory identifier will have some value which is reflected in Utils.DataSources, and you'd want to compare the data to the enum itself. The value will not have the other datasources enum contained within itself.

Unable to get variable outside subscribe in Angular

Well, maybe my issue sounds similar to the few questions here about Angular2-EventEmitter-Subject-Observable-Subscribe-stuff... but it's quite different.
My goal (in short):
Be able to go from route ItemsList to route AddNewItem and then push on the custom 'back' button and find myself in ItemsList WITH ALL SETTINGS THAT I HAD HERE. For a example - search params. So... the only way (afaik) in Angular2+ to store that params between non-related components is to use shared service. So... My code:
ItemsList ts\html (very briefly):
export class ListComponent implements OnInit {
public addItem(allSettings: ISettingsTable) {
this._shService.returnToList = true;
this._shService.allCurrentSettings = allSettings;
this._router.navigate(['someRoute', 'add']);
}
ngOnInit() {
this._settings = {
search: /* .. */,
/* .. */
}
this._shService.getSettings().subscribe((settings: ISettingsTable) => {
this._settings = settings;
}
}
}
<button (click)='addItem(_settings)'>
<mat-icon svgIcon='add'></mat-icon>
</button>
Service (in short):
export class SettingsService {
private _returnToList: boolean;
private _settingsChanged$: Subject<ISettingsTable> = new Subject();
public emitSettings(val: ISettingsTable) {
this._settingsChanged$.next(val);
}
public getSettings(): Subject<ISettingsTable> {
return this._settingsChanged$;
}
}
AddEditItems ts\html (very briefly as well):
export class EditComponent implements OnInit {
public back(par: ISettingsTable): void {
if (this.returnToList) {
this._router.navigate(['someRoute', 'list']).then(() => {
this._shService.emitSettings(par);
});
ngOnInit() {
if (this._shService.returnToList) {
this.returnToList = true;
this._p = this._testS.allCurrentSettings;
}
}
}
<button mat-raised-button (click)='back(_p)'>Go back</button>
So! When I go to the Add route I store the current params in service. Fine. Then on the Add route I get them from service. Fine. Then when I wanna go back I pass that params to the emit method of Subject\Event Emitter... Fine! But on the List route this._settings exists only INSIDE subscribe... It's undefined outside. Yeah, I know about asynchronous behavior and stuff... But how to resolve my issue properly??? Anyone! Please. Hope I made myself clear.
EDIT...
Obviously I always on all routes have some settings. The issue is I dunno how to code If I've got some settings from observable - use them, if not - use default this._settings ...

Data object constructor not called when parsing JSON

I'm getting some data from a server and then parsing it into TypeScript classes. I'm trying use some inheritance - every class needs to be able to report its type.
Here's how that works:
This is the base class
import { PageElementType } from './page-element-type'
export class PageElement {
pageElementType: PageElementType;
constructor(aPageElementType: PageElementType) {
this.pageElementType = aPageElementType;
}
}
This is a derived class
import { PageElement } from './page-element.model'
import { PageElementType } from './page-element-type'
export class Metadata extends PageElement {
id: number;
body: string;
constructor(){
super(PageElementType.metadata);
}
}
Here's the service function I call to parse the data
getExam(){
let exam = this.http.get('http://orangeberry.hopto.org/api/Exam/1')
.map((response:Response) => <Exam>response.json())
.do(data => console.log(data));
return exam;
}
Seems like I'm getting some sort of plain objects. I want meaningful, functional objects that actually follow the class definition. What's the simplest and most straight-forward way of achieving this for my case?
A cast is only a hint for static code analysis but doesn't have any effect at runtime.
If you want the value to become an instance of a class, you need to create such an instance yourself:
.map((response:Response) => new Exam(response.json()))
where the constructor of the Exam class decomposes the JSON to its properties.

Aurelia - how to register view resources for ViewCompiler?

I have a row-based (table-like) custom element, which renders its template dynamically based on a bindable columns attribute. It composes the row template in string and uses ViewCompiler, ViewFactory and View to render.
import {inject} from 'aurelia-dependency-injection';
import {bindable, ViewCompiler, ViewResources} from 'aurelia-templating';
#inject(ViewCompiler, ViewResources)
export class MyDynamicGrid {
#bindable columns: any[];
#bindable rows: any[];
constructor(viewCompiler: ViewCompiler, viewResources: ViewResources) {
const template = '<template><custom-element></custom-element></template>'; //this is rather complex in practice
viewResources.registerElement('custom-element', /* HtmlBehaviorResource? */);
this._viewFactory = viewCompiler.compile(template, viewResources);
}
_render() : void {
const view = this._viewFactory.create(/* some container */);
view.bind(someContext, someOverrideContext);
//attach view to the DOM
}
}
This works fine, until the custom template contains standard HTML elements. Once I start putting custom elements in the template, it stops working. It still renders the HTML, but the custom element's behaviour is not being attached by Aurelia.
I'm aware, that all custom elements should be "registered" in order to be used. "Normal registration" happens either in the view via <require>, or in the view-model #viewResources, or registering it globally.
In this particular case, however, the injected ViewCompiler only inherits the view resources of the view-model's parents. My question is: how can be any additional view-resources registered? I'm aware of the second parameter in ViewCompiler's compile method, but couldn't make it work. The only way I was able to make it work, if I register it globally.
Note: this question is focusing on registering view resources. The dynamic rendering works just fine
I've found a solution by diggin into the docs+github. I've created two samples for two different approaches:
Create HtmlBehaviorResource instance manually, this is to register one specific element.
Sample (based on: https://github.com/aurelia/templating-resources/blob/master/test/repeat-integration.spec.js)
import {CustomElement} from 'my-components/my-custom-element';
import {inject, Container} from 'aurelia-dependency-injection';
import {ViewCompiler, ViewResources} from 'aurelia-templating';
import {metadata} from 'aurelia-metadata';
#inject(ViewCompiler, ViewResources, Container)
export class MyDynamicGrid {
//bindables and constructor is ommitted
init(): void {
const resource: HtmlBehaviorResource = metadata.get(metadata.resource, CustomElement);
resource.initialize(this._container, CustomElement);
resource.load(this._container, CustomElement)
.then(() => {
resource.register(this._viewResources);
this._viewFactory = viewCompiler.compile(template, this._viewResources);
});
}
}
Remark: the line resource.register(this._viewResources); is equivalent to this._viewResources.registerElement('custom-element', resource);. The only difference is the first reads the name from convention or decorator.
Use ViewEngine and import (a) whole module(s). This is more appropriate if importing multiple resources, even different types (attribute, element, converter, etc.) and from different files.
Sample:
import {CustomElement} from 'my-components/my-custom-element';
import {inject} from 'aurelia-dependency-injection';
import {ViewCompiler, ViewResources, ViewEngine} from 'aurelia-templating';
#inject(ViewCompiler, ViewResources, ViewEngine)
export class MyDynamicGrid {
//bindables and constructor is ommitted
init(): void {
this._viewEngine
.importViewResources(['my-components/my-custom-element'], [undefined], this._viewResources)
.then(() => {
this._viewFactory = viewCompiler.compile(template, this._viewResources);
});
}
}
I've found your question while struggling with the same problem, but I think I managed to make it work with resources parameter of compile. Here is my setup:
I wrapped the compilation into a helper class:
#autoinject
export class ViewFactoryHelper {
constructor(resources, viewCompiler, container, loader) {
}
compileTemplate(html, bindingContext) {
let viewFactory = this.viewCompiler.compile(html, this.resources);
let view = viewFactory.create(this.container);
view.bind(bindingContext);
return view;
}
}
And then the client looks like this:
#autoinject
export class SomethingToCreateDynamicControls {
constructor(viewFactoryHelper, myCustomConverter, anotherCustomConverter) {
viewFactoryHelper.resources.registerValueConverter('myCustomConverter', myCustomConverter);
viewFactoryHelper.resources.registerValueConverter('anotherCustomConverter', anotherCustomConverter);
}
makeControl(model) {
let html = '...'; // HTML that uses those converters in normal way
let compiledTemplate = this.viewFactoryHelper.compileTemplate(html, model);
// ...
}
}
UPDATE: So far I'm not able to call registerElement instead of registerValueConverter with desired effect, so my answer is probably not a good one yet. I'll keep trying...

Typescript, cant load internal module

I m actually learning typescript, and I m facing some problems with internal modules.
In fact, I have three files :
index.ts in which I start my app
///<reference path='RouteManager.ts'/>
import RouteManager = RestifyRouting.RouteManager;
var myManager = new RouteManager();
myManager.init("superpath");
RouteManager.ts that manage my REST routes
///<reference path='RouteParser.ts'/>
module RestifyRouting {
export class RouteManager {
routeParser:RouteParser;
constructor() {
}
public init(filePath) {
this.routeParser = new RouteParser();
this.routeParser.register("zfaf","callback");
console.log(filePath);
}
}
}
RouteParser which has to parse some string to get some informations
module RestifyRouting {
export class RouteParser {
constructor() {
}
public register(path, callback) {
console.log('super register');
}
}
}
I have a gulp file that creates my .js and d.ts files and it works great, except for the index.js file. The compiler tells my that RestifyRouting (which is my internal module) is undefined and I dont know why...
Can you help me ?
PS : every files are in the same folder, it's just a learning application.
Thanks for advance
As of TypeScript 1.5 the module syntax is aligned with ES6 module syntax and that is what I have been using as well...
You can remove any references to TypeScript modules and just export the classes directly
index.ts
import { RouteManager } from './RouteManager';
var myManager = new RouteManager();
myManager.init("superpath");
RouteManager.ts
import { RouteParser } from './RouteParser';
export class RouteManager {
routeParser:RouteParser;
constructor() {}
public init(filePath) {
this.routeParser = new RouteParser();
this.routeParser.register("zfaf","callback");
console.log(filePath);
}
}
RouteParser.ts
export class RouteParser {
constructor() {}
public register(path, callback) {
console.log('super register');
}
}
Keeping modules
If you'd like to keep using internal modules then you have to be sure to export your module as well as the classes inside the module.
// RouteManager.ts
export module RestifyRouting {
export class RouteManager{}
}
//index.ts
import { RestifyRouting } from './RouteManager';
//usage
var manager = new RestifyRouting.RouteManager();
Something to keep in mind is that you will not be able to import multiple items into the the same name.
// i.e.
import { RestifyRouting } from './RouteManager';
import { RestifyRouting } from './RouteParser';
NOTES
the {} syntax in the import statement can allow multiple imports
{ Class1, Class2 }
The {} can be skipped if you exporting a default:
//Source (foo.ts):
export default class Foo{}
//Reference:
import Foo from './foo';
//usage:
class User {
foo: Foo;
}

Categories

Resources