【问题标题】:Cannot inject provider无法注入提供者
【发布时间】:2017-09-12 22:11:52
【问题描述】:

Angular 1.6

我开发了一个dashboard application。已注册的仪表板组件有两个静态定义的 ui.router 状态:home-dashboardother-dashboard

现在我想根据仪表板数据动态定义ui.router 状态。为此,我在app.config 内循环。但是为了获取仪表板数据,StorageService 提供程序应该被注入到配置中。

收到的错误是:

Error: [$injector:unpr] Unknown provider: StorageService

如何注入提供者?有没有更好的方法来实现我的目标?


另外,我尝试将$stateProvider 移动到父控制器dashboardController。通过将其附加到app.config 内的应用程序,例如app.stateProvider = $stateProvider; 并导出将return default app; 放置在app.js 文件末尾的应用程序。

我得到的错误是'return' outside of function


Providerservices/storage.service.js(是一个模拟API的类,以后会从DB获取数据):

class Storage {

  constructor () {
      this.dashboards = {
        'home': {
            id: '1',
            name: 'Home',
        view: 'home',
        url: '/home',
        component: 'homeDashboard',
            widgets: [{
                col: 0,
                row: 0,
                sizeY: 1,
                sizeX: 1,
                name: "Widget 1"
            }, {
                col: 2,
                row: 1,
                sizeY: 1,
                sizeX: 1,
                name: "Widget 2"
            }]
        },
        'other': {
            id: '2',
            name: 'Other',
        view: 'other',
        url: '/other',
        component: 'otherDashboard',
            widgets: [{
                col: 1,
                row: 1,
                sizeY: 1,
                sizeX: 2,
                name: "Other Widget 1"
            }, {
                col: 1,
                row: 3,
                sizeY: 1,
                sizeX: 1,
                name: "Other Widget 2"
            }]
        }
      };
  }

  saveDashboards(dashboards) {
    this.dashboards = dashboards;
  }

  listDashboards() {
    return this.dashboards;
  }

  $get() {
    return this.dashboards;
  }
}

export { Storage };

app.js

import { DashboardCtrl } from './controllers/dashboardController';

import { homeDashboard } from './dashboards/home/homeDashboard.component';
import { otherDashboard } from './dashboards/other/otherDashboard.component';
import { aWidget } from './widgets/a_widget/aWidget.component';

import { Storage } from './services/storage.service.js';
import { Object2Array } from './filters/object2Array.js';

const app = angular.module('dashboardApp', [
    'ui.router',
    'ui.bootstrap',
    'gridster'
])
.controller('DashboardCtrl', DashboardCtrl)
.component('aWidget', aWidget)
.component('homeDashboard', homeDashboard)
.component('otherDashboard', otherDashboard)
//.factory('StorageService', () => new Storage())
.provider('StorageService', Storage)
.filter('object2Array', Object2Array);

app.config(function ($urlRouterProvider, $stateProvider, StorageService) {

  const dashboards = StorageService.listDashboards();

  _.forEach(dashboards, function (d) {
    $stateProvider.state({
      name: d.view,
      url: d.url,
      component: d.component
    });
  });

  /*
  const homeState = {
    name: 'home',
    url: '/home',
    component: 'homeDashboard'
  };

  const otherState = {
    name: 'other',
    url: '/other',
    component: 'otherDashboard'
  };

  $stateProvider.state(homeState);  
  $stateProvider.state(otherState); 
   */

  $urlRouterProvider.otherwise('/home');
});

应用树:

../angular-dashboard/
├── LICENSE
├── README.md
├── dist
├── package.json
├── src
│   ├── app
│   │   ├── app.js
│   │   ├── controllers
│   │   │   └── dashboardController.js
│   │   ├── dashboards
│   │   │   ├── home
│   │   │   │   ├── homeDashboard.component.js
│   │   │   │   ├── homeDashboard.controller.js
│   │   │   │   └── templates
│   │   │   │       └── homeDashboard.template.html
│   │   │   └── other
│   │   │       ├── otherDashboard.component.js
│   │   │       ├── otherDashboard.controller.js
│   │   │       └── templates
│   │   │           └── otherDashboard.template.html
│   │   ├── filters
│   │   │   └── object2Array.js
│   │   ├── services
│   │   │   └── storage.service.js
│   │   └── widgets
│   │       └── a_widget
│   │           ├── aWidget.component.js
│   │           ├── aWidget.controller.js
│   │           ├── aWidget.settings.controller.js
│   │           └── templates
│   │               ├── aWidget.settings.template.html
│   │               └── aWidget.template.html
│   ├── index.html
│   └── style
│       ├── style-common.css
│       └── style.css
└── webpack.config.js

15 directories, 22 files

界面外观:

【问题讨论】:

标签: javascript angularjs angular-ui-router


【解决方案1】:

StorageServiceprovider 服务,在配置阶段作为 StorageServiceProvider 服务提供者使用,在运行阶段作为 StorageService 服务实例使用。

当以StorageServiceProvider 注入时,它将是Storage 类的实例,当以StorageService 注入时,它将是$get 方法(dashboards 对象)的返回值。

当服务实例依赖其他服务时,需要providerfactoryservice服务。否则可以使用constantvalue 服务。

Storage 类是多余的,因为它所做的只是为普通对象提供访问器方法。它可以是constant 服务,在配置和运行阶段都可以使用相同的名称:

app.constant('StorageService', {
  home: { ... },
  ...
});

【讨论】:

  • StorageService 是一个模拟API。将来我想从数据库中获取仪表板数据
  • 在 app.config 中查询数据库是不是一种不好的做法?如果是,我应该怎么做?
  • @trex 问题中没有提到这一点。但是,是的。它是。 DB 请求是异步的,不是吗?这将导致竞争条件,因为应用程序初始化将在数据库请求完成之前完成。当这是仅应在应用程序控制器中使用的数据时,这是通过路由解析器完成的。但是当这个数据是应该在config中已经可用的路由数据时,它应该在angular.bootstrap被调用之前就可用了。 IE。你先做DB请求,动态设置StorageService app.constant('StorageService', ...),然后才调用angular.bootstrap
  • 数据库请求将是异步的。你说我必须将我的数据库请求服务定义为 app.constant 吗?
  • 这取决于。您必须将它的 result 定义为 app.constant。我们在谈论什么样的数据库请求?本地 IndexDb 还是远程 API 调用?
【解决方案2】:

可以直接在控制器中定义路由。

首先,我们需要为控制器提供$stateProvider

...
app.config(function ($urlRouterProvider, $stateProvider) {
  app.stateProvider = $stateProvider;
  $urlRouterProvider.otherwise('/home');
});

export default app;

其次,我们在控制器内部定义状态。

import app from '../app';
...
const DashboardCtrl = function ($scope, $timeout, StorageService) {
...
  forEach($scope.dashboards, function (dashboard) {
    app.stateProvider.state({
      name: dashboard.name,
      url: dashboard.url,
      component: dashboard.component
    });
  });
});

【讨论】:

    猜你喜欢
    • 2014-01-19
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 2021-04-23
    • 2015-11-11
    • 2016-02-18
    • 1970-01-01
    相关资源
    最近更新 更多