Passing global constants to angular 4 from ASP.NET MVC - asp.net-mvc

I am shifting from Razor views to Angular 4, and trying to figure out how to pass global constants from the server to Angular without relying on Ajax calls.
So the server constants will be transaction status for example:
Id: 1->Active
Id: 2-> Inactive
Id: 3->Cancelled etc
So these statuses are saved in the db and are used to query various transactions, Thus will be required in lots of components
In Razor views, I used to pass these values together with the viewmodel. But in Angular currently I can see two options:
Make Ajax calls in ngOnInit of each component that requires these constants
Make a static model to hold these values
Option 1 increases the number of server calls by quite a bit -> so I am trying to avoid this.
Option 2 will require me to change status in multiple places in my application if a new status is added for example, which i am also not fond of.
I am looking for a way to send all my constants to Angular as the application loads or page is reloaded for example.

You need to use ReplaySubject
as per rxjs documentation
ReplaySubject:Represents an object that is both an observable sequence as well as an observer. Each notification is broadcasted to all subscribed
Look at this code snippet
export class GlobalConstants{
Status:number[];
}
import { Observable, ReplaySubject } from 'rxjs';
import { GlobalConstants } from '../models/GlobalConstants';
#Injectable()
export class YourService {
//This line will cache the latest list you will get from the server
private dataSubject = new ReplaySubject<GlobalConstants>();
//you will use this observer in your components to subscribe to the getStatus result
yourStatusList$: Observable<GlobalConstants> = this.dataSubject.asObservable();
constructor(private http: Http) {
this.getStatus()
}
getStatus() {
return this.http.get('url').subscribe(res => {
this.dataSubject.next(res);
})
}
export class ExampleComponent {
public statusList;
public constructor(private _yourService: YourService) {
this.getStatus();
}
getStatus(): void {
this._yourService.yourStatusList$.subscribe(
result => {
this.statusList = result;
}
)
}
}
what will happen is when angular create the service it will call getStatus method one time per the app life cycle and then fetch your status list from the server then u will need to subscribe in your components to yourStatusList$ , for each subscrbition you will get latest cached list and if the list changed in your server u just need to call YourService.getStatus then u will fetch the status list again and all component subscribed to this observer will get notified by the new list
let's take your two challenges
1-Make Ajax calls in ngOnInit of each component that requires these constants
-by using this code your app will make one call to the server to fetch status list so u don't need to make Ajax call in ngOnInit of each component
2-Make a static model to hold these values will require me to change status in multiple places in my application if a new status is added
-if new status is added you just need to call YourService.getStatus one time in any place in your code and all components subscribed to your yourStatusList will get notified by the new status list
NOTE: you must n't use providers: [yourService] in your component cause if u used it it will create a new object and will not use the global object , just add your service in #NgModule providers and use component constructor to inject the service object

It may be best to have a service cache the information in a local variable. Then, when you inject the service into your components, and one calls a service function, the service checks the local variable. If something is in the variable, use it, if not, load the data and cache it for later use.
Since the service is a singleton, the data should only load once unless you create some mechanism to timeout the value. So, the first time the service is called, the data will be fetched. After that, the local variable (below called globals) should be used.
Service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class GlobalsService {
private globals: any;
constructor(private httpClient: HttpClient) { }
getGlobals(): any {
if (this.globals) {
return this.globals;
} else {
// call your API to get global data from DB
this.httpClient.get<any>('...').subscribe((data: any) => {
this.globals = data;
return this.globals;
});
}
}
}
Component using the service:
import { GlobalsService } from './../globals.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-tester',
templateUrl: './tester.component.html',
styleUrls: ['./tester.component.css']
})
export class TesterComponent implements OnInit {
constructor(private globalsService: GlobalsService) { }
ngOnInit() {
// Do something here with the globals from the service
const gbls = this.globalsService.getGlobals();
if (gbls) {
// ... maybe put these in a variable for later use, what ever you need
}
}
}
Doing this will keep you from having to do the Ajax call you mention, and avoid you have to keep code in more than one place. The service pattern offers a nice central place to keep this data for the lifetime of the application. All you need to do is inject the service into the component, or other services, where it is needed.

