Каков рекомендуемый способ расширения контроллеров AngularJS?

У меня есть три контроллера, которые очень похожи. Я хочу иметь контроллер, который расширяет эти три функции и разделяет их функции.

Ответы на вопрос(12)

ParentController», {$ scope: $ scope}) Примерmodule.controller('Parent', ['$scope', function ($scope) { //code }])

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) { //extend parent controller $controller('CtrlImpl', {$scope: $scope}); }]);

чего вы хотите достичь, но обычно Услуги - это путь. Вы также можете использовать характеристики наследования Scope Angular для совместного использования кода между контроллерами:


 <div ng-controller="FirstChildCtrl"></div>
 <div ng-controller="SecondChildCtrl"></div>


function ParentCtrl($scope) {
 $scope.fx = function() {
   alert("Hello World");
 });
}

function FirstChildCtrl($scope) {
  // $scope.fx() is available here
}

function SecondChildCtrl($scope) {
  // $scope.fx() is available here
}
 vladexologija14 мая 2013 г., 12:22
Совместно используйте одни и те же переменные и функции между контроллерами, которые делают похожие вещи (одна для редактирования, другая для создания и т. Д.). Это определенно одно из решений ...
 mwarren19 янв. 2015 г., 17:48
В конце концов это казалось самым угловатым путем. У меня есть три очень коротких parentController на трех разных страницах, которые просто устанавливают значение $ scope, которое childController может подобрать. ChildController, который я изначально думал о расширении, содержит всю логику контроллера.
 snez11 июл. 2014 г., 22:34
Наследование $ scope - безусловно, лучший способ сделать это, намного лучше, чем принятый ответ.
 Akash09 сент. 2016 г., 08:52
не будет$scope.$parent.fx( )  быть намного более чистым способом сделать это, так как это - то, где это фактически определено?
 M K25 янв. 2014 г., 22:59
Это определенно работает, но хочется использовать глобальные переменные.

function extendController(baseController, extension) {
    return [
        '$scope', '$injector',
        function($scope, $injector) {
            $injector.invoke(baseController, this, { $scope: $scope });
            $injector.invoke(extension, this, { $scope: $scope });
        }
    ]
}

Вы можете использовать это так:

function() {
    var BaseController = [
        '$scope', '$http', // etc.
        function($scope, $http, // etc.
            $scope.myFunction = function() {
                //
            }

            // etc.
        }
    ];

    app.controller('myController',
        extendController(BaseController,
            ['$scope', '$filter', // etc.
            function($scope, $filter /* etc. */)
                $scope.myOtherFunction = function() {
                    //
                }

                // etc.
            }]
        )
    );
}();

Плюсы:

Ты ненужно зарегистрировать базовый контроллер.Ни одному из контроллеров не нужно знать о службах $ controller или $ инжектор.Хорошо работает с угловымСинтаксис внедрения массива - который необходим, если ваш javascript будет минимизирован.Вы можете легко добавить дополнительные инъекционные сервисы к базовому контроллеру,без также нужно помнить, чтобы добавить их и передать от всех ваших дочерних контроллеров.

Минусы:

Базовый контроллер должен быть определен как переменная, которая рискует загрязнить глобальную область. Я'Мы избежали этого в моем примере использования, обернув все в анонимную самовыполняющуюся функцию, но это означает, что все дочерние контроллеры должны быть объявлены в одном файле.Этот шаблон хорошо работает для контроллеров, которые создаются непосредственно из вашего html, но неЭто так хорошо для контроллеров, которые вы создаете из своего кода через службу $ controller (), потому что это 'Зависимость от инжектора не позволяет вам напрямую вводить дополнительные не обслуживающие параметры из вашего вызывающего кода.

ия JavaScript. Вот демо, которое использует$injector

function Parent($scope) {
  $scope.name = 'Human';
  $scope.clickParent = function() {
    $scope.name = 'Clicked from base controller';
  }    
}

function Child($scope, $injector) {
  $injector.invoke(Parent, this, {$scope: $scope});
  $scope.name = 'Human Child';
  $scope.clickChild = function(){
    $scope.clickParent();
  }       
}

Child.prototype = Object.create(Parent.prototype);

Если вы используетеcontrollerAs синтаксис (который я очень рекомендую), еще проще использовать классический шаблон наследования:

function BaseCtrl() {
  this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
  //body
};

function ChildCtrl() {
  BaseCtrl.call(this);
  this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
  this.parentMethod();
  //body
};

app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);

