Разрешение зависимостей объекта от клиента с помощью Restangular

У меня проблемы с восстановлением отношений сущностей на клиенте (AngularJS) после их получения через REST с использованием Restangular. Я много искал, но не мог найти чистого решения. У меня есть несколько лет опыта программирования, но я новичок в экосфере AngularJS и парадигме REST.

Задание

В моем бэкэнде Spring Data у меня есть две сущности, Article и ArticleGroup, в отношениях 1:n. Полученный REST json (через Spring Data Rest) выглядит так:

Статья

{
"_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"
                }
            }
        },
      ...

Группа статей

{
"_embedded": {
    "articleGroups": [
        {
            "id": 1,
            "name": "Drinks",
            "printer": null,
            "_links": {
                "self": {
                    "href": "http://localhost:8080/articleGroups/1"
                },
                "articles": {
                    "href": "http://localhost:8080/articleGroups/1/articles"
                }
            }
        },
      ...

Теперь я хочу отобразить группу вкладок, содержащую articleGroup.name в качестве метки вкладки и таблицу статей в этой группе articleGroup в качестве ее содержимого:

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

Я легко получаю articleGroups в своем контроллере AngularJS, используя Restangular:

Restangular.all('articleGroups').getList()
        .then(function(groups) {
            $scope.articleGroups = groups;
        });

Это отлично работает, и вкладки отображаются красиво. Теперь я могу сделать то же самое и для статей, но тут я столкнулся с проблемой, с которой я сталкиваюсь уже несколько дней.

Эта проблема

Как я могу отфильтровать статьи для их группы статей, чтобы каждая часть статей отображалась на правильной вкладке? Какое правильное выражение в ng-repeat выше, где я просто поставил "group.articles" в качестве заполнителя? Теперь? Это звучит очень просто, но моя проблема в том, что у меня нет оперативной идентификации группы статей статьи для фильтрации нужных статей в ng-repeat для каждой вкладки. Что я пробовал:

  • используя self.href в качестве идентификатора а-ля article._links.articleGroup.href == articleGroup._links.self.href, но это не работает, как вы можете видеть в JSON выше, эти две ссылки настроены по-разному
  • добавление идентификаторов (базы данных) в JSON, но, конечно, статья не содержит идентификатор своей группы статей, а только отношение ссылки
  • перебирая articleGroups и извлекая статьи каждой группы в массив с articleGroup.id в качестве ключа, но я не могу заставить это работать, поскольку я либо получаю undefined ошибок с помощью JavaScript, либо бесконечные циклы

Помощь

Прежде чем я продолжу возиться с этим в течение нескольких часов, было бы здорово, если бы вы могли подсказать мне, в каком направлении двигаться и каким должен быть «чистый» и методологически обоснованный подход к задаче. Как я могу снова объединить статьи и соответствующие им группы? Это кажется такой простой (и частой) проблемой, но я часами и днями пытался запустить ее и боюсь, что что-то упустил. Я просмотрел множество примеров, но ни один из них не помог мне добиться прорыва. Я буду рад предоставить любую дополнительную информацию по мере необходимости. Заранее большое спасибо!


person Jörg Gottschlich    schedule 08.08.2014    source источник


Ответы (1)


Ну, я решил это. Оказалось, что я заблудился в обработке асинхронных запросов, особенно между наличием самого объекта данных и обещанием для запроса, то есть заполнителей, которые предоставляют доступ к данным, как только они становятся доступными - очень хорошо объяснено в этот пост.

Restangular всегда возвращает обещания. Поэтому я придумал следующее решение, которое работает именно так, как я хотел:

Для кода контроллера:

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")
            }
        });

Поэтому, когда группы статей поступают с сервера, я просматриваю их все и помещаю в массив $scope.articles с ключом articleGroup.id. Обратите внимание, что group[i].getList("articles") возвращает обещание для отношения article. С помощью свойства $object Restangular я получаю массив данных о статьях в 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>

Теперь все статьи выбранной вкладки articleGroup отображаются на вкладке. Хотя это кажется хорошим, я все еще не уверен, является ли это лучшим решением с точки зрения стиля или производительности. Но, по крайней мере, это шаг вперед. Комментарии очень приветствуются.

person Jörg Gottschlich    schedule 08.08.2014