Angular $resource returns too many results - angularjs

I don't know if my question makes any sense as I'm a bit confused to what is happening here myself, but I have a service that returns information about offices. There seems to be nothing wrong with this and it returns data like this:
[
{
"mainContact": {
"phoneNumbers":[
{"key":1,"number":"22555555","type":"Mobile"}
],
"key":1,
"name":"Ola Dunk",
"email":"oladunk#lol.no"
},
"secretary": {
"phoneNumbers": [
{
"key":2,
"number":"22666666",
"type":"Home"
}
],
"key":2,
"name":"Kari Norrmann",
"email":"kari#test.no"
},
"key":1,
"specialRequirements":null,
"name":"Ola Dunk",
"address":"Test",
"doctorCount":10,
"presumedPurchaseAmount":100000,
"phoneNumber":"22222222",
"membershipStatus":1
}
]
I tried using $resource to get the data using
var r = $resource('http://localhost:60297/api/office');
console.log(r.query());
I use query() over get() since this is the default get all service when no id is specified or some other selector. It just happens to return only the one test office I've created because that's the only office that exists presently.
My problem is what you can see in my console which I've screenshotted here:
That's just the tip of the iceberg. The result keeps getting repeated. Just to check I tried using $http instead of $resource and then it works just fine.
Any ideas on what's wrong?

That's because object 'self-assigned', you can try in console:
var test = { foo : 'bar'};
test.foo = test;
and get same thing. The question is: why it bothers you?

Related

Angular Request how it works for nestjsx/crud

I've been trying for hours to make it work and I can't do it, I hope some of you have the answer to my question because it must be very simple and I am a beginner
I am using AngularJs and NestJs in Nest used the #nestjsx/crud and I went trow the request docs so, here is the problem:
This is my Angular service function
getProductsOfPiece(pieceId: number): Observable<ProductSimple[]> {
return this.http.get<ProductSimple[]>(
'api/producto/', {
params: {
fields: "id,refFabr,refCliente,descrCorta,imagen",
filter: 'pieza.id||$eq||'+ pieceId
}
}
);
}
This request gives me a 400 Bad Request, it looks like this:
/api/producto/?fields=id,refFabr,refCliente,descrCorta,imagen&filter=pieza.id%257C%257C$eq%257C%257C1
I imagine the % and the hexadecimal have something to do with the URI coding and tried to encode/decode it, but didn't work.
I also tried using the class RequestQueryBuilder of #nestjsx/crud-request from the FrontEnd usage referenced in the docs, and append it to the URL
let queryString = RequestQueryBuilder.create()
.select(["id","refFabr","refCliente","descrCorta","imagen"])
.setFilter({
field: "coleccion.id",
operator: CondOperator.EQUALS,
value: collectionId
}).query();
return this.http.get<ProductSimple[]>(
'api/producto/?'+queryString
);
but got worse result
/api/producto/?fields=id%2CrefFabr%2CrefCliente%2CdescrCorta%2Cimagen&filter%5B0%5D=pieza.id%7C%7C%24eq%7C%7C1
What I don't understand is how I do this with my Postmand and it works!
api/producto/?fields=id,refFabr,refCliente,descrCorta,imagen&filter=coleccion.id||$eq||6
How can I make it work, what is wrong with my code?
Finally got the answer, just had to set the .query(false) on the RequestQueryBuilder, this boolean parameter is for encode, seams like Angular's HttpClient class does some encoding or something to the URL so, anyway
It Works! Here is the code:
getProductsOfPiece(pieceId: number): Observable<ProductSimple[]> {
let queryString = RequestQueryBuilder.create()
.select(["id","refFabr","refCliente","descrCorta","imagen"])
.setFilter({
field: "coleccion.id",
operator: CondOperator.EQUALS,
value: collectionId
}).query(false);
return this.http.get<ProductSimple[]>(
'api/producto/?'+queryString
);
}
And you need to import
RequestQueryBuilder of #nestjsx/crud-request
npm i #nestjsx/crud-request.
Any observations are welcome...
UPDATE
To create or update
Here are de docs
Create One https://github.com/nestjsx/crud/wiki/Controllers#create-one-resource
Update One https://github.com/nestjsx/crud/wiki/Controllers#update-one-resource
Following that guide the create and update are simple
Just do POST to the API 'api/producto/' (for example) with the object as body in the request
For the Update follows similar just using the PUT method and the API with the model id 'api/producto/1' (for example)

need to find out the source of angularjs factory values modifier

In my angularjs application, I am using factory to store the values and share them across the controllers. But I am getting into a peculiar problem.
The following is my factory :
factory.quoteLinks = {allLinks : [], allLeftLinks :[], curSection : "-1", insType: "-1", test:"-1"};
factory.setQuoteLinks = function(qlinks, qleftLinks, qsubLink, qinsuranceType, testVal) {
factory.quoteLinks = { allLinks : qlinks, allLeftLinks : qleftLinks, curSection: qsubLink, insType: qinsuranceType, test:testVal};
};
factory.getQuoteLinks = function() {
return factory.quoteLinks;
};
As far as I Know, the values will be stored in factory.quoteLinks, only when I call factory.setQuoteLinks. So whenever I explicitly make call to factory.setQuoteLinks, the values are correctly getting stored. After a while debugging remaining part of the code, during debugging, I noticed even though I am not calling factory.setQuoteLinks, the values of allLinks in factory.quoteLinks is getting modified to some other values and I am not able to figure out from where this is getting modified even though I am not calling factory.setQuoteLinks to modify the allLinks at that particular point. Is there any possibility for me to track from where this value in the factory is getting modified, I mean the cause for this modification? I left with no clue how to figure it out?
Ax Max Sorin said you're probably modifying it outside of here because you're passing back the reference to it in factory.getQuoteLinks. If you need this changed use an angular copy:
factory.getQuoteLinks = function() {
return angular.copy(factory.quoteLinks);
};
This will return a copied quoteLinks.

Angular Resource - Default Model Structure

So I'm using this Rest API with ngResource to do get, query, post and update requests. What I'm looking for, is a way to define the structure for each entity.
For example, assuming we have:
module.factory('app.entity.item', function($resource) {
return $resource('http://xmpl.io/items/:itemId', { itemId: '#id' });
});
I want to instantiate it in a controller like:
module.controller('AddItemCtrl', ['app.entity.item', function(Item) {
$scope.item = new Item();
});
and bind it to the respective form in my template.
The actual problem that I have run into, is that I have to deal with 1:m tables.
An example of the entity structure would be:
{
"name": "",
"categories": [],
"list": [
{
"value": "",
"list": [
{
"value": "",
"list": [
{
"value": ""
}
]
}
]
}
]
}
(A more thorough example in the fiddle below)
Now the first two fields are obviously not the problem. It is the third one. The list. Each one of these lists can have a variable number of items.
I am currently using ngRepeat and an add(type, context) method, which adds a new set of fields to the scope (value field in this example and child lists for the first two levels), which will appear in UI by ngRepeat so the user can fill it up and submit it to the service.
First off, I have to define the structure, so the UI would not be empty when the page loads.
module.controller('AddItemCtrl', ['app.entity.item', function(Item) {
$scope.item = new Item({
"name": "",
"categories": [],
"list": [
{
"value": "",
"list": [
{
"value": "",
"list": [
{
"value": ""
}
]
}
]
}
]
});
});
But that is redundant. I have to do it everywhere!
Another issue is that when the item.$save is called, the model is emptied (perhaps re-instantiated?) and the fields inside the list property (managed by the ngRepeat directive) are gone.
So I'm wondering, what would you do under such circumstances.
Is there a way to define the entity (resource) structure?
SAMPLE: http://jsfiddle.net/g15sqd5s/3/
trying to give simple answer - for simple structures I would use something like
module.factory('Item', function($resource) {
var resource = $resource('http://xmpl.io/items/:itemId', { itemId: '#id' },
// you can also define transformRequest here:
{ transformRequest: function(data) {
// data can be transformed here
return angular.toJson(data);
}});
return angular.extend(resource.prototype,
{
name: null,
categories: []
});
});
but then be aware of need to 'flatten' the object.
and for the more complex model I would check restangular
similar topic is also discussed here:
How can I extend the constructor of an AngularJS resource ($resource)?
I would go ahead and revise my model structure in the backend in the first place - the models on the client side should merely follow the ones already defined, rather than being re-defined in a transform block. So, to answer your question, the "default" model structure comes from the server. What you get in your $resource objects has the structure of what your server returns.
To start off, is it really ok to invoke $save on the Item model when the user has populated some values? What we want to save are obviously the lists associated with an item, not the item itself. A separate resource defined in the backend, say items/<item_id>/list, may be a cleaner solution. It may not scale very well, as you'll have to make a separate GET request for each item to fetch its list, but that's the proper RESTful way to do it.
Extending this approach to the example in your fiddle, I imagine a routing scheme like buildings/<building_id>/floors/<floor_id>/units/<unit_id> would be a proper solution. Making a GET request to buildings/ should yield you a list of buildings; each building in the array returned should be an instance of a Building model, which has the proper URL set so the user can perform a single POST and update only the building name, instead of sending back the whole structure back to the server. Applying this recursively to the nested resources should give you a clean and concise way to deal with model changes.
Regarding the UI part - I would go ahead and define three directives for buildings, floors and units, and let each one manage an array with the respective resources, also taking care for the UI bindings to the model values.
So how could a Building model look like?
var BuildingResource = $resource('/buildings/:id', { id: '#id' });
Invoking BuildingResource.query() should yield an array of existing buildings. Adding a new building could look like this:
var newBuilding = new BuildingResource();
newBuilding.$save().then(function(building) {
$scope.buildings.push(building);
}, function(errData) {
//Handle error here...
});
It should be easy to extend this pattern for the rest of the resources - note that what the server needs to return for every building is just the name and the id; knowing the id is sufficient to construct an URL (and a $resource object, respectively) to fetch the needed child resources (in this case, floors).

How to get database field values from extbase action?

now that I managed to get random AJAX output, I want to get some useful values from the database as the next step.
Once again, my AJAX call looks like this (additionally, I added a JSON call, which would be even better).
$.ajax({
url: "index.php",
data: "tx_myext_myplugin1[controller]=Mycontroller1&tx_myext_myplugin1[action]=ajax&type=89657201",
success: function(result) {
alert(result);
}
});
/*
var uri = '<f:uri.action action="ajax" controller="Mycontroller1" pageType="89657201" />';
jQuery.getJSON(uri, function(result) {
alert(result.c);
});
*/
my ajaxAction function:
public function ajaxAction() {
$arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
return json_encode($arr);
}
This works when I use the JSON call, now I need to get an array with database values though. I thought calling the repository with a findAll() function would already help, but it's not an array I think, which is why I can't use it. A different idea would be to use the getValue methods I wrote in the Model, but I'm not sure if this would help.
Disclaimer: Generally using findAll() method can be real performance killer therefore try to write custom finders, selecting only required properties, especcialy if your model is big or contains many relations!
You are close enough, as you can send findAll() result with json_encode(), but be careful, depending on your model, json created from findAll can be really huge. It's better idea to iterate results and rewrite to new array only required values.
$dataFromRepo = $this->yourRepository->findAll();
$resultArray = array();
foreach ($dataFromRepo as $object){
$resultArray[$object->getUid()] = $object->getTitle();
}
return json_encode($resultArray);
in result you'll get basic JSON object:
{
"1": "Title of first item",
"2": "Second item",
"3": "Et cetera"
}
When you'll remove custom index from $resultArray
foreach ($dataFromRepo as $object){
$resultArray[] = $object->getTitle();
}
you will get JSON array
[
"Title of first item",
"Second item",
"Et cetera"
]
And so on. Of course you can also build this way multidimensional array and send more sophisticated objects to get all you need at once.
P.S. Try always to use for an example JsonLint - online validator to validate if the output you're expecting is valid.

backbone.js not updating id of model object after save, why not?

I have been trying out backbone.js and have been stymied when I create a new model object then call model.save(). I am expecting the backbone.js default behavior to update the model object with the id from the database but it is not. Is this not supposed to happen? I have verified that I am getting a post with the attributes in json format. My server saves the json to a table and then returns the json with a new id field to backbone.js. Is this correct? Should my server return the entire new object or just the id or what?
//contents of the POST from backbone.js
{ "text":"this is a test" }
//reply from my server
{ id:"15", text:"this is a test" }
My sample code is below
var SQLRow = Backbone.Model.extend({
table:"",
urlRoot:'db',
url:function () {
return "/" + this.urlRoot + "?table=" + this.table +
"&id=" + this.attributes.id;
}
});
var Xtra = SQLRow.extend ({
table:'Xtra'
});
var row = new Xtra({
text: "this is a test"
});
alert(row.url());
row.save()
alert("row:" + row.get("id"));
Tough to tell from your post. Two ideas :
1) the response from the server isn't successful What does your save call return ?
2) Your "id" attribute is named something other than ID. To account for the different name add the following to your model :
idAttribute : "MyModelsID",
EDIT
You're likely facing a timing issue, where the alert fires before the ID has returned. Instead of your last two lines try this :
row.save( null,
{
success : function(model, response) { alert(model.get('id'); }
}
);
ALTERNATIVE
As #mu_is_too_short mentioned, another way is to listen for the change even on the model and respond to the event. (i was just trying to keep the answer as close to your code as possible). But something like the following pseudo code should get you started...
var myView = Backbone.View.extend({
....
initialize : function () {
this.collection.bind('change', this.SOME_LISTENING_FUNC );
}
});
OR, if you're in a collection/view-less world something like this creates a listenr ...
row.on('change', function() { /* do stuff */ }, this);
This answer is based on one comment of Cjolly in the answer above.
It is essential for making the Backbone.Model.save([attributes],[options]) successful in assiging the model with the newly generated model's id from the server, that the server returns the model's id in a JSON string like this { "id" : <the id> }. (note it is "id" and not id).
In essence backbone rightly expects a JSON string and in contrast to how objects may be defined in Javascript without quoted keys, JSON requires the object keys to be quoted (see JSON Spec - does the key have to be surrounded with quotes?)
Since according to Cjolly's comment this has been the essential problem, I want to hightlight this solution in an second answer. Partially because I was hit by the very same problem and only by reading througth the comments I was able to receive the insight.
I've faced the same issue and what I've found is that my validate function of the saved model actually invalidates the model returned from the back end. That's why my fields were not updated properly.
Maybe its a little outtimed, but today I had the same missing id.
It turns out, that the server just sends a Header 'Location' with a redirect containing the new id, but dosen't return the persisted object.
Adding the object to the response was the solution.
It seems, that not returning the object is standard behavier with Roo(Spring) generated Json-Controllers.

Resources