Другим способом можно было бы просто создатьАннотация" Функция конструктора, которая будет вашим базовым контроллером:

function BaseController() {
  this.click = function () {
    //some actions here
  };
}

module.controller('ChildCtrl', ['$scope', function ($scope) {
  BaseController.call($scope);
  $scope.anotherClick = function () {
    //other actions
  };
}]);

Сообщение в блоге на эту тему

ре, просто внедрив его.

app.service("reusableCode", function() {

    var reusableCode = {};

    reusableCode.commonMethod = function() {
        alert('Hello, World!');
    };

    return reusableCode;
});

Затем в вашем контроллере, который вы хотите расширить из вышеупомянутого сервиса reusableCode:

app.controller('MainCtrl', function($scope, reusableCode) {

    angular.extend($scope, reusableCode);

    // now you can access all the properties of reusableCode in this $scope
    $scope.commonMethod()

});

ДЕМО ПЛАНКЕР:http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview

Решение Вопроса

возможновы дон»Расширить контроллер, но можно расширить контроллер или сделать один контроллер из нескольких контроллеров.

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    // Initialize the super class and extend it.
    angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
    … Additional extensions to create a mixin.
}]);

Когда родительский контроллер создан, логика, содержащаяся в нем, также выполняется. См. $ Controller () для получения дополнительной информации о, но только$scope значение должно быть передано. Все остальные значения будут введены нормально.

@mwarrenВаше беспокойство автоматически решается с помощью инъекции угловой зависимости. Все, что вам нужно, это ввести $ scope, хотя при желании вы можете переопределить другие введенные значения. Возьмите следующий пример:

(function(angular) {

	var module = angular.module('stackoverflow.example',[]);

	module.controller('simpleController', function($scope, $document) {
		this.getOrigin = function() {
			return $document[0].location.origin;
		};
	});

	module.controller('complexController', function($scope, $controller) {
		angular.extend(this, $controller('simpleController', {$scope: $scope}));
	});

})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>

<div ng-app="stackoverflow.example">
    <div ng-controller="complexController as C">
        <span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
    </div>
</div>

Хотя $ document не передается в 'simpleController» когда он созданcomplexController» $ документ введен для нас.

 schellmax23 дек. 2014 г., 10:46
@tomraithel не используетangular.extend (или же$.extend) на самом деле означает расширение$scope только, но если ваш базовый контроллер также определяет некоторые свойства (например,this.myVar=5), у вас есть доступ только кthis.myVar в расширяющем контроллере при использованииangular.extend
 Petr Averyanov24 июл. 2017 г., 20:47
Не то, что вы можете сделать удобным способом.
 egermano21 нояб. 2013 г., 18:18
Это круто!
 Justin Kruse22 июн. 2017 г., 23:19
Это замечательно! Просто не забудьте расширить все необходимые функции, т. Е. У меня было что-то вроде:handleSubmitClick который бы назвалhandleLogin который в свою очередь имелloginSuccess а такжеloginFail, Итак, в моем расширенном контроллере мне пришлось перегрузить,handleSubmitClickhandleLogin, а такжеloginSucess для правильногоloginSuccess функция, которая будет использоваться.
 M K25 янв. 2014 г., 22:58
Безусловно, самое быстрое, чистое и простое решение для этого! Спасибо!
 Michael Trouw06 мая 2015 г., 12:46
