I'm trying to consume a REST webservice, responding with a JSON String containing a fairly "complex" schema.
I created a model that contains every fields sent by the webservice.
Here are the relevant codes that should be a problem :
public getUser(user_id: number): PlanDeCharge.Modeles.User {
var toto;
this.UserRest.get({ user_id: user_id }, function(){}, function(err){
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
}).$promise.then(function(data){
toto = data;
});
return toto;
}
-
this.userConnecte = this.gestionUserService.getUser(759);
-
export function userRest($resource: ng.resource.IResourceService, $cookies: ng.cookies.ICookiesService): PlanDeCharge.Modeles.IUserResource {
this.key = $cookies.get("encodedKey");
var urlService: string = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return <PlanDeCharge.Modeles.IUserResource> $resource(urlService, {user_id: "#user_id"}, {
get:{
headers:{"key" : this.key}
}
});
}
app.factory("UserRest", ["$resource", "$cookies", userRest]);
I did a lot of modifications, trying to fix the call without success... The request actually get a response containing the JSON string, but I can't put it inside an object to be use (like user['id'] = 2)
Thanks in advance
I deleted the last post and made this new one, the first one wasn't clear enough and people were confused
When working with promises you should let Angular handle the resolvement.
Am I right, if you are actually using AngularJS 1 and not ng2 as the question is tagged? The syntax is ng1 anyways.
Some notes on the getUser method. Return the reference created by $resource instead of creating one your self. Further more, use the fat-arrow syntax on the callbacks to bind this to the proper context. See this article for more on this.
To remove even more code use TypeScripts object initialization and init the user id object with just { user_id }. This creates a JavaScript object with a property user_id with the value of user_id.
public getUser(user_id: number): SomeModel {
return this.UserRest
.get({ user_id }, () => { }, () => {
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
});
}
In your component or controller access
this.userConnecte = this.gestionUserService.getUser(759);
Lastly, the factory/service.
Use the fact that $resource is generic and set your variables as constants when not changed.
export function userRest(
$resource: ng.resource.IResourceService,
$cookies: ng.cookies.ICookiesService
): ng.resource.IResourceClass<PlanDeCharge.Modeles.IUserResource> {
this.key = $cookies.get("encodedKey");
const urlService = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return $resource<PlanDeCharge.Modeles.IUserResource>(urlService, { user_id: "#user_id" }, {
get: {
headers: { "key": this.key }
}
});
}
This should fix your problems and make to code more readable. :)
Related
I am trying to build a function that allows users to retrieve data from the database, but in a dynamic way. So allowing them to specify the source table, as well as which columns they would like to retrieve.
I have already built out the part that allows them to choose the table and columns, and these users only have access to data we are happy for them to retrieve.
I want this to be as dynamic as possible, so I am building a function to help me with this. I have run into one problem though so far. I have this function:
const modelMap = (model, action, criteria, options) => {
const models = {
EXTERNAL_USER: {
READ: services.externalUser.readExternalUser(criteria, options),
},
TASK: {
READ: services.task.readTask(criteria, options),
},
USER: {
READ: services.user.readUser(criteria, options),
},
}
return models[model][action]
}
So, for example, I call this function using
modelMap('EXTERNAL_USER', 'READ', { id: userID }, { populates: ['documents'] }).
This returns the data I want, however I get an ``OperationError` in my terminal:
OperationalError [UsageError]: Invalid populate(s).
Details:
Could not populate `documents`. There is no attribute named `documents` defined in this model.
The error is saying that the Task model has no attribute documents, which it doesn't. So I am guessing that even though I am not trying to access the readTask function, it is being called anyway. How can I get around this?
SOLUTION
I altered the models object to the following:
const models = {
EXTERNAL_USER: {
READ: () => services.externalUser.readExternalUsers(criteria, options),
},
TASK: {
READ: () => services.task.readTask(criteria, options),
},
USER: {
READ: () => services.user.readUser(criteria, options),
},
}
And I can then use await modelMap(model, action, criteria, options)() to get the data I need.
Yes. The functions called anyway
This is the method I'm using, pretty simple.
DailyCountTest: function (){
this.$store.dispatch("DailyCountAction")
let NewPatientTest = this.$store.getters.NewPatientCountGET
console.log(NewPatientTest)
}
The getter gets that data from a simple action that calls a django backend API.
I'm attempting to do some charting with the data so I need to assign them to variables. The only problem is I can't access the variables.
This is what the console looks like
And this is what it looks like expanded.
You can see the contents, but I also see empty brackets. Would anyone know how I could access those values? I've tried a bunch of map.(Object) examples and couldn't get any success with them.
Would anyone have any recommendation on how I can manipulate this array to get the contents?
Thanks!
Here is the Vuex path for the API data
Action:
DailyCountAction ({ commit }) {
axios({
method: "get",
url: "http://127.0.0.1:8000/MonthlyCountByDay/",
auth: {
username: "test",
password: "test"
}
}).then(response => {
commit('DailyCountMutation', response.data)
})
},
Mutation:
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
state.DailyCount.push(NewPatientCycle)
});
}
Getter:
NewPatientCountGET : state => {
return state.DailyCount
}
State:
DailyCount: []
This particular description of your problem caught my eye:
The getter gets that data from a simple action that calls a django backend API
That, to me, implies an asynchronous action and you might be getting a race condition. Would you be able to post a sample of your getter function to confirm my suspicion?
If that getter does indeed rely on an action to populate its contents, perhaps something to the effect of the following might do?
DailyCountTest: async () => {
await this.$store.dispatch('DailyCountAction')
await this.$store.dispatch('ActionThatPopulatesNewPatientCount')
let NewPatientTest = this.$store.getters.NewPatientCountGET
// ... do whatever with resulting array
}
You can also try with a computer property. You can import mapGetters
import { mapGetters } from 'vuex'
and later in computed properties:
computed: {
...mapGetters(['NewPatientCountGET'])
}
then you can use your NewPatientCountGET and it will update whenever the value changes in the store. (for example when the api returns a new value)
Hope that makes sense
Empolyee class...
class Empolyee
public name: string;
public id: string;
public dep: string;
constructor(name, id, dep) {
this.name = name;
this.id = id;
this.dep = dep;
}
typescript
emp: Empolyee;
ngOnInit() {
this.serviceA.getEmpolyee().subscribe(
{ data => emp = data; });
}
addNew(newEmp) {
this.emp = newEmp; //this does not work....
}
html
<table *ngFor="let person of emp">
<tr>{{person.name}}</tr>
</table>
When I attempted this I got below error
ERROR Error: Error trying to diff 'Sam John'. Only arrays and iterables are allowed.
So how do I append an object to emp? or was there something I didn't get? my goal is to add the new empolyee to the front of the table and display it. Somehow I cannot understand why the error is being thrown.
Here is a sample response returned from calling getEmpolyee()
returns the following....
getEmpolyee() {
return this.httpclient.get<Empolyee>('/getEmployee').map( data => data);
}
The data sent back from service is below
"empolyee":[
{"name":"Reed Thomas","id":"5729","dep":"Sale"},
{"name":"Green Steve","id":"3268","dep":"IT"}
]
First you need to change your variable in controller, from
emp: Empolyee;
to
emp: Array<Empolyee>;
Based on the JSON model that you presents, you may need to do the following in ngOnInit:
data => emp = data.empolyee;
And in addNew function, so, you will use the array unshift function:
this.emp.unshift(newEmp);
Link to additional full example:
Employee Angular code
Try this:
emp: Empolyee[];
ngOnInit() {
this.serviceA.getEmpolyee().subscribe(
data => this.emp = data.employee );
}
addNew(newEmp) {
this.emp.unshift(newEmp);
}
Apparently your service returns just a single Empolyee (isn't that misspelled btw?).
So try doing this:
<table>
<tr><td>{{emp.name}}</td></tr>
</table>
This is really basic Angular though, so you should probably take a tutorial/course somewhere (the official tutorial is pretty solid).
I am attempting to build a generic filter which needs to be able to handle - based on configuration - parameters. Both a resource instance and a service.
I have the following factory code:
angular.module('sample').factory('Sample', function($resource) {
var methods = {
search: {
method: 'POST',
isArray: true
}
}
var Sample = new $resource('/sample', methods);
Sample.prototype.elasticFilter = function (search) {
var query = {
query: {
filtered: {
query: {
wildcard: {
name: '*' + search.toLowerCase() + '*'
}
}
}
}
}
return this.$search(query);
}
return Sample;
});
Now if I do the following in my directive:
scope.search = function (search) {
Sample.elasticFilter(search).$promise.then(function () {
handle
});
this results in
TypeError: Cannot read property 'then' of undefined
printing out Sample.elasticFilter(search), the result is directly a Promise.
Modifying the directive to read directily off Sample.elasticFilter(search).then results in:
TypeError: value.push is not a function.
For non-instance-resources (e.g. NOT newed up, rather service directly), .$promise works fine.
Why is this happening? How can I work around it? When does a resource have a $promise, and when does it not?
This appears to be a "feature" https://github.com/angular/angular.js/issues/11767
The only way to really work around this is to not use isArray on instance level resource methods.
Say I have a collection (of search results, for example) which needs to be populated and a pagination model that needs to take values for current page, total number of pages, etc. In my controller, I make a GET call to an API which returns both search results and pagination information. How, then, can I fetch all this information and parse it into a collection and a separate model? Is this possible?
I am using AirBNB's Rendr, which allows you to use a uniform code base to run Backbone on both the server and the client. Rendr forces me to parse the API response as an array of models, keeping me from being able to access pagination information.
In Rendr, my controller would look like this:
module.exports = {
index: function (params, callback) {
var spec = {
pagination: { model: 'Pagination', params: params },
collection: { collection: 'SearchResults', params: params }
};
this.app.fetch(spec, function (err, result) {
callback(err, result);
});
}
}
I apologize if this is not clear enough. Feel free to ask for more information!
This is super old so you've probably figured it out by now (or abandoned it). This is as much a backbone question as a Rendr one since the API response is non-standard.
Backbone suggests that if you have a non-standard API response then you need to override the parse method for your exact data format.
If you really want to break it up, the way you may want to code it is:
a Pagination Model
a Search Results Collection
a Search Result Model
and most importantly a Search Model with a custom parse function
Controller:
index: function (params, callback) {
var spec = {
model: { model: 'Search', params: params }
};
this.app.fetch(spec, function (err, result) {
callback(err, result);
});
}
Search Model
var Base = require('./base'),
_ = require('underscore');
module.exports = Base.extend({
url: '/api/search',
parse: function(data) {
if (_.isObject(data.paginationInfo)) {
data.paginationInfo = this.app.modelUtils.getModel('PaginationInfo', data.paginationInfo, {
app: this.app
});
}
if (_.isArray(data.results)) {
data.results = this.app.modelUtils.getCollection('SearchResults', data.results, {
app: this.app,
params: {
searchQuery: data.searchQuery // replace with real parameters for client-side caching.
}
});
}
return data;
}
});
module.exports.id = 'Search';