I have problems with restoring my entity relations at the (AngularJS) client after retrieving them via REST using Restangular. I searched a lot, but could not find a clean solution. I have some years of programming experience, but I'm quite new to the AngularJS ecosphere and the REST paradigm.
At my Spring Data backend I have two entities, Article
and ArticleGroup
, in a 1:n relationship. The resulting REST json (via Spring Data Rest) looks like this:
Article
{
"_embedded": {
"articles": [
{
"id": 1,
"name": "A Drink",
"price": 2.90,
"created": null,
"modified": null,
"active": false,
"displayOrder": 0,
"_links": {
"self": {
"href": "http://localhost:8080/articles/1"
},
"articleGroup": {
"href": "http://localhost:8080/articles/1/articleGroup"
}
}
},
...
ArticleGroup
{
"_embedded": {
"articleGroups": [
{
"id": 1,
"name": "Drinks",
"printer": null,
"_links": {
"self": {
"href": "http://localhost:8080/articleGroups/1"
},
"articles": {
"href": "http://localhost:8080/articleGroups/1/articles"
}
}
},
...
Now I want to display a tabgroup containing the articleGroup.name as the tab's label and a table of the articles in this articleGroup as its content:
<tabset>
<tab ng-repeat="group in articleGroups" heading="{{group.name}}">
<table class="table">
<tr ng-repeat="article in group.articles">
<td ng-click="increase(article)">{{article.name}}</td>
<td>{{article.price | currency }}</td>
...
</tr>
</table>
</tab>
</tabset>
I retrieve the articleGroups easily in my AngularJS controller using Restangular:
Restangular.all('articleGroups').getList()
.then(function(groups) {
$scope.articleGroups = groups;
});
This works fine and the tabs show up nicely. Now I can do so for the articles as well, but here I come upon the problem which I'm dealing with for days now.
How can I filter the articles for their articleGroup so every portion of articles appears in the right tab? What is the right expression in the ng-repeat above where I just put "group.articles" as a placeholder now? This sounds very easy, but my problem is that I have no operational identification of an Article's articleGroup to filter the right articles in the ng-repeat for each tab. What I tried:
article._links.articleGroup.href == articleGroup._links.self.href
, but this doesn't work as you can see in the JSON above those two links are set up differentlyundefined
errors by JavaScript or infinite loopsBefore I continue fiddling along for hours, it would be great if you could give me hints on which direction to take and what a "clean" and methodologically sound approach to the task would be. How can I bring articles and their corresponding group back togehter? It seems like such an easy (and frequent) problem, but I tried for hours and days to get it running and fear I'm missing something. I looked at many examples but none of them helped me to have a breakthrough. I'm happy to provide any further information as needed. Thanks a lot in advance!
Well, I solved it. It turned out that I got lost in the handling of asynchronous requests, especially between having a data object itself and a promise for a request, i.e. placeholders which provide access to the data as soon as it is available - very well explained in this post.
Restangular always returns promises. So I came up with the following solution which works exactly as I wanted to:
For the controller code:
Restangular.all('articleGroups').getList()
.then(function(groups) {
$scope.articleGroups = groups;
for(i=0;i<groups.length;i++) {
$scope.articles[groups[i].id] = groups[i].getList("articles")
}
});
So when the articleGroups arrive from the server, I walk through all of them and put them into the array $scope.articles
with the articleGroup.id
as key. Notice that group[i].getList("articles")
returns a promise for the articles relation. With Restangular's $object property, I receive the articles data array in the ng-repeat
:
<tabset>
<tab ng-repeat="group in articleGroups" heading="{{group.name}}">
<table class="table">
<tr ng-repeat="article in articles[group.id].$object | orderBy:'id':false ">
<td>{{article.name}}</td>
<td>{{article.price | currency }}</td>
</tr>
</table>
</tab>
</tabset>
Now, all articles of the selected articleGroup
's tab are displayed on the tab. While this seems fine, I'm still not sure if this is the best solution in terms of style or performance. But at least it's a step ahead. Comments very welcome.