Подтвердить что ты не робот

Является ли хорошей практикой комбинировать контроллеры CREATE и EDIT в AngularJS?

В контроллерах CREATE и EDIT много дублированных кодов. Эти контроллеры можно объединить в один для минимизации повторяющегося кода.

Проблема: мне нужно отличить, какой метод использовать при отправке формы - create() или edit(), например.

Решение: я мог бы добавить $scope.mode, например, и установить $scope.mode='edit', если пользователь нажал кнопку "EDIT" или установил $scope.mode='add', если пользователь нажал кнопку "ADD".

Я мог бы использовать службы для минимизации повторяющегося кода, но все равно будет дублированный код. Например, в обоих контроллерах у меня есть метод cancel(), который очищает форму и скрывает ее. Я мог бы хранить clearForm() и hideForm() в службе, но этот код будет дублироваться в обоих контроллерах:

$scope.cancel = function() {
    Service.clearForm();
    Service.hideForm();
};

Вопросы:

  • Хорошо ли сочетать контроллеры CREATE и EDIT в AngularJS?
  • Есть ли какие-либо хорошие методы для минимизации повторяющегося кода?
4b9b3361

Ответ 1

Да. Используйте 1 контроллер.

Вот почему вы используете 1 контроллер

Задача контроллера - поддерживать представление. Ваше представление создания и вид редактирования точно такие же - только у него есть данные, предварительно заполненные (редактировать), а другое - нет (создавать). Кроме того, "цель" этого представления состоит в том, чтобы пользователь изменил или ввел новые значения в форму. Ваша единственная разница должна быть чем-то вроде reset(). Но даже там вы можете начать с пустого объекта модели, например. $scope.entity = {} в случае CREATE, и вы начнете с $scope.entity = $http.get().

Проблема повторения с двумя контроллерами

С двумя разными контроллерами и службами вы понесете хотя бы следующее дублирование:

$scope.cancel = function() {
    Service.cancel();
};

$scope.validate = function() {
   ValidtionSvc.validate();
}
.
.
.//other stuff similar

но проблема в том, почему даже это дублирование, как вы заявили.

(UDATED здесь, так как выше был ответ на 1-й вопрос)

Как использовать 1 контроллер с повторением?

Есть ли какие-либо хорошие методы для минимизации повторяющегося кода?

Вопрос redefined: Есть ли хорошая практика устранения повторяющегося кода в формах CREATE и EDIT?

Никакой официальной "лучшей практики" не существует, насколько мне известно, чтобы избежать повторяющегося кода в этой конкретной ситуации. Однако я рекомендую использовать mode = edit/create. Причина в том, что для контроллеров в этой ситуации не должно быть почти никакой разницы, поскольку их работа заключается в том, чтобы просто получать/обновлять модель по мере взаимодействия пользователя.

Вот разница, с которой вы столкнетесь в этой ситуации, и как вы можете избежать, если /then/else с режимом = create/edit:

1) Заполнение формы существующими значениями против пустой формы для Create.

Для извлечения существующих объектов вам понадобятся некоторые данные ключа/запроса. Если такие ключевые данные присутствуют, вы можете сделать

var masterEntity = {};
if(keyData) {
   masterEntity = MyEntityResourceFactory.getEntity(keyData);
} 
$scope.entity = masterEntity;//for Create this would be {}

2) reset()  должен быть просто

   $scope.reset = function() {
      $scope.entity = masterEntity;
   }

3) Обновить/Создать

$http.post()//should not be different in today world since we are treating PUT as POST

4) Валидация - это идеальное повторное использование - не должно быть различий.

5) Начальные/значения по умолчанию

Вы можете использовать masterEntity = Defaults вместо {}.

Ответ 2

Хорошо ли сочетать контроллеры CREATE и EDIT в AngularJS?

По моему опыту, да, это хорошая идея в 99,9% случаев. Обычно я добавляю переменную formType в свой контроллер через функцию разрешения $routeProvider. Поэтому у меня было бы что-то вроде следующего:

$routeProvider
    .when('/item/create', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.getNew();
            }],
            formType: function () { return Enums.FormType.CREATE; }
        },
    })
    .when('/item/edit/:itemId', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.get($route.current.params.itemId);
            }],
            formType: function () { return Enums.FormType.EDIT; },
        },
    });

Таким образом вы получаете свой объект и тип действия формы, введенного в контроллер. Я также использую одни и те же шаблоны, поэтому сохраняя форму, я могу либо полагаться на свой репозиторий/службу, чтобы определить, какую конечную точку REST для вызова, или я могу сделать простую проверку внутри контроллера в зависимости от того, какой тип формы был введен.

Есть ли какие-либо хорошие методы для минимизации повторяющегося кода?

Некоторые из вещей, которые я использую, чтобы держать вещи сухими:

Если вы придерживаетесь общего соглашения с API-интерфейсом вашего сервера, вы можете пройти очень длинный путь с базовым factory/репозиторием/классом (независимо от того, что вы хотите назвать) для доступа к данным. Например:

GET  -> /{resource}?listQueryString     // Return resource list
GET  -> /{resource}/{id}                // Return single resource
GET  -> /{resource}/{id}/{resource}view // Return display representation of resource
PUT  -> /{resource}/{id}                // Update existing resource
POST -> /{resource}/                    // Create new resource
etc.

Затем мы используем AngularJs factory, который возвращает базовый класс репозитория, позволяет называть его abstractRepository. Затем для каждого ресурса я создаю конкретный репозиторий для этого конкретного ресурса, который прототипно наследует от abstractRepository, поэтому я наследую все общие/базовые функции из abstractRepository и определяю любые специфичные для ресурса функции в конкретном репозитории. Таким образом, подавляющее большинство кода доступа к данным можно определить в abstractRepository. Вот пример использования Restangular:

abstractRepository

app.factory('abstractRepository', [function () {

    function abstractRepository(restangular, route) {
        this.restangular = restangular;
        this.route = route;
    }

    abstractRepository.prototype = {
        getList: function (params) {
            return this.restangular.all(this.route).getList(params);
        },
        get: function (id) {
            return this.restangular.one(this.route, id).get();
        },
        getView: function (id) {
            return this.restangular.one(this.route, id).one(this.route + 'view').get();
        },
        update: function (updatedResource) {
            return updatedResource.put();
        },
        create: function (newResource) {
            return this.restangular.all(this.route).post(newResource);
        }
        // etc.
    };

    abstractRepository.extend = function (repository) {
        repository.prototype = Object.create(abstractRepository.prototype);
        repository.prototype.constructor = repository;
    };

    return abstractRepository;
}]);

Конкретный репозиторий, позвольте использовать клиента в качестве примера:

app.factory('customerRepository', ['Restangular', 'abstractRepository', function (restangular, abstractRepository) {

    function customerRepository() {
        abstractRepository.call(this, restangular, 'customers');
    }

    abstractRepository.extend(customerRepository);
    return new customerRepository();
}]);

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

Ответ 3

Ответ на ваш первый вопрос, вероятно, зависит от конкретных обстоятельств.

Если два контроллера разделяют значительное количество операций, а поведение только одной или двух функций должно быть изменено - почему бы и нет! Возможно, это не самое элегантное решение, но эй, что бы ни работало.

Если поведение многих или всех операций контроллера будет зависеть от "$ scope.mode"... Я бы сказал, будьте осторожны. Это похоже на опасный путь.

Услуги

Angular всегда хорошо меня обслуживали, когда дело доходило до минимизации репликации кода между контроллерами. Если есть "хорошая практика для минимизации повторяющегося кода", я бы сказал, что это будут службы. Они являются глобальными для вашего приложения и могут быть введены в несколько контроллеров без проблем.

Я надеюсь, что это поможет!