inject breeze service in angularjs + typescript - angularjs

class Metadata {
constructor(private breeze) {
this.breeze.? // Ctrl+Space Nothing
breeze.? // Ctrl+Space Everything
}
}
angular.module('bs.breeze', ['breeze.angular']);
// do nothing but you could
// create the window.breeze object
angular.module('bs.breeze').run(['breeze', function (breeze) { }]);
//get breeze metadata by hand
angular.module("bs.breeze").factory('metadata', [ 'breeze', (breeze) => new Metadata(breeze)]);
this.breeze.? shows nothing because "private breeze" has none declared type as you can see.
breeze.? shows everything because it does reference to module breeze declared in breeze.d.ts
breeze and this.breeze are the same object
My problem here is how can use AngularJs standards injections like I'm doing in last line when I'm injecting breeze service into metadata service and then when I'm coding Metadata class how can I use "this.breeze" and have TypeScript advantages like IntelliSense.
Finally, it's possible that this.breeze can be seen as breeze module for IntelliSense purposes or exists other way to implement this scenario?.

You can use typeof to refer to the type of a module. In this case since you have the parameter named breeze, you'll need to either rename the parameter or create an import for the global symbol breeze so you can actually refer to it:
import br = breeze;
class MyClass1 {
constructor(private breeze: typeof br) {
}
}
/*** or ***/
class MyClass2 {
constructor(private br: typeof breeze) {
}
}

Related

How do I use the factory pattern if I'm migrating from Angular 1.5.8 to Angular 2?

If I'm migrating to Angular 2 and I want to use the factory pattern to create a transient dependency (a dependency that doesn't share state between components in which it gets injected), what is the best way to register a service in angular 1.5.8 with plans to migrate to ng2's way of registering services
I know in angular 2, components can reinstantiate services by passing them to the providers array, but that option doesn't exist in angular 1, and it seems like .factory is all but deprecated in angular 2 since the docs don't give it much love
An example would be a TabulationService that manages the state of which tab a user is viewing on a dashboard, which would obviously not share state between components. I would want to reinstantiate the service in each component it gets injected into. But I also want to avoid using .factory if Angular 2 best practices seem to shy away from using it.
Here is the "hack" I've resorted to, but I don't like it because even though it gets me type hinting and statelessness for my service, I can't use dependency injection in the object that gets created and i have to manage the state of my service when it gets injected and when the component in which it gets injected is destroyed (by manually clearing the service's state):
tab-manager.service.ts:
import { TabManager } from './tab-manager.class';
export class TabService {
manager;
public initialize(tabs: string[], defaultTab: string) {
this.manager = new TabManager(tabs, defaultTab);
}
}
tab-manager.class.ts:
import { includes } from 'lodash';
const mandatory = (param) => { throw new Error(`${ param } is a required field in Tab Manager!`) };
export class TabManager {
tab: string;
constructor(public tabs: string[] = mandatory(`tabs`), public defaultTab: string = mandatory('defaultTab')) {
this.checkTab(defaultTab);
this.tab = defaultTab;
}
public switchTab(tab) {
const self = this;
self.checkTab(tab);
self.tab = tab;
}
private checkTab(tab: string) {
const self = this;
if (!includes(self.tabs, tab)) {
throw new Error(`{ tab } is not a valid tab. Available tabs are ${ self.tabs.join(',') }`);
}
}
}
The service then gets initialized by importing the TabManager service from tab-manager.service.ts and calling `angular.service('TabService', TabManagerService)
There's nothing to blame Angular 2 documentation on. Angular 1 factory service is implemented in Angular 2 DI as useFactory provider.
It doesn't really matter here if it is factory or service in this case. Both serve the same purpose and share the same behaviour - they are singletons in Angular 1. Similarly, useFactory and useClass providers are singletons within the same injector in Angular 2.
To achieve the desired behaviour uniformly in both frameworks a dependency should be instantiated after injection. It doesn't really matter if this is done with factory or constructor function - they should be defined as value service in Angular 1 or useValue provider in Angular 2.
For Angular 1 it will be:
export class TabulationService { ... }
export type TTabulationService = typeof TabulationService;
...
app.value('TabulationService', TabulationService);
app.component('some', {
controller: class {
tabulationService: TabulationService;
static $inject = ['TabulationService'];
constructor (TabulationService: TTabulationService) {
this.tabulationService = new TabulationService();
}
}
});
And for Angular 2:
providers: [{ provide: TabulationService, useValue: TabulationService }]
...
#Component(...)
export class SomeComponent {
tabulationService: TabulationService;
constructor (#Inject(TabulationService) TabulationService: TTabulationService) {
this.tabulationService = new TabulationService();
}
}

Sharing data between controllers in Typescript | Angular JS

I have worked with angular js with javascript where as I know I can able to create service to share data . I am new to typescript it would be great if anyone could help us to understand how to create service in typescript to share data between controllers
The below sample service is called from the controller. Even I changed the service values when I tried redirect from other page the value is not getting changed it is having the default values. Though I am using the syntax
angular.module("app").service(...)
I believe the service is creating new instance when the controller is loaded.
export class sharedData {
public getMyProperty(): boolean {
return this._myProperty;
}
public setMyProperty(value) {
this._myProperty= value;
}
private _myProperty: boolean = false;
}
angular.module("app")
.service("sharedData", App.RfiDetail.sharedData);
I have tried with function also , but its not working
export function sharedFactory() {
return {
setStatus: setStatus,
getSuccess: getSuccess
};
function setStatus(value) {
this._myProperty = value;
}
function getSuccess() {
return this._myProperty;
}
}
angular.module(App.Constants.Modules.app)
.factory("sharedFactory", App.RfiDetail.sharedFactory);

How to access the user Token in an injected service to reencode passwords?

I have the below code where I am trying to re-encode passwords as users log in (the database has bee migrated form a legacy website). However, I'm not sure what I'm doing wrong as I keep getting errors:
Attempted to call an undefined method named "forward" of class "AppBundle\Service\HubAuthenticator".
I have set things up as follows:
security.yml
security:
encoders:
AppBundle\Entity\Member:
id: club.hub_authenticator
services.yml
services:
//This should be central service than then calls the second
club.hub_authenticator:
class: AppBundle\Service\HubAuthenticator
club.password_rehash:
class: AppBundle\Service\PasswordRehash
Hubauthenticator.php
namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
class HubAuthenticator extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
function __construct($cost=13)
{
parent::__construct($cost);
}
function isPasswordValid($encoded, $raw, $salt)
{
// Test for legacy authentication (and conditionally rehash the password stored in the database if true)
if ($this->comparePasswords($encoded, sha1("saltA".$raw."saltB"))) {
$this->forward('club.password_rehash:rehash');
}
// Test for Symfony's Bcrypt authentication (any passwords just rehashed in previous step should work here)
if (parent::isPasswordValid($cost=13, $encoded,$raw,$salt)) return true ;
}
}
PasswordRehash.php
namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
class PasswordRehash extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder
{
// Customises BCryptPasswordEncoder class to use legacy SHA method
function rehash($member, $raw, $salt)
{
//Salt is null as Symfony documentation says it is better to generate a new one
parent::encodePassword($member->getPlainPassword, $salt=null ) ;
}
}
Some other previous attempts for completeness:
My guess is that the problem is that I am misunderstanding what objects are available to me. My understanding is that the user hasn't been authenticated at this point so have tried and removed the below attempts:
Trying to inject the $member into the HubAuthenticator service:
function __construct($cost=13)
{
parent::__construct($cost, \Member $member);
}
When trying to get the plainpassword to rehash:
$this->get('security.context')->getToken()->getUser()->getPlainPassword();
In your services, you can only access what dependencies you've injected.
So, to access the current user object, you need to pass it as argument:
service:
club.password_rehash:
class: AppBundle\Service\PasswordRehash
arguments: [ "#security.token_storage" ]
Constructor:
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class HubAuthenticator extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
private $storage;
function __construct($cost = 13, TokenStorageInterface $storage)
{
parent::__construct($cost);
$this->storage = $storage;
// Now you can use:
// $user = $this->storage->getToken()->getUser();
}
}
Then, to access the second service, same way, inject it.
Add it to the service arguments:
club.password_rehash:
class: AppBundle\Service\PasswordRehash
arguments: [ "#security.token_storage", "#club.password_rehash" ]
Add it to your constructor:
private $storage;
private $passwordRehash
function __construct($cost = 13, TokenStorageInterface $storage, PasswordRehash $passwordRehash)
{
parent::__construct($cost);
$this->storage = $storage;
$this->passwordRehash = $passwordRehash;
// Now you can use:
// $this->passwordRehash->rehash(...);
}
Hope this helps you.

Restangular with Typescript confusing when 'restangularized' response object

I am using Angular 1.5.x with TypeScript. For accessing a remote API I use restangular. As a summary this is my scenario:
My API has the following resource http://localhost:53384/api/timezones. Sending a request with the verb GET to that url returns a JSON array:
[
{
"code":"Dateline Standard Time",
"name":"(UTC-12:00) International Date Line West"
},
{
"code":"UTC-11",
"name":"(UTC-11:00) Coordinated Universal Time-11"
},
{
"code":"Hawaiian Standard Time",
"name":"(UTC-10:00) Hawaii"
}
]
Now in my client AngularJs application with TypeScript:
Restangular configuration being restangularProvider: restangular.IProvider
restangularProvider.setBaseUrl("http://localhost:53384/api");
The TimeZone object representation in the client side with typescript
module app.blocks {
"use strict";
export class TimeZone {
public code: string;
public name: string;
}
}
Factory(restangular.IService) to wrap the restangular all 'timezones' resource
module app.services {
factory.$inject = ["Restangular"];
function factory(restangular: restangular.IService): restangular.IElement {
return restangular.all("timezones");
}
angular
.module("app.services")
.factory("app.services.TimeZonesRestangular", factory);
}
Service that uses TimeZonesRestangular to wrap its restangular functionality and return chained promises to whoever requests timezones in an asynchronous way
module app.services {
"use strict";
export interface IStaticDataService {
getTimeZones(): ng.IPromise<app.blocks.TimeZone[]>;
}
class StaticDataService implements IStaticDataService {
constructor(private timeZonesRestangular: restangular.IElement) {
}
public getTimeZones(): ng.IPromise<blocks.TimeZone[]> {
return this.timeZonesRestangular.getList()
.then((timeZones: blocks.TimeZone[]) => {
return timeZones;
}, (restangularError: any) => {
throw "Error retrieving time zones. Status: " + restangularError.status;
});
}
}
factory.$inject = ["app.services.TimeZonesRestangular"];
function factory(timeZonesRestangular: restangular.IElement): IStaticDataService {
return new StaticDataService(timeZonesRestangular);
}
angular
.module("app.services")
.factory("app.services.StaticDataService", factory);
}
And finally in the controller using the service to get the 'timezones' asynchronously I have this statement
//..other controller things not relevant for this sample
this.staticDataService.getTimeZones()
.then((timeZones: blocks.TimeZone[]) => {
this.timeZones = timeZones;
});
There are 2 PROBLEMS:
The type definition for restangular (which I installed with tsd install restangular --resolve --save) tells me that the successCallback in the getTimeZones() method is a promiseValue: any[], which is fine because it is indeed an array. I thought it would be an array of TimeZone[] and typescript compiles properly because it accepts any[], but when debuggin I see that the successCallback promised value it's not an array of TimeZone[]. It has the properties I expected (code and name) but it also has many other things restangular-ish. An object within that array looks like this (plus some functions):
{
"code":"Dateline Standard Time",
"name":"(UTC-12:00) International Date Line West",
"route":"timezones",
"reqParams":null,
"restangularized":true,
"fromServer":true,
"parentResource":null,
"restangularCollection":false
}
As per https://github.com/mgonto/restangular/issues/150 it looks as if my response had been "restangularized". Scary description for somebody new to restangular like myself..
What interface in restangular type definition should I use to represent the array of restangularized TimeZone[] ?
Is there any example on how to achieve something similar with TypeScript?
Thank you.
After digging a little bit further I found out that the best way to handle this is by expecting a promised value of type restangular.ICollection (which inherits from IService and Array<any>) so that I can de-restangularize the response like this:
public getTimeZones(): ng.IPromise<blocks.TimeZone[]> {
return this.timeZonesRestangular.getList()
.then((restangularizedTimeZones: restangular.ICollection) => {
return restangularizedTimeZones.plain();
}, (restangularError: any) => {
throw "Error retrieving time zones. Status: " + restangularError.status;
});
}
Now everthing seems to be fine and the response is, indeed, a promise of TimeZone[]

Register Specific Module Constructor

I would like to inject different strings into each of my module's contructors. I register a factory method which constructs the module. I can then call container.Resolve<T>() and all is well. For some reason though when Nancy tries to resolve my module it throws the error
Nancy.TinyIoc.TinyIoCResolutionException: Unable to resolve type:
Plugin.HomeModule ---> Nancy.TinyIoc.TinyIoCResolutionException:
Unable to resolve type: System.String
public class HomeModule : NancyModule
{
public HomeModule(string text)
{
}
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<HomeModule>((ctr, param) => { return new HomeModule("text"); });
HomeModule module = container.Resolve<HomeModule>();
}
I have also tried doing the registration in ConfigureRequestContainer() with the same results. I have tried container.Register<HomeModule>(new HomeModule("some text")); as well as AsSingleton(). I can register an implementation to the string type with container.Register<string>("text"), but this would inject the same string into all modules.
How can I register a module constructor so that Nancy can resolve it?
Modules are obtained through the INancyModuleCatalog, which is normally implemented by the bootstrapper, you'd have to create a custom variation of that - if you're using the default bootstrapper then this is the current implementation:
https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultNancyBootstrapper.cs#L205
The best approach for this would be to not pass in a primitive into your module, but us something richer, or perhaps a factory. The container can resolve those dependencies. Passing a plain string into the module is a sign of a problem somewhere else and a hint that your architecture probably needs rethinking
I have implemented a custom catalog that registeres only Modules of a specific namespace, but I don't know where to register this.
public CustomModuleCatalog()
{
// The license type is read from db in Global.ascx.
// So I want to register a module based on a namespace.
// The namespace is the same like the license name.
if(WebApiApplication.LicenseType == LicenseType.RouteOne)
{
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
var modules = assemblyTypes.Where(t => t.Namespace != null && t.Namespace.EndsWith("MyCustomNamespace"));
var nancy = modules.Where(t => t.IsAssignableFrom(typeof(INancyModule)));
foreach (var type in nancy)
{
var nancyType = (INancyModule)type;
_modules.Add(type, (INancyModule)Activator.CreateInstance(type));
}
}
}
public IEnumerable<INancyModule> GetAllModules(NancyContext context)
{
return _modules?.Values;
}
public INancyModule GetModule(Type moduleType, NancyContext context)
{
if (_modules != null && _modules.ContainsKey(moduleType))
{
return _modules[moduleType];
}
return null;
}

Resources