You can add you constants as attributes on your app element inside you razor view
<app someatt="{ your json data here }">Loading...</app>
then on you app's root component access them like this:
export class AppComponent implements OnInit {
constructor(
private el: ElementRef
) {
}
ngOnInit() {
console.log(this.el.nativeElement.attributes["someatt"].value);
}
}
then you can have a global service with its statuses data set here on ngOnInit and consumed in all your components

Related

Extending a Future and/or preserving await functionality

I'd like to extend the Future class and give it more functionality while keeping the functionality of the await keyword. As I understand it, Futures can't be extended directly in Dart, but perhaps there is another way to achieve what I want?
The class I'm trying to create is effectively a mechanism for interacting with an API. The server is RPC-like in the sense that its' API can be bi-directional while the request is open (messages can go back and forth between server and client until the request is considered resolved).
To make the client library more usable, I'm trying to create a Request class that has all the goodness of a normal Future, but also the ability to use a when() or on() function which effectively listens for updates during the resolution of the future.
Some sudo code of usage:
Request(args)
.when('SomeEvent', (event) => print('An update: $event'))
.then((response) => print('The final response: $response'))
.onError((err) => print('Some error: $err'));
// This also needs to work:
final response = await Request(args);
So far I have something like this, but the await keyword doesn't work:
class Request {
final Completer _completer = Completer();
Request(args) {
/* Setup and make some request to an API and respond/update using response|error|update */
}
Future<dynamic> then(fn) async {
// Should this actually return a Request?
return _completer.future.then(fn);
}
Future<dynamic> onError(fn) async {
// Should this actually return a Request?
return _completer.future.onError(fn);
}
Request when(String eventName, Function fn) {
/* attach a listener/stream which fires fn on update */
return this;
}
void _response(res) {
_completer.complete(res);
}
void _error(err) {
_completer.completeError(err);
}
void _update(upd) {
/* Some update from the request is given */
}
}
Is what I'm attempting impossible in Dart?
I'd recommend not extending the Future interface, but instead let your Request class have a future instead of being a future.
Then you can do await request.result and request.when(...), without having to re-implement the entire Future API.
If you insist on making Request be a Future, all you need is to add implements Future<Object?> to the class ... and then actually implement the entire Future API. No need to do onError (that's an extension method which works on any Future, including your Request), but you need to implement then, catchError, whenComplete, asStream and timeout correctly and totally (support all the arguments and have the correct type).
Then you'll be able to use your class with await.
If you do that, you can make those functions return Request too, if you make Request generic (class Request<T> implements Future<T>), because .then<int>(...) needs to return a Future<int>. You'd need a strategy for forwarding the when/on events to the new futures then.
It's much easier not to do that, and just expose the internal future by itself, separately from the progress callbacks.
See also CancelableOperation.

Dynamically inject repository in generic services with nestjs

I am building an authorization service for my nestjs app.
For every protected resource on my app (Media, Game, ...), I have a *RoleEntity associated (MediaRoleEntity, GameRoleEntity, ...) that defines what a user can do with a specific resource. Each one of this *RoleEntity implements RoleEntityInterface:
export interface RoleEntityInterface<T extends ResourceEntity> {
resource: T;
user: UserEntity;
role: string;
}
Each protected entity (MediaEntity, GameEntity, ...) extends ResourceEntity.
Now I want to build a generic provider RoleService, responsible for database interaction:
#Injectable()
export class RoleService<T extends ResourceEntity> {
readonly roleRepository: Repository<RoleEntityInterface<T>>;
async read(roleDto: Partial<RoleDto<T>>): Promise<RoleEntityInterface<T>> {
return this.roleRepository.findOne({
where: { ...roleDto },
});
}
async create(roleDto: RoleDto<T> | RoleDto<T>[]): Promise<void> {
await this.roleRepository.insert(roleDto);
}
}
And I want inject this service in guards, interceptors...
Problem, I don't know how to do that, more precisely:
How can I dynamically inject the roleRepository ? (I imagine some kind of factory has to be involved.)
REAL USE CASE
I want to be able to protect resources with a guard:
#Injectable()
export class RoleGuard<T extends ResourceEntity> implements CanActivate {
constructor(
private authService: AuthService,
private roleService: RoleService<T>,
private readonly reflector: Reflector,
) {}
...
}
Now in a controller, when I use
#Role('Admin')
#UseGuards(RoleGuard<MediaEntity>)
Get()
...
It would be perfect if the whole thing magically works :), ie correct roleService with correct roleRepository are properly injected.
I am completely new to nestjs and typescript (and never played with angular neither) so maybe the whole approach is wrong..

