TypeScript and Angular Services - javascript

When writing services in TypeScript for AngularJS do you define a model for the request and the response?
So for example, given the following service call into a RESTFul endpoint from the service:
module Application {
export module Services {
export class MyService {
public static $inject = ["$http"];
constructor(private $http: ng.IHttpService) {
}
getSomeData = (model: Models.RequestModel): ng.IPromise<Models.ResponseModel> => {
this.$http.post("url", model).then((response: ng.IHttpPromiseCallbackArg<Models.ResponseModel>) => {
return response.data;
});
}
}
}
}
So basically I am sending the RequestModel and receiving back the ResponseModel
Would that be the proper use/syntax?

So basically I am sending the RequestModel and receiving back the ResponseModel, Would that be the proper use/syntax?
Yes. Request in, promise to Response out.

Related

Angular, add a post ajax call directly into an angular service

I have some old code which does ajax calls. I wrote a new angular 10 application, which needs to run the original ajax code directly into the angular service (per requirement). Is there a way to run an ajax call directly or a node module that can be used. Thanks for the help.
#Injectable({providedIn: 'root'})
export class SomeService {
destroy$ = new Subject();
constructor(private http: HttpClient) { }
ajax(): Observable<DataType> {
return this.http
.get<DataType>(URL, {params: {email: 'tt#tt.tt'}})
.pipe(
takeUntil(this.destroy$), // will unsubscribe automatically if call this.destroy$.next(true) && this.destroy$.complete()
map(data => /*map data here if need*/)
);
}
}

How to intercept specific request

I'm using NestJS and Angular 2, both have similar (close) approach to work with Interceptors. I would like to find best practice to identify some specific request to do some additional work.
To declare Interceptor who will listen some Controller (in NestJS) I should use this logic:
#UseInterceptors(ObjectsInterceptor)
#Controller('objects')
export class ObjectsController {
#Get()
async findAll(): Promise<ObjectDto[]> {
// Request which should be intercepted
...
}
#Get(':slug')
async findOne(#Params('slug') slug: string): Promise<ObjectDto> {
// Request which shouldn't be intercepted
...
}
}
In Interceptor:
#Injectable()
export class ObjectsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> {
// Some logic to detect specific request
return next.handle();
}
}
Probably I use wrong way to solve my problem
just put decorator above method instead of class
#Get()
#UseInterceptors(ObjectsInterceptor)
async findAll(): Promise<ObjectDto[]> {
// Request which should be intercepted
...
}

Can I save data in guard before loading page

Current routing configuration:
//...
{
path: 'foo/:id',
component: SomeComponent,
canActivate: [SomeGuard]
},
//...
Then in guard I call permission service to get access for component:
#Injectable()
export class SomeGuard implements CanActivate {
constructor(private service: Service) {
}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
const id = parseInt(next.params['id']);
return this.service.getPermissions(id).then(permissions => {
if (permissions.canView) {
return true;
}
return false;
});
}
}
But in the component I utilize the same permissions endpoint, which means I call it twice in a row to get to one page:
//...
constructor(private route: ActivatedRoute,
private service: Service) {
}
ngOnInit() {
this.id = parseInt(this.route.snapshot.params['id']);
this.service.getPermissions(this.id).then(permissions => {
// ...
});
}
//...
So it would be great to just save the permissions data in the route and utilize it by both guard and the component. I tried using resolve, but it turns out resolve only activates after the guards, which is no good. So how can i save permissions data?
This looks like the kind of task for a caching service. Permissions do not change often so they are the perfect candidate for caching. That way even multiple visits to the same resource would not trigger multiple HTTP requests for permission checks.
Edit: Since you need permissions to be loaded each time, you could listen for RouteNavigationStart and clear the cache. If this becomes too cumbersome to maintain in the PermissionsService you could extract the logic into a separate service.
You could something like this in the service you use to get your permissions:
// Permissions service
private permissionCache;
constructor(
router: Router,
) {
// clear cache when a route navigation starts
router.events
.filter(event => event instanceof NavigationStart)
.subscribe(event => this.permissionCache = {})
}
getPermissions(id) {
if (permissionCache[id]) {
return Observable.of(permissionCache[id]);
} else {
// get the permissions
permissionCache[id] = response;
return Observable.of(response);
}
});

Angular 2+ http service is being called, but request is not going out

I want to be able to instantiate a model class, but also give it access to services.
For example, say I have these endpoints:
/book/:id
/book/:id/author
I want to have a BooksService service to fetch a list a Book instance. I'd like the book instances to be instantiated with new, given a definition JSON through the constructor, while still being able to use Angular dependencies.
Example of what I want to do:
BooksService.getBook(1) // makes call to /book/1
.subscribe((book) => {
book.getAuthor() // makes call to /book/1/author
...
});
To accomplish this, I tried to use a factory to new an instance of a book model. I then pass in a reference to the Http injected dependency that the factory injects.
Here's what I have:
BooksService
#Injectable()
export class BookService {
constructor(
private http: Http,
private bookModelFactory: BookModelFactory
) {}
getBook(): Observable<BookModel> {
return this.http.get('http://localhost:3000/book/1')
.map((res) => {
return this.bookModelFactory.make(res.json().data);
});
}
}
BookModel, BookModelFactory
#Injectable()
export class BookModelFactory {
constructor (private http: Http) {}
make(def: object): BookModel {
var book = new BookModel(def);
book.http = this.http;
return book;
}
}
export class BookModel {
def: any;
http: Http;
constructor (def: object) {
this.def = def;
}
getAuthor() {
console.log('http', this.http);
this.http.get('http://localhost:3000/book/1/author');
}
}
When I try to use this code, I see the console log for the http object in book.getAuthor(). It exists, and I can see the get method on it. But it never makes the API request. Nothing in the network tab has anything about a call to /book/1/author. There are no errors. Simply put, nothing happens.
Why isn't the request being made when this.http.get('...') is being called in getAuthors()?
Thanks in advance.
Using Angular 4.
(Imports statements are removed for brevity)
2) If this is a good strategy... why isn't the request being made when this.http.get('...') is being called in getAuthors()?
Because no-one ever subscribed to the results of this call:
this.http.get('http://localhost:3000/book/1/author').subscribe(res => {
// do something with the results here
});
In angular if you do not subscribe to the results of the HTTP call, then this call will never be made.
Or maybe you want your getAuthor method to return an Observable<Author> so that it is the caller of this method that can subscribe to the results:
getAuthor(): Observable<Author> {
return this.http.get('http://localhost:3000/book/1/author').map(res => {
return res.json().data;
});
}
So that you can subscribe to it later:
BooksService.getBook(1) // makes call to /book/1
.subscribe(book => {
book.getAuthor() // makes call to /book/1/author
.subscribe(author => {
// do something with the book author here
});
...
});
So remember, if you do not subscribe, the AJAX call will not be made.

Angular JS TypeScript IHttpService inject custom header value

I have a project where I make successful Http Get request from TypeScript (Angular HTTP Service) code to Web API controller and display the list in a grid. The project is using Angular JS 1.4.x and TypeScript successfully.
Full Project's GitHub URL. and the TypeScript code which calls to the server is below.
module App {
export class StudentListService {
private qService: ng.IQService;
private httpService: ng.IHttpService;
constructor($q: ng.IQService, $http: ng.IHttpService) {
this.qService = $q;
this.httpService = $http;
}
get(): ng.IPromise<Object[]> {
var self = this;
var deffered = self.qService.defer();
self.httpService.get('/api/values').then((result: any): void => {
if (result.status === 200) {
deffered.resolve(result.data);
} else {
deffered.reject(result);
}
}, error => {
deffered.reject(error);
});
return deffered.promise;
}
}
StudentListService.$inject = ['$q', '$http'];
angular.module('app').service('StudentListService', StudentListService);
}
Now, I want to add a custom header with the get request call. I have tried many ways, but TypeScript keep giving me build error. Any help or work around would be highly appreciated.
As long as you are using correct typing file for angular you should be able to add header as a part of config, second argument which is of type ng.IRequestShortcutConfig which is an extension of IHttpProviderDefaults that has the header property.
get<T>(url: string, config?: IRequestShortcutConfig): IHttpPromise<T>;
Also added much simplified code.
export class StudentListService {
static $inject = ['$q', '$http'];
constructor(private qService: angular.IQService,
private httpService: angular.IHttpService) { }
get(): angular.IPromise<Object[]> {
//Example of config structure
var config: angular.IRequestShortcutConfig = {
headers: {
"someheader":"somevalue"
}
}
//add config and just return the promise directly instead of creating a deferred object. Promises are chainable
return this.httpService.get('/api/values', config)
.then((result: any) => result.data);
//If you want to catch then use ".catch" instead of second argument to the "then" which is a better practice as any error that may happen inside your code in the then block will be caught as well.
}
}

Categories

Resources