Я хотел уменьшить сложность моих контроллеров, имея ихнаследовать» поделился функциональностью, я понятия не имел, это было так легко сделать. AngularJS великолепен! Использование этого для приложений Ionic также прекрасно, так как вы можете добавить общее поведение, такое как скрытие / показ общих вещей, например, $ Ionicloading.
 Kamil Lach25 июл. 2014 г., 14:19
идеальное, отличное решение!
 tomraithel16 дек. 2014 г., 13:38
Я думаю ты неэто нужно$.extend()Вы можете просто позвонить$controller('CtrlImpl', {$scope: $scope});
 mwarren19 янв. 2015 г., 17:52
Предположительно, если у вашего расширенного контроллера много аргументов, вам придется повторить все аргументы в сигнатуре метода расширяемого контроллера, что в итоге показалось мне немного сложным.
 ya_dimon28 мая 2016 г., 02:56
Здесь проблема с отложенной инициализацией simpleController. Например. у вас есть обещание, которое устанавливает некоторое свойство позже. Для свойства будет установлено значение simpleController после расширения (поскольку выполняется инициализация). Так что, вероятно, проще создать экземпляр simpleController, расширить его новыми свойствами, а затем вернуть его.

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

Сервисы,фабрики или жепровайдеры, они одинаковы, но с разной степенью гибкости.

Вот пример использования фабрики:http://jsfiddle.net/aaaflyvw/6KVtj/2/

angular.module('myApp',[])

.factory('myFactory', function() {
    var myFactory = {
        save: function () {
            // saving ...
        },
        store: function () {
            // storing ...
        }
    };
    return myFactory;
})

.controller('myController', function($scope, myFactory) {
    $scope.myFactory = myFactory;
    myFactory.save(); // here you can use the save function
});

И здесь вы можете использовать функцию магазина также:

<div ng-controller="myController">
    <input ng-blur="myFactory.store()">
</div>

взятое из этогостатья:

// base controller containing common functions for add/edit controllers
module.controller('Diary.BaseAddEditController', function ($scope, SomeService) {
    $scope.diaryEntry = {};

    $scope.saveDiaryEntry = function () {
        SomeService.SaveDiaryEntry($scope.diaryEntry);
    };

    // add any other shared functionality here.
}])

module.controller('Diary.AddDiaryController', function ($scope, $controller) {
    // instantiate base controller
    $controller('Diary.BaseAddEditController', { $scope: $scope });
}])

module.controller('Diary.EditDiaryController', function ($scope, $routeParams, DiaryService, $controller) {
    // instantiate base controller
    $controller('Diary.BaseAddEditController', { $scope: $scope });

    DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
        $scope.diaryEntry = data;
    });
}]);
 Eli Albert29 нояб. 2017 г., 17:39
Это сработало очень хорошо для меня. Он имеет преимущество в простом рефакторинге в ситуации, когда вы начали с одного контроллера, создали другой очень похожий, а затем захотели сделать код DRYer. Ты неНе нужно менять код, просто вытащите его и все готово.

function baseController(callback){
    return function($scope){
        $scope.baseMethod = function(){
            console.log('base method');
        }
        callback.apply(this, arguments);
    }
}

app.controller('childController', baseController(function(){

}));
 TaylorMac09 нояб. 2013 г., 23:26
Ага. Не нужно расширять, просто вызвать с контекстом

как" синтаксис в сочетании с простым наследованием JavaScript

Подробнее смотрите здесьhttp://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/

ции, то эти функции необходимо перенести в службу. Эта услуга может быть введена в ваш контроль, миллеры.

 Bart14 мая 2013 г., 12:07
Дон»т смешивать. Вы можете создать другой сервис, который обрабатывает эти методы сервиса (сохранить, удалить, ...). Чем больше логики приложения вы можете вывести из контроллера, тем лучше.
 vladexologija14 мая 2013 г., 12:00
Спасибо, но у меня есть 4 функции, которые уже используют службы (сохранение, удаление и т. Д.) И одинаковые существуют во всех трех контроллерах. Если расширение не вариант, есть ли возможностьсмешивать?
 vladexologija14 мая 2013 г., 12:39