How to disable V2 OData $batch request by default in UI5?

I made a Master-Detail application in Web IDE with SAPUI5.
I connected my application to an OData service (V2). The connection parameters have been stored in manifest.json.
I want to prevent my UI5 application from using $batch requests.
I know how to use the following code to disable batch request for a particular request:
var oDataModel = this.getModel(); // sap.ui.model.odata.v2.ODataModel
oDataModel.setUseBatch(false);
But the problem is that I can not use this in onInit function.
Can I set some parameter in manifest.json to disable batch request in general and even when the program is loading it does not use $batch?
You should be able to add parameter useBatch to the settings of your model. According to the documentation (section /sap.ui5/models) these settings will be passed to the constructor.
{
"sap.ui5": {
"models": {
"yourV2ODataModel": {
"dataSource": "yourDataSource",
"settings": {
"useBatch": false
}
}
}
}
}
The availability of component models in onInit has been discussed here several times. See the application init process to see why they are not available.
Well you could to it in the onInit function. But like this:
var oDataModel = this.getOwnerComponent().getModel();
oDataModel.setUseBatch(false);
Go to Component.js
on its "init" method:
this.getModel("yourDesiredModel").setUseBatch(false)

Binding from mvc model to angular2 component (Components in mvc project)

I could use some help, figure out how to pass model data from mvc application to a angular2 component running inside mvc.
Lets say I have a cs.html file that has an component
<my-app></my-app>
This will load the angular2 component. I need to generate some binding to keep mvc models intact with my angular2 models.
First of all, I'm trying to pass a model to the component via the Input property.
CSHTML file:
In the top of my cshtml file, I have:
#model MainModel
<script>
var model = #Html.Json(Model.Form.PassengerModel);
</script>
I want to pass this model to my angular2 component.
What I have tried are:
<my-app passengerModel="model"></my-app>
Angular2 component:
import { Component, Input } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './Content/Scripts/angular2components/app.component.html',
})
export class AppComponent {
#Input() passengerModel: PassengerModel;
constructor() {
console.log("Model loaded?: " + this.passengerModel);
}
}
export class PassengerModel {
constructor(
public Adults: number,
public Children: number
) { }
}
The problem is that the model is undefined always. Is there any way to pass a model in to the component?
The problem you have outlined above is that your binding is not correct for the context you are attempting to use it in.
<my-app passengerModel="model"></my-app>
The above line is telling Angular to bind passengerModel inside your my-app component to a property on the host component named model. This means the page (component) which hosts your my-app component should be a component with a property named model. You have created a global variable which is not in the scope of your host component. Angular2 specifically isolates the scope of each component so that you do not accidentally introduce unwanted side effects.
Save yourself some pain an anguish and embrace Angular fully. Ditching your MVC Page Controllers and moving to WebApi service calls will yield better results and save you the need to translate the model manually among other issues you will run into going down the mixed route.
Considerations:
#Html.Json will ultimately cause your data to be exposed directly in your script tag. This could be a security risk if the data is sensitive and if you start using MVC Model bindings in the page alongside Angular bindings they will fight each other.
Basically these approaches are diametrically opposed as ASP.NET MVC is a server side approach and Angular is a client side approach. Mixing them in the same application will always be awkward at best.
WebApi gives you the JSON serialization more or less for free. Your MVC model is automatically serialized to JSON by the framework when returning an HttpAction. If you are trying to avoid converting your ASP.NET MVC views to Angular Components then I understand. You may not have a choice but if you do I would steer clear of mixing these two.
[HttpGet]
[AcceptVerbs["GET"]
[Route("passengers/{id:int}")]
public IHttpActionResult GetPassenger(int id)
{
// For illistration...
try
{
var passengerModel = PassengerService.LoadPassenger(id);
return Ok(passenger);
}
catch(Exception e)
{
return InternalServerError(e);
}
}
https://angular.io/docs/ts/latest/tutorial/toh-pt6.html
// I would normally put this in the environemnt class..
private passengerUrl = 'api/passengers'; // URL to web api
constructor(private http: Http) { }
getPassenger(id: number): Promise<Passenger> {
return this.http.get(`this.passengerUrl/${id}`)
.toPromise()
.then(response => response.json() as Passenger)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}

Can you only inject services into services through bootstrap?

I am trying to wire up a basic Angular2 app that uses the Http service. (Most of the tutorials I've seen do this by having a Component consume the Http service, which seems wrong unless the basic philosophy of thin controllers has changed – but that's a different question.)
I would like to create a service that uses Angular's Http service. But I can't figure out how to inject the Http service other than this:
boot.ts:
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {HTTP_PROVIDERS } from 'angular2/http';
bootstrap(AppComponent, [HTTP_PROVIDERS]);
myService.ts:
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
#Injectable()
export class aService{
constructor(http:Http){
}
/** do some stuff *//
}
This works, but it seem very wrong to require the user of the service to know the service's dependencies and be required to inject them into the bootstrap process. It seems like there should be a way to directly hand a providers array to a service the same way you can a component, but I can't find it. Am I just missing something?
Update
This way if a parent injector provides an implementation for OtherService this one is used, otherwise OtherServiceImpl is used (default).
#Injectable()
class SomeService {
OtherService _other;
SomeService(Injector injector) {
_other = injector.getOptional(OtherService);
if (_other == null) {
_other = injector.resolveAndCreateChild([
provide(OtherService, useClass: OtherServiceImpl)
]).get(OtherService);
}
_other.doSomething();
}
}
If you provide another one like
bootstrap(AppElement, [
provide(OtherService, useClass: OtherServiceImpl2)
]);
OtherServiceImpl2 is used.
See also https://github.com/angular/angular/issues/5622
Original
You could just make the http service optional (using the #Optional() annotation) and if none is provided just create an instance inside the constructor with new Http().
This way the user doesn't need to know about the services dependencies, but is able to pass alternative implementations if necessary (for example for testing).
If creating the dependeny inside the service requires DI itself, you can inject an injector and use it to get dependencies.
See also optional dependencies in http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html
What also could work (not tried myself yet) is just to create a child injector and instruct it to skip self
From the SkipSelfMetadata documentation
class Dependency {
}
#Injectable()
class NeedsDependency {
dependency;
constructor(#SkipSelf() dependency:Dependency) {
this.dependency = dependency;
}
}
var parent = Injector.resolveAndCreate([Dependency]);
var child = parent.resolveAndCreateChild([NeedsDependency]);
expect(child.get(NeedsDependency).dependency instanceof Depedency).toBe(true);
var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
expect(() => inj.get(NeedsDependency)).toThrowError();
I don't know yet if this still resolves from "self" if parent can't provide the requested type.

Resources