48

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

Error: Unknown provider: firstOtionalServiceProvider <- firstOtionalService 

Таким образом, мне нужно, чтобы загрузить сценарии на всех страницах. Могу ли я объявить зависимость как необязательную в Angular? Например:

myApp.controller('MyController', ['$scope', 'firstRequiredService', 'secondRequiredService', 'optional:firstOptionalService', 'optional:secondOptionalService', function($scope, firstRequiredService, secondRequiredService, firstOptionalService, secondOptionalSerivce){ 

    // No need to check, as firstRequiredService must not be null 
    firstRequiredService.alwaysDefined(); 

    // If the dependency is not resolved i want Angular to set null as argument and check 
    if (firstOptionalService) { 
     firstOptionalService.mayBeUndefinedSoCheckNull(); 
    } 

}]); 

ответ

50

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

Однако поведение, о котором вы описали, может быть достигнуто с помощью $injector service. Вы просто вводите $injector вместо всех своих зависимостей в контроллер и вытягиваете зависимости из него вручную, проверяя, существуют ли они. Вот именно:

index.html:

<!DOCTYPE html> 
<html data-ng-app="myApp"> 
    <head> 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script> 
    <script src="app.js"></script> 
    <script src="1.js"></script> 
    <script src="2.js"></script> 
    <title>1</title> 
    </head> 
    <body data-ng-controller="DemoController"> 
    </body> 
</html> 

app.js:

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

myApp.service('commonService', function(){ 
    this.action = function(){ 
     console.log('Common service is loaded'); 
    } 
}); 

myApp.controller('DemoController', ['$scope', '$injector', function($scope, $injector){ 
    var common; 
    var first; 
    var second; 

    try{ 
     common = $injector.get('commonService'); 
     console.log('Injector has common service!'); 
    }catch(e){ 
     console.log('Injector does not have common service!'); 
    } 
    try{ 
     first = $injector.get('firstService'); 
     console.log('Injector has first service!'); 
    }catch(e){ 
     console.log('Injector does not have first service!'); 
    } 
    try{ 
     second = $injector.get('secondService'); 
     console.log('Injector has second service!'); 
    }catch(e){ 
     console.log('Injector does not have second service!'); 
    } 

    if(common){ 
     common.action(); 
    } 
    if(first){ 
     first.action(); 
    } 
    if(second){ 
     second.action(); 
    } 
}]); 

1.js:

myApp.service('firstService', function(){ 
    this.action = function(){ 
     console.log('First service is loaded'); 
    } 
}); 

2.js:

myApp.service('secondService', function(){ 
    this.action = function(){ 
     console.log('Second service is loaded'); 
    } 
}); 

Смотреть это жить в this plunk! Попробуйте сыграть с тегами <script> и понаблюдайте за выходом консоли.

P.S. И, как сказал @Problematic, вы можете использовать $injector.has(), начиная с AngularJS 1.1.5.

+0

Спасибо! Именно то, что мне нужно. Я использую последнюю версию Angular, поэтому используйте 'has'! – molaccha

56

По-видимому не используется автоматическая инъекция. Тем не менее, вы можете придать форсунку и проверьте службы:

myApp.controller('MyController', [ 
    '$scope', '$injector', 'firstRequiredService', 'secondRequiredService', 
    function ($scope, $injector, firstRequiredService, secondRequiredService) { 
     if ($injector.has('firstOptionalService')) { 
      var firstOptionalService = $injector.get('firstOptionalService'); 
     } 
    } 
]); 
+0

Прохладный! Я хочу, чтобы они использовали backport '$ injector.has' до 1.0.7! – madhead

+3

Ницца! Это правильный ответ с моей точки зрения – Gabriel

+2

Мне нравится этот ответ по поводу @ madhead, потому что он использует '$ injector.has' вместо' try'/'catch' –

13

я бы, вероятно, пойти с @ предложением Proplematic в использовании $ форсунки. Однако есть другое решение, о котором я могу думать: зарегистрируйте все службы с их значениями по умолчанию (например, null) в вашем файле начальной загрузки. Когда загружаются дополнительные файлы, более поздние определения переопределяют определения по умолчанию, несколько создавая желаемый эффект.

var app = angular.module('plunker', []); 

app.value("service1", null) 
    .value("service2", null) 
    .factory("service1", function() { return "hello"; }); 

app.controller('MainCtrl', function($scope, service1, service2) { 
    console.log(service1); // hello 
    console.log(service2); // null 
}); 

Demo link

+0

Это хаки, но работает. Я использую его там, где у меня есть несколько маршрутов, совместно использующих контроллер, но только некоторые из них нуждаются в решении: {} свойство, введенное. – httpete

+0

Это лучший ответ для моего проекта с дополнительными параметрами. – sean

+0

Это именно то, что я хотел! Благодаря! Мне нужен тот же контроллер, что и модальный контроллер, и как ng-controller. А для модального контроллера мне нужны дополнительные резольверы. –

5

Попробуйте этот способ ..

try { 
    angular.module('YourModule').requires.push('Optional dependency module'); 
} catch(e) { 
    console.log(e) 
} 

'требуется' является массив модулей зависимостей.

9

Это, как я ее решил:

var deps = []; 

try { 
    //Check if optionalModule is available 
    angular.module('app').requires.push('optionalModule'); 
    deps.push('optionalModule'); 
} catch(e){ 
    console.log("Warn: module optionalModule not found. Maybe it's normal"); 
} 

angular.module('app', deps).factory('stuff', function($injector) { 
    var optionalService; 

    if($injector.has('optionalService')) { 
     optionalService = $injector.get('optionalService'); 
    } else { 
     console.log('No waffles for you, dear sir'); 
    } 
}); 
Смежные вопросы