Angular UI Router: вызов функции контроллера дочернего состояния

Я работаю с angular ui-router, и одна проблема продолжает возникать. Я надеюсь, что некоторые из вас могут дать мне совет, как решить эту проблему чистым, не хакерским способом.

Рассмотрим следующий сценарий:

введите здесь описание изображения

Слева у меня есть боковая навигация со списком контактов. Когда я нажимаю на контакт, сведения о выбранном контакте отображаются в состоянии app.contacts.details. Как только я выбрал контакт, в шапке появляются некоторые элементы управления, например. «редактировать» и «удалить» (рассмотрите их просто как пример, на самом деле эти действия более сложны).

В идеале эти кнопки просто вызывали бы функцию detailStateController, например. detailStateController.delete() для удаления текущего выбранного контакта или detailStateController.edit() для редактирования выбранного контакта (вы поняли). Конечно, это не работает, потому что кнопки редактирования и удаления не находятся внутри представления состояния app.contacts.details, и поэтому detailStateController не входит в их область действия.

Я знаю, что это можно решить путем трансляции событий, но я хочу по возможности избегать использования событий.

Как бы вы решили это?

Любые советы высоко ценится.


person omnibrain    schedule 31.05.2016    source источник


Ответы (3)


Фабрики являются одноэлементными и могут использоваться для обмена данными и функциями между контроллерами. Вы можете написать это так:

app.factory("DataService", ["$http", function($http){
    var contacts = [];

    return {
        //sharing functions
        postItem: function(url, item) {
            return $http({
                url: url,
                method: 'POST',
                data: item
            });
        },
        putItem: function(url, item) {
            return $http({
                url: url,
                method: 'PUT',
                data: item
            });
        },
        deleteItem: function(url, item) {
            return $http({
                url: url,
                data: item,
                method: 'DELETE'
            });
        },
        setContacts = function(contacts) {
            contacts = contacts;
        },
        addContacts = function(contact) {
            contacts.push(contact);
        },
        deleteContact = function(contact) {
            var idx = this.contacts.indexOf(contact);
            contacts.splice(idx, 1);
        }
    };
}]);

Затем в вашем контроллере:

app.controller("ContactDetailsCtrl", ["$scope", "DataService", function($scope, DataService){
    $scope.deleteContact = function() {
        DataService.deleteItem('path/to/delete', { contactId: 123 }).then(function(response) {
            //remove from client-side array once it's removed form db
            DataService.deleteContact(contact);
        }).catch(function(response){
            //an error occurred
        });
    }
}]);
person Kyle    schedule 31.05.2016

Я отошел от этого стиля и просто обрабатываю все из контроллера со списком. Если вы удаляете элемент из контроллера деталей или редактируете поле, отображаемое в родительском контроллере, вам все равно придется обновлять контроллер списка. Когда я делал это так же, как вы делаете это сейчас, мне казалось, что мне приходилось прыгать через множество дополнительных обручей, вызванных тем, что детали находились в одном контроллере, а список — в другом. Обычно у меня просто есть свойство списка, представляющее собой массив на моем контроллере, и свойство текущей строки, отображающее полную запись. Затем я использую ng-if, чтобы проверить текущую строку и отобразить ее соответствующим образом. Когда нажимается строка, я использую $location.search для обновления URL-адреса, а также проверяю поиск $location при запуске на наличие глубоких ссылок. Это приводит к тому, что один контроллер немного больше, но все же меньше, чем два контроллера вместе взятые. Если я имею дело только с несколькими полями, я включаю все поля в список. Если данных много, я делаю вызов службы, когда текущий элемент в списке изменяется, чтобы получить данные для currentRow и просто обновить currentRow.

person Mike Feltman    schedule 31.05.2016

Лично мне в таких случаях нравится создавать следующую структуру.

Роутер заявляет:

  • app.contacts.index — для содержания панели инструментов для подробного просмотра/списка
  • app.contacts.list - Для списка
  • app.contacts.detail - Подробнее

Контроллер (для каждого состояния соответственно):

function IndexCtrl($scope)
{
   $scope.contact = {}; // For containing the selected contact
   $scope.contacts = []; // List of contacts also on the parent view

   // Define Detail View functions here
   $scope.edit = Edit;
   $scope.delete = Delete;

   // Perform operations on $scope.contact/$scope.contacts
   function Edit() {}
   function Delete() {}
}

function DetailCtrl($scope)
{
    $scope.contact = $scope.$parent.contact = $scope.$parent.contacts[id]; // This way we work with the parent contact defined in IndexCtrl
}

function ListCtrl($scope, Contacts) 
{
    $scope.contacts = $scope.parent.contacts = Contacts.list(); // Contacts Service to retrieve the contact list
}
person Ankit Gupta    schedule 31.05.2016