Хорошо, я могу поставить функции в службу, нет проблем. Как насчет переменных, совместного использования области и т. Д.
 vladexologija14 мая 2013 г., 15:41
Спасибо! Что вы предлагаете, если в моих функциях используется много ссылок на $ scope, и эта область нет доступны в сервисе?
 vladexologija14 мая 2013 г., 12:02
Также есть переменные, которые я тоже нене хочу определять три раза.
 Bart14 мая 2013 г., 16:30
@vladexologija Если у вас много переменных для (пере) установки$scope Вы можете создать помощника. Он может выполнять некоторые специальные задачи, которые неплохо вписываются в услугу или необходимы более чем в одном месте. Увидетьjsfiddle.net/mFhge/1
 ewahner04 сент. 2015 г., 17:38
Барт абсолютно прав. Если вам нужно расширить контроллер, то, скорее всего, у вас есть проблемы с дизайном. Если у вас есть 3 контроллера, взаимодействующих с общими элементами, тогда, если это происходит через пользовательский интерфейс, вам нужно больше реализации дочернего представления. Если они обмениваются данными, то вы действительно должны делать это из службы, которой можно делиться. Контроллеры не должны быть тесно связаны с другими контроллерами, и они также не должны быть тесно связаны с Сервисами. Вы хотите самые маленькие тестируемые компоненты.
 Bart14 мая 2013 г., 14:36
@vladexologija Здесь 'Вот пример того, что я имею в виду:jsfiddle.net/ERGU3 Это'очень простой, но тыя пойму идею
 Bart14 мая 2013 г., 15:57
У меня создается впечатление, что вы слишком тесно связываете контроллер с вашим сервисом. Если ты хочешьЧтобы получить реальный ответ, вам нужно будет предоставить пример кода, чтобы проиллюстрировать вашу проблему.
 vladexologija14 мая 2013 г., 13:54
@ganaraj ничего особенного, чтобы отправить. У меня просто есть переменные, которые используются как в представлениях, так и в контроллерах, и будут использоваться в новом сервисе. Я бродил чтолучший способ поделиться, rootScope?
 vladexologija14 мая 2013 г., 16:15
Ну, что-то вроде этого:jsfiddle.net/vladexologija/mFhge
 ganaraj14 мая 2013 г., 12:31
@vladexologija Я согласен с Бартом здесь. Я думаю, что услуги смешиваютсяs. Вы должны попытаться переместить как можно больше логики из контроллера (в службы). Так что если у вас есть 3 контроллера, которые должны выполнять аналогичные задачи, то сервис, кажется, является правильным подходом. Расширение контроллеров не кажется естественным в Angular.
 ganaraj14 мая 2013 г., 12:57
@vladexologija Можете ли вы опубликовать пример сценария?
 tobylaroni15 янв. 2016 г., 21:59
Классическим примером может служить случай, когда на вашем сайте есть два отчета на основе форм, каждый из которых зависит от множества одних и тех же данных, и каждый из которых использует множество общих служб. Теоретически вы можете попробовать собрать все ваши отдельные сервисы в один большой сервис с помощью десятков вызовов AJAX, а затем использовать общедоступные методы, такие как 'getEverythingINeedForReport1' а также 'getEverythingINeedForReport2'и установите все это на один гигантский объект области видимости, но тогда выдействительно вкладываем то, что по сути является логикой контроллера, в ваш сервис. Расширение контроллеров в некоторых случаях абсолютно оправдано.
 a better oliver25 нояб. 2015 г., 19:26
Ответ довольно бесполезен без каких-либо аргументов и дальнейших объяснений. Я также думаю, что вы несколько скучаете по ОП 'точка с. Там уже есть общий сервис. Единственное, что вы делаете, - это непосредственно предоставляете эту услугу. Я нене знаю, если этохорошая идея Ваш подход также терпит неудачу, если необходим доступ к области. Но, следуя вашим рассуждениям, я бы явно представил область видимости как свойство области видимости, чтобы ее можно было передать в качестве аргумента.

Ваш ответ на вопрос