Nativescript: how to store HTTP values to public variables - javascript

I have some problem here, I'm using a mix of Angular2 and Nativescript's native JS to use HTTP because I was having problems with Angular2 HTTP before this implementation, but I'm having frustration on how to put the JSON response from the http request to the monthList variable so it can be read all over the place. Please help, Thank you.
Here's my code:
public monthList = [];
constructor(location: Location, private page: Page, private router: Router, private testing: any) {
this.router = router;
this.testing = testing;
let http = require("http");
http.getJSON("link")
.then(function (r) {
// Argument (r) is JSON!
}, function (e) {
// Argument (e) is Error!
console.log(e);
});
}

Inside your .then you set your return object to your monthList
this.monthList = r;
Try doing a console.dump(r) and see what is being returned. You may have to do something like r.xxx or however it is structured.
Then you can probably do something like
this.monthList.month
and access the data of the month and so forth. Or you maybe have to do something like
this.monthList[0].month.
For example in my project I have a JSON object coming back that is nested and I need to set it as something like r.value.data.

Is there a specific issue you're running into? I would think its as simple as:
class SomeAngularClass {
constructor() {
http.getJSON("link")
.then(function(r) {
this.monthList.push(r);
}, function (e) {
console.log(e);
});
}
}
And then you could access it via:
SomeAngularClass().monthList;

Related

Angular2 observable with JSON root element

This is my first time ever working with angular observables and I'm a bit confused on how this works. I was given a mostly functioning angular CLI app that I just need to wire up to my already existing API.
I have a service with this function
public getApps(): Observable<ApplicationInterface[]> {
return this.http.get(url);
}
Then in my component, I have
public data: ApplicationInterface[];
ngOnInit() {
this.route.params
.subscribe(params => {
this.fetchData();
});
}
fetchData() {
this.service.getApps()
.subscribe(data => {
this.data = data;
});
}
My api endpoint returns a JSON structure of {"applications": []}
I can't seem to figure out how to access the array in that JSON hash.
If I console.log(data) in the subscribe block, it is the API response with the applications key that I expect, but if I change the data assignment to this.data = data.applications, ng build fails with Property 'applications' does not exist on type 'ApplicationInterface[]'
You should design the interface to be aligned with the response. If the response is object, than you need to have it like this also in the interface.
Try something like this (using the new HttpClient):
interface ApplicationInterfaceResponse {
applications: ApplicationInterface[];
}
public getApps(): Observable<ApplicationInterface[]> {
return this.httpClient
.get<ApplicationInterfaceResponse>(url)
.map(response => {
console.log(response.applications);
return data.applications;
});
}
If your return is of type ApplicationInterface[], then it's an array of ApplicationInterfaces, thus does not have a property called applications on it. This has nothing to do with your observable; it's fine. Rather, you've mistyped your variable.
If you don't need any other properties of data, you can map the value:
public getApps(): Observable<ApplicationInterface[]> {
return this.http.get(url).map(data => data.applications);
}
However, I recommend against this in most situations. If your object changes in the future, then you have to change this function and all attached subscriptions. Instead, you should create an interface for your response (your response right now does not match the type you're giving it), and use values of it as necessary.
The simplest fix is to indicate the correct form of the data that is returned by your service method since it doesn't actually return an array:
public getApps(): Observable<{applications:ApplicationInterface[]}> {
return this.http.get(url);
}
Now in your subscribe, you can get at the array as you would expect
.subscribe(e => this.data = e.applications)

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.
}
}

Can't get Injected Ember Service from Ember Controller - But works on models & adapters

I'm running into an issue with an Ember CLI project where I can't get an injected ember service from a controller action function.
The really strange thing is that this totally works on my models and custom adapters:
the controller:
export default Ember.Controller.extend({
node: Ember.inject.service(),
azureStorage: Ember.computed.alias('node.azureStorage'),
actions: {
myAction: function () {
// this returns null
var x = this.get('azureStorage');
}
}
});
// The service code (azureStorage and fs are NOT null)
if (window.requireNode) {
azureStorage = window.requireNode('azure-storage');
fs = window.requireNode('fs');
}
export default Ember.Service.extend({
azureStorage: azureStorage,
fs: fs,
getActiveAccount: function (store) {
return new Ember.RSVP.Promise(function (resolve, reject) {
var accounts = store.all('account'),
length = accounts.get('length'),
i = 0;
accounts.forEach(function (account) {
if (account.get('active') === true) {
return Ember.run(null, resolve, account);
}
i += 1;
if (i >= length) {
return Ember.run(null, reject, 'could not find any active accounts');
}
});
});
}
});
// the controller test code
var controller = this.subject();
controller.send('myAction');
I would have expected this to return the service and the azureStorage object. On my models & adapters the same pattern works just fine:
export default DS.Adapter.extend({
serializer: serializer.create(),
node: Ember.inject.service(),
azureStorage: Ember.computed.alias('node.azureStorage'),
findQuery: function () {
// this returns the value correctly
var x = this.get('azureStorage');
}
});
Any reason this would work on models & adapters but NOT on a controller?
I'm not familiar with the Ember.inject.service() pattern, but is there a reason you're not using the pattern outlined in http://guides.emberjs.com/v1.10.0/understanding-ember/dependency-injection-and-service-lookup/ ?
Also, why are you injecting node and azureStorage into the controller if you've already abstracted them into an adapter? You should just be using this.store.find('whatever', 123) from the controller to get your data. If your azureStore is different than your normal Ember Data store, then you should create a new store and register it with the application's container. If you inject it in your controller, you can access it with this.azureStore, or alternatively this.container.lookup('store:azure').
Also, not a good practice to start injecting stuff into your models. I would really take a look at the Ember-friendly ways of doing service/dependency injection, because this doesn't look very elegant and you're duplicating a lot of code to get access to something you already have.

sails.js access controller method from controller method

How come in sails you cannot access other controller methods from within another one?
like this.
module.exports =
findStore: ->
# do somthing
index: ->
#findStore(); # Error: undefined
Compiled
module.exports = {
findStore: function() {},
index: function() {
return this.findStore(); // Error: undefined
}
};
If you can't do this, then why not? how else should I be doing this...
You can use sails.controllers.yourControllerName.findStore()
the sails global object has references to almost everything.
One of the best ways to organize your code in Sails, at least for me and my team, has been to have all the real business logic in Services (/api/services). Those objects can be accessed globally from any controller.
Also, a good practice is working with promises in services (as Sails use them on the model methods)
Just create a Store service (StoreService.js), with your code:
module.exports = {
findStore: function(storeId) {
// here you call your models, add object security validation, etc...
return Store.findOne(storeId);
}
};
Your Controllers should handle all that is related to requests, calling services, and returning apropriate responses.
For example, in you example, the controller could have this:
module.exports = {
index: function(req, res) {
if(req.param('id')) {
StoreService.findStore(req.param('id'))
.then(res.ok)
.catch(res.serverError);
} else {
res.badRequest('Missing Store id');
}
},
findStore: function(req, res) {
if(req.param('id')) {
StoreService.findStore(req.param('id'))
.then(res.ok)
.catch(res.serverError);
} else {
res.badRequest('Missing Store id');
}
},
};
That way, you have really simple controllers, and all business logic is managed by services.
Having the same problem for last few hours. I used the api/services folder.
It may not be exactly what you need but it is an option.
A good explanation is here. What services would one add to the api/services folder in sails.js
It's slightly annoying when you're just trying to build something quickly, but in the long run it forces good code organization practice (by making it harder to shove all business logic into a controller).
I would like to suggest a solution that works but not the best possible way to do it. We can use bind function to bind the context with the calling source as shown below :
generateUrl is present in the Controller A
function generateUrl(){
return 'www.google.com';
}
get URL is another method in Controller A
getURL(){
A.generateURL.bind(A.generateURL) //func call with optional arg
}
I hope this helps!
A more elegant way to solve this problem is using the keyword this before the function name.
Example:
one: function() {
console.log('First Function');
},
two: function() {
// call the function one in the same controller
this.one();
}
You can do something like this:
//ArticleController
module.exports = {
findStore: async () => {
return await findStoreFunc(req.param('id'));
},
index: async () => {
...
return await findStoreFunc(id);
}
};
const findStoreFunc = async (id) => {...}
And to use the function from another controller:
const ArticleController = require('./ArticleController');
//CustomerController
module.exports = {
index: async () => {
...
let article = await ArticleController.findStore(id);
...
}
};

Categories